diff --git a/.aegir.js b/.aegir.js deleted file mode 100644 index 07d86700..00000000 --- a/.aegir.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -module.exports = { - bundlesize: { - maxSize: '14kB' - } -} \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dd84ea78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..e06e02db --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,78 @@ +name: ci +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx aegir lint + - run: npx aegir ts -p check + - run: npx aegir build + - run: npx aegir dep-check + - uses: ipfs/aegir/actions/bundle-size@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + test-node: + needs: check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + node: [14, 15] + fail-fast: true + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + - run: npm install + - run: npx aegir test -t node --bail --cov + - uses: codecov/codecov-action@v1 + test-chrome: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: microsoft/playwright-github-action@v1 + - run: npm install + - run: npx aegir test -t browser --bail --cov + - run: npx aegir test -t webworker --bail + - uses: codecov/codecov-action@v1 + test-firefox: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: microsoft/playwright-github-action@v1 + - run: npm install + - run: npx aegir test -t browser -t webworker --bail -- --browser firefox + test-webkit: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: microsoft/playwright-github-action@v1 + - run: npm install + - run: npx aegir test -t browser -t webworker --bail -- --browser webkit + test-electron-main: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx xvfb-maybe aegir test -t electron-main --bail + test-electron-renderer: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx xvfb-maybe aegir test -t electron-renderer --bail diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 81758d88..00000000 --- a/.travis.yml +++ /dev/null @@ -1,44 +0,0 @@ -language: node_js -cache: npm -stages: - - check - - test - - cov - -node_js: - - 'lts/*' - - 'stable' - -os: - - linux - - osx - -script: npx nyc -s npm run test:node -- --bail -after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov - -jobs: - include: - - os: windows - cache: false - - - stage: check - script: - - npx aegir dep-check - - npm run lint - - npm run test:types - - - stage: test - name: chrome - addons: - chrome: stable - script: npx aegir test -t browser -t webworker - - - stage: test - name: firefox - addons: - firefox: latest - script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless - -notifications: - email: false - diff --git a/README.md b/README.md index cf037f0e..1d4be878 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,8 @@ js-multiaddr - [Background](#background) - [What is multiaddr?](#what-is-multiaddr) - [Install](#install) - - [Setup](#setup) - - [Node.js](#nodejs) - - [Browser: Browserify, Webpack, other bundlers](#browser-browserify-webpack-other-bundlers) - - [Browser: ` - - -``` diff --git a/package.json b/package.json index 637dae53..5471cc5a 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "test": "npm run test:node && npm run test:browser", "test:node": "aegir test --ts -t node", "test:browser": "aegir test -t browser", - "test:types": "npx tsc", "build": "aegir build", "release": "aegir release", "release-minor": "aegir release --type minor", @@ -32,26 +31,30 @@ "bugs": "https://github.com/multiformats/js-multiaddr/issues", "homepage": "https://github.com/multiformats/js-multiaddr", "browser": { - "dns": false + "./src/resolvers/dns.js": "./src/resolvers/dns.browser.js" }, "dependencies": { "cids": "^1.0.0", - "class-is": "^1.1.0", "dns-over-http-resolver": "^1.0.0", - "err-code": "^2.0.3", + "err-code": "^3.0.1", "is-ip": "^3.1.0", - "multibase": "^3.0.0", - "uint8arrays": "^1.1.0", - "varint": "^5.0.0" + "multibase": "^4.0.2", + "uint8arrays": "^2.1.3", + "varint": "^6.0.0" }, "devDependencies": { - "@types/chai": "^4.2.8", - "@types/dirty-chai": "^2.0.2", - "@types/mocha": "^8.0.1", - "@types/node": "^14.0.11", - "aegir": "^29.0.1", - "sinon": "^9.2.0", - "typescript": "^3.9.5" + "@types/varint": "^6.0.0", + "aegir": "^33.0.0", + "sinon": "^10.0.0", + "util": "^0.12.3" + }, + "aegir": { + "build": { + "bundlesizeMax": "22kB" + } + }, + "eslintConfig": { + "extends": "ipfs" }, "contributors": [ "David Dias ", diff --git a/src/codec.js b/src/codec.js index 09bbfa0c..85d0edc1 100644 --- a/src/codec.js +++ b/src/codec.js @@ -33,6 +33,9 @@ module.exports = { } // string -> [[str name, str addr]... ] +/** + * @param {string} str + */ function stringToStringTuples (str) { const tuples = [] const parts = str.split('/').slice(1) // skip first empty elem @@ -73,22 +76,31 @@ function stringToStringTuples (str) { } // [[str name, str addr]... ] -> string +/** + * @param {[number, string?][]} tuples + */ function stringTuplesToString (tuples) { + /** @type {Array} */ const parts = [] - tuples.map(tup => { + tuples.map((tup) => { const proto = protoFromTuple(tup) parts.push(proto.name) if (tup.length > 1) { parts.push(tup[1]) } + return null }) return cleanPath(parts.join('/')) } // [[str name, str addr]... ] -> [[int code, Uint8Array]... ] +/** + * @param {Array} tuples + * @returns {[number , Uint8Array?][]} + */ function stringTuplesToTuples (tuples) { - return tuples.map(tup => { + return tuples.map((tup) => { if (!Array.isArray(tup)) { tup = [tup] } @@ -100,11 +112,19 @@ function stringTuplesToTuples (tuples) { }) } -// [[int code, Uint8Array]... ] -> [[str name, str addr]... ] +/** + * Convert tuples to string tuples + * + * [[int code, Uint8Array]... ] -> [[int code, str addr]... ] + * + * @param {Array<[number, Uint8Array?]>} tuples + * @returns {Array<[number, string?]>} + */ + function tuplesToStringTuples (tuples) { return tuples.map(tup => { const proto = protoFromTuple(tup) - if (tup.length > 1) { + if (tup[1]) { return [proto.code, convert.toString(proto.code, tup[1])] } return [proto.code] @@ -112,8 +132,11 @@ function tuplesToStringTuples (tuples) { } // [[int code, Uint8Array ]... ] -> Uint8Array +/** + * @param {[number, Uint8Array?][]} tuples + */ function tuplesToBytes (tuples) { - return fromBytes(uint8ArrayConcat(tuples.map(tup => { + return fromBytes(uint8ArrayConcat(tuples.map((/** @type {any[]} */ tup) => { const proto = protoFromTuple(tup) let buf = Uint8Array.from(varint.encode(proto.code)) @@ -125,6 +148,10 @@ function tuplesToBytes (tuples) { }))) } +/** + * @param {import("./types").Protocol} p + * @param {Uint8Array | number[]} addr + */ function sizeForAddr (p, addr) { if (p.size > 0) { return p.size / 8 @@ -136,8 +163,13 @@ function sizeForAddr (p, addr) { } } -// Uint8Array -> [[int code, Uint8Array ]... ] +/** + * + * @param {Uint8Array} buf + * @returns {Array<[number, Uint8Array?]>} + */ function bytesToTuples (buf) { + /** @type {Array<[number, Uint8Array?]>} */ const tuples = [] let i = 0 while (i < buf.length) { @@ -170,6 +202,9 @@ function bytesToTuples (buf) { } // Uint8Array -> String +/** + * @param {Uint8Array} buf + */ function bytesToString (buf) { const a = bytesToTuples(buf) const b = tuplesToStringTuples(a) @@ -177,6 +212,9 @@ function bytesToString (buf) { } // String -> Uint8Array +/** + * @param {string} str + */ function stringToBytes (str) { str = cleanPath(str) const a = stringToStringTuples(str) @@ -186,17 +224,26 @@ function stringToBytes (str) { } // String -> Uint8Array +/** + * @param {string} str + */ function fromString (str) { return stringToBytes(str) } // Uint8Array -> Uint8Array +/** + * @param {Uint8Array} buf + */ function fromBytes (buf) { const err = validateBytes(buf) if (err) throw err return Uint8Array.from(buf) // copy } +/** + * @param {Uint8Array} buf + */ function validateBytes (buf) { try { bytesToTuples(buf) // try to parse. will throw if breaks @@ -205,18 +252,30 @@ function validateBytes (buf) { } } +/** + * @param {Uint8Array} buf + */ function isValidBytes (buf) { return validateBytes(buf) === undefined } +/** + * @param {string} str + */ function cleanPath (str) { - return '/' + str.trim().split('/').filter(a => a).join('/') + return '/' + str.trim().split('/').filter((/** @type {any} */ a) => a).join('/') } +/** + * @param {string} str + */ function ParseError (str) { return new Error('Error parsing address: ' + str) } +/** + * @param {any[]} tup + */ function protoFromTuple (tup) { const proto = protocols(tup[0]) return proto diff --git a/src/convert.js b/src/convert.js index 7258b50c..4ffa0b10 100644 --- a/src/convert.js +++ b/src/convert.js @@ -12,6 +12,10 @@ const uint8ArrayConcat = require('uint8arrays/concat') module.exports = Convert // converts (serializes) addresses +/** + * @param {string} proto + * @param {string | Uint8Array} a + */ function Convert (proto, a) { if (a instanceof Uint8Array) { return Convert.toString(proto, a) @@ -20,9 +24,16 @@ function Convert (proto, a) { } } +/** + * Convert [code,Uint8Array] to string + * + * @param {number|string} proto + * @param {Uint8Array} buf + * @returns {string} + */ Convert.toString = function convertToString (proto, buf) { - proto = protocols(proto) - switch (proto.code) { + const protocol = protocols(proto) + switch (protocol.code) { case 4: // ipv4 case 41: // ipv6 return bytes2ip(buf) @@ -31,7 +42,7 @@ Convert.toString = function convertToString (proto, buf) { case 273: // udp case 33: // dccp case 132: // sctp - return bytes2port(buf) + return bytes2port(buf).toString() case 53: // dns case 54: // dns4 @@ -52,9 +63,9 @@ Convert.toString = function convertToString (proto, buf) { } } -Convert.toBytes = function convertToBytes (proto, str) { - proto = protocols(proto) - switch (proto.code) { +Convert.toBytes = function convertToBytes (/** @type {string | number } */ proto, /** @type {string} */ str) { + const protocol = protocols(proto) + switch (protocol.code) { case 4: // ipv4 return ip2bytes(str) case 41: // ipv6 @@ -85,6 +96,9 @@ Convert.toBytes = function convertToBytes (proto, str) { } } +/** + * @param {string} ipString + */ function ip2bytes (ipString) { if (!ip.isIP(ipString)) { throw new Error('invalid ip address') @@ -92,6 +106,9 @@ function ip2bytes (ipString) { return ip.toBytes(ipString) } +/** + * @param {Uint8Array} ipBuff + */ function bytes2ip (ipBuff) { const ipString = ip.toString(ipBuff) if (!ipString || !ip.isIP(ipString)) { @@ -100,6 +117,9 @@ function bytes2ip (ipBuff) { return ipString } +/** + * @param {number} port + */ function port2bytes (port) { const buf = new ArrayBuffer(2) const view = new DataView(buf) @@ -108,17 +128,26 @@ function port2bytes (port) { return new Uint8Array(buf) } +/** + * @param {Uint8Array} buf + */ function bytes2port (buf) { const view = new DataView(buf.buffer) return view.getUint16(0) } +/** + * @param {string} str + */ function str2bytes (str) { const buf = uint8ArrayFromString(str) const size = Uint8Array.from(varint.encode(buf.length)) return uint8ArrayConcat([size, buf], size.length + buf.length) } +/** + * @param {Uint8Array} buf + */ function bytes2str (buf) { const size = varint.decode(buf) buf = buf.slice(varint.decode.bytes) @@ -130,6 +159,9 @@ function bytes2str (buf) { return uint8ArrayToString(buf) } +/** + * @param {string | Uint8Array | CID} hash + */ function mh2bytes (hash) { // the address is a varint prefixed multihash string representation const mh = new CID(hash).multihash @@ -137,6 +169,12 @@ function mh2bytes (hash) { return uint8ArrayConcat([size, mh], size.length + mh.length) } +/** + * Converts bytes to bas58btc string + * + * @param {Uint8Array} buf + * @returns {string} bas58btc string + */ function bytes2mh (buf) { const size = varint.decode(buf) const address = buf.slice(varint.decode.bytes) @@ -148,6 +186,9 @@ function bytes2mh (buf) { return uint8ArrayToString(address, 'base58btc') } +/** + * @param {string} str + */ function onion2bytes (str) { const addr = str.split(':') if (addr.length !== 2) { @@ -169,6 +210,9 @@ function onion2bytes (str) { return uint8ArrayConcat([buf, portBuf], buf.length + portBuf.length) } +/** + * @param {string} str + */ function onion32bytes (str) { const addr = str.split(':') if (addr.length !== 2) { @@ -189,6 +233,9 @@ function onion32bytes (str) { return uint8ArrayConcat([buf, portBuf], buf.length + portBuf.length) } +/** + * @param {Uint8Array} buf + */ function bytes2onion (buf) { const addrBytes = buf.slice(0, buf.length - 2) const portBytes = buf.slice(buf.length - 2) diff --git a/src/index.d.ts b/src/index.d.ts deleted file mode 100644 index 0fca50e3..00000000 --- a/src/index.d.ts +++ /dev/null @@ -1,204 +0,0 @@ -declare type NetOptions = { - family: "ipv4" | "ipv6"; - host: string; - transport: "tcp" | "udp"; - port: number; -}; - -declare type Protocol = { - code: number; - size: number; - name: string; - resolvable: boolean | undefined; - path: boolean | undefined; -}; - -declare interface Protocols { - table: { - [index: number]: Protocol; - }; - names: { - [index: string]: Protocol; - }; - codes: { - [index: number]: Protocol; - }; - object( - code: number, - size: number, - name: string, - resolvable?: any, - path?: any - ): Protocol; -} - -declare type NodeAddress = { - family: "IPv4" | "IPv6"; - address: string; - port: string; -}; - -declare type MultiaddrInput = string | Uint8Array | Multiaddr | null; - -declare class Multiaddr { - /** - * Creates a [multiaddr](https://github.com/multiformats/multiaddr) from - * a Uint8Array, String or another Multiaddr instance - * public key. - * @param addr - If String or Uint8Array, needs to adhere - * to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format) - */ - constructor(addr?: MultiaddrInput); - - bytes: Uint8Array; - - /** - * Returns Multiaddr as a String - */ - toString(): string; - - /** - * Returns Multiaddr as a JSON encoded object - */ - toJSON(): string; - - /** - * Returns Multiaddr as a convinient options object to be used with net.createConnection - */ - toOptions(): NetOptions; - - /** - * Returns Multiaddr as a human-readable string - */ - inspect(): string; - - /** - * Returns the protocols the Multiaddr is defined with, as an array of objects, in - * left-to-right order. Each object contains the protocol code, protocol name, - * and the size of its address space in bits. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - */ - protos(): Protocol[]; - - /** - * Returns the codes of the protocols in left-to-right order. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - */ - protoCodes(): number[]; - - /** - * Returns the names of the protocols in left-to-right order. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - */ - protoNames(): string[]; - - /** - * Returns a tuple of parts - */ - tuples(): [number, Uint8Array][]; - - /** - * Returns a tuple of string/number parts - */ - stringTuples(): [number, string | number][]; - - /** - * Encapsulates a Multiaddr in another Multiaddr - */ - encapsulate(addr: MultiaddrInput): Multiaddr; - - /** - * Decapsulates a Multiaddr from another Multiaddr - */ - decapsulate(addr: MultiaddrInput): Multiaddr; - - /** - * A more reliable version of `decapsulate` if you are targeting a - * specific code, such as 421 (the `p2p` protocol code). The last index of the code - * will be removed from the `Multiaddr`, and a new instance will be returned. - * If the code is not present, the original `Multiaddr` is returned. - */ - decapsulateCode(code: number): Multiaddr; - - /** - * Extract the peerId if the multiaddr contains one - */ - getPeerId(): string; - - /** - * Extract the path if the multiaddr contains one - */ - getPath(): string | null; - - /** - * Checks if two Multiaddrs are the same - */ - equals(addr: Multiaddr): boolean; - - /** - * Gets a Multiaddrs node-friendly address object. Note that protocol information - * is left out: in Node (and most network systems) the protocol is unknowable - * given only the address. - * - * Has to be a ThinWaist Address, otherwise throws error - */ - nodeAddress(): NodeAddress; - - /** - * Returns if a Multiaddr is a Thin Waist address or not. - * - * Thin Waist is if a Multiaddr adheres to the standard combination of: - * - * `{IPv4, IPv6}/{TCP, UDP}` - */ - isThinWaistAddress(addr?: Multiaddr): boolean; - - /** - * Resolve multiaddr if containing resolvable hostname. - */ - resolve(): Promise> -} - -declare namespace Multiaddr { - const resolvers: Map < string, (addr: Multiaddr) => Promise < Array < string >>> - - /** - * Creates a Multiaddr from a node-friendly address object - */ - function fromNodeAddress(addr: NodeAddress, transport: string): Multiaddr; - - /** - * Object containing table, names and codes of all supported protocols. - * To get the protocol values from a Multiaddr, you can use - * [`.protos()`](#multiaddrprotos), - * [`.protoCodes()`](#multiaddrprotocodes) or - * [`.protoNames()`](#multiaddrprotonames) - */ - const protocols: Protocols; - - /** - * Returns if something is a Multiaddr - */ - function isMultiaddr(addr: unknown): addr is Multiaddr; - - /** - * Returns if something is a Multiaddr that is a name - */ - function isName(addr: Multiaddr): boolean; - - /** - * Returns an array of multiaddrs, by resolving the multiaddr that is a name - */ - function resolve(addr: Multiaddr): Promise; -} - -/** - * Creates a [multiaddr](https://github.com/multiformats/multiaddr) from - * a Uint8Array, String or another Multiaddr instance - * public key. - * @param addr - If String or Uint8Array, needs to adhere - * to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format) - */ -declare function Multiaddr(input?: MultiaddrInput): Multiaddr; - -export = Multiaddr; diff --git a/src/index.js b/src/index.js index fc464bd6..50d328b6 100644 --- a/src/index.js +++ b/src/index.js @@ -4,507 +4,590 @@ const codec = require('./codec') const protocols = require('./protocols-table') const varint = require('varint') const CID = require('cids') -const withIs = require('class-is') const errCode = require('err-code') const inspect = Symbol.for('nodejs.util.inspect.custom') const uint8ArrayToString = require('uint8arrays/to-string') const uint8ArrayEquals = require('uint8arrays/equals') +/** + * @typedef {(addr: Multiaddr) => Promise} Resolver + * @typedef {string | Multiaddr | Uint8Array | null} MultiaddrInput + * @typedef {import('./types').MultiaddrObject} MultiaddrObject + * @typedef {import('./types').Protocol} Protocol + */ + +/** @type {Map} */ const resolvers = new Map() +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. * - * @class Multiaddr - * @param {(string | Uint8Array | Multiaddr)} addr - If String or Uint8Array, needs to adhere - * to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format) - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001') - * // */ -const Multiaddr = withIs.proto(function (addr) { - if (!(this instanceof Multiaddr)) { - return new Multiaddr(addr) - } +class Multiaddr { + /** + * @example + * ```js + * new 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) + */ + constructor (addr) { + // default + if (addr == null) { + addr = '' + } - // default - if (addr == null) { - addr = '' - } + // Define symbol + Object.defineProperty(this, symbol, { value: true }) - if (addr instanceof Uint8Array) { - /** - * @type {Uint8Array} - The raw bytes representing this multiaddress - */ - this.bytes = codec.fromBytes(addr) - } else if (typeof addr === 'string' || addr instanceof String) { - if (addr.length > 0 && addr.charAt(0) !== '/') { - throw new Error(`multiaddr "${addr}" must start with a "/"`) + if (addr instanceof Uint8Array) { + /** @type {Uint8Array} - The raw bytes representing this multiaddress */ + 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)) { // Multiaddr + this.bytes = codec.fromBytes(addr.bytes) // validate + copy buffer + } else { + throw new Error('addr must be a string, Buffer, or another Multiaddr') } - this.bytes = codec.fromString(addr) - } else if (addr.bytes && addr.protos && addr.protoCodes) { // Multiaddr - this.bytes = codec.fromBytes(addr.bytes) // validate + copy buffer - } else { - throw new Error('addr must be a string, Buffer, or another Multiaddr') } -}, { className: 'Multiaddr', symbolName: '@multiformats/js-multiaddr/multiaddr' }) -/** - * Returns Multiaddr as a String - * - * @returns {string} - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').toString() - * // '/ip4/127.0.0.1/tcp/4001' - */ -Multiaddr.prototype.toString = function toString () { - return codec.bytesToString(this.bytes) -} - -/** - * Returns Multiaddr as a JSON encoded object - * - * @returns {string} - * @example - * JSON.stringify(Multiaddr('/ip4/127.0.0.1/tcp/4001')) - * // '/ip4/127.0.0.1/tcp/4001' - */ -Multiaddr.prototype.toJSON = Multiaddr.prototype.toString - -/** - * Returns Multiaddr as a convinient options object to be used with net.createConnection - * - * @returns {{family: string, host: string, transport: string, port: number}} - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').toOptions() - * // { family: 'ipv4', host: '127.0.0.1', transport: 'tcp', port: 4001 } - */ -Multiaddr.prototype.toOptions = function toOptions () { - const opts = {} - const parsed = this.toString().split('/') - opts.family = parsed[1] === 'ip4' ? 'ipv4' : 'ipv6' - opts.host = parsed[2] - opts.transport = parsed[3] - opts.port = parseInt(parsed[4]) - return opts -} - -/** - * Returns Multiaddr as a human-readable string. - * For post Node.js v10.0.0. - * https://nodejs.org/api/deprecations.html#deprecations_dep0079_custom_inspection_function_on_objects_via_inspect - * - * @returns {string} - * @example - * console.log(Multiaddr('/ip4/127.0.0.1/tcp/4001')) - * // '' - */ -Multiaddr.prototype[inspect] = function inspectCustom () { - return '' -} - -/** - * Returns Multiaddr as a human-readable string. - * Fallback for pre Node.js v10.0.0. - * https://nodejs.org/api/deprecations.html#deprecations_dep0079_custom_inspection_function_on_objects_via_inspect - * - * @returns {string} - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').inspect() - * // '' - */ -Multiaddr.prototype.inspect = function inspect () { - return '' -} + /** + * Returns Multiaddr as a String + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').toString() + * // '/ip4/127.0.0.1/tcp/4001' + * ``` + */ + toString () { + return codec.bytesToString(this.bytes) + } -/** - * @typedef {object} protocol - * @property {number} code - * @property {number} size - * @property {string} name - * @property {boolean} [resolvable] - * @property {boolean} [path] - */ + /** + * Returns Multiaddr as a JSON encoded object + * + * @example + * ```js + * JSON.stringify(new Multiaddr('/ip4/127.0.0.1/tcp/4001')) + * // '/ip4/127.0.0.1/tcp/4001' + * ``` + */ + toJSON () { + return this.toString() + } -/** - * Returns the protocols the Multiaddr is defined with, as an array of objects, in - * left-to-right order. Each object contains the protocol code, protocol name, - * and the size of its address space in bits. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - * - * @returns {protocol[]} protocols - All the protocols the address is composed of - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').protos() - * // [ { code: 4, size: 32, name: 'ip4' }, - * // { code: 6, size: 16, name: 'tcp' } ] - */ -Multiaddr.prototype.protos = function protos () { - return this.protoCodes().map(code => Object.assign({}, protocols(code))) -} + /** + * Returns Multiaddr as a convinient options object to be used with net.createConnection + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').toOptions() + * // { family: 4, host: '127.0.0.1', transport: 'tcp', port: 4001 } + * ``` + */ + toOptions () { + /** @type {MultiaddrObject} */ + const opts = {} + const parsed = this.toString().split('/') + opts.family = parsed[1] === 'ip4' ? 4 : 6 + opts.host = parsed[2] + opts.transport = parsed[3] + opts.port = parseInt(parsed[4]) + return opts + } -/** - * Returns the codes of the protocols in left-to-right order. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - * - * @returns {Array} protocol codes - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').protoCodes() - * // [ 4, 6 ] - */ -Multiaddr.prototype.protoCodes = function 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 = protocols(code) - const size = codec.sizeForAddr(p, buf.slice(i + n)) - - i += (size + n) - codes.push(code) + /** + * Returns the protocols the Multiaddr is defined with, as an array of objects, in + * left-to-right order. Each object contains the protocol code, protocol name, + * and the size of its address space in bits. + * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').protos() + * // [ { code: 4, size: 32, name: 'ip4' }, + * // { code: 6, size: 16, name: 'tcp' } ] + * ``` + * + * @returns {Protocol[]} protocols - All the protocols the address is composed of + */ + protos () { + return this.protoCodes().map(code => Object.assign({}, protocols(code))) } - return codes -} + /** + * Returns the codes of the protocols in left-to-right order. + * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) + * + * @example + * ```js + * Multiaddr('/ip4/127.0.0.1/tcp/4001').protoCodes() + * // [ 4, 6 ] + * ``` + * + * @returns {number[]} protocol codes + */ + 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 = protocols(code) + const size = codec.sizeForAddr(p, buf.slice(i + n)) + + i += (size + n) + codes.push(code) + } -/** - * Returns the names of the protocols in left-to-right order. - * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) - * - * @returns {Array.} protocol names - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').protoNames() - * // [ 'ip4', 'tcp' ] - */ -Multiaddr.prototype.protoNames = function protoNames () { - return this.protos().map(proto => proto.name) -} + return codes + } -/** - * Returns a tuple of parts - * - * @returns {[number, Uint8Array][]} tuples - * @example - * Multiaddr("/ip4/127.0.0.1/tcp/4001").tuples() - * // [ [ 4, ], [ 6, ] ] - */ -Multiaddr.prototype.tuples = function tuples () { - return codec.bytesToTuples(this.bytes) -} + /** + * Returns the names of the protocols in left-to-right order. + * [See list of protocols](https://github.com/multiformats/multiaddr/blob/master/protocols.csv) + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').protoNames() + * // [ 'ip4', 'tcp' ] + * ``` + * + * @returns {string[]} protocol names + */ + protoNames () { + return this.protos().map(proto => proto.name) + } -/** - * Returns a tuple of string/number parts - * - tuples[][0] = code of protocol - * - tuples[][1] = contents of address - * - * @returns {[number, string|number][]} tuples - * @example - * Multiaddr("/ip4/127.0.0.1/tcp/4001").stringTuples() - * // [ [ 4, '127.0.0.1' ], [ 6, 4001 ] ] - */ -Multiaddr.prototype.stringTuples = function stringTuples () { - const t = codec.bytesToTuples(this.bytes) - return codec.tuplesToStringTuples(t) -} + /** + * Returns a tuple of parts + * + * @example + * ```js + * new Multiaddr("/ip4/127.0.0.1/tcp/4001").tuples() + * // [ [ 4, ], [ 6, ] ] + * ``` + */ + tuples () { + return codec.bytesToTuples(this.bytes) + } -/** - * Encapsulates a Multiaddr in another Multiaddr - * - * @param {Multiaddr} addr - Multiaddr to add into this Multiaddr - * @returns {Multiaddr} - * @example - * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080') - * // - * - * const mh2 = Multiaddr('/ip4/127.0.0.1/tcp/4001') - * // - * - * const mh3 = mh1.encapsulate(mh2) - * // - * - * mh3.toString() - * // '/ip4/8.8.8.8/tcp/1080/ip4/127.0.0.1/tcp/4001' - */ -Multiaddr.prototype.encapsulate = function encapsulate (addr) { - addr = Multiaddr(addr) - return Multiaddr(this.toString() + addr.toString()) -} + /** + * Returns a tuple of string/number parts + * - tuples[][0] = code of protocol + * - tuples[][1] = contents of address + * + * @example + * ```js + * new Multiaddr("/ip4/127.0.0.1/tcp/4001").stringTuples() + * // [ [ 4, '127.0.0.1' ], [ 6, '4001' ] ] + * ``` + */ + stringTuples () { + const t = codec.bytesToTuples(this.bytes) + return codec.tuplesToStringTuples(t) + } -/** - * Decapsulates a Multiaddr from another Multiaddr - * - * @param {Multiaddr} addr - Multiaddr to remove from this Multiaddr - * @returns {Multiaddr} - * @example - * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080') - * // - * - * const mh2 = Multiaddr('/ip4/127.0.0.1/tcp/4001') - * // - * - * const mh3 = mh1.encapsulate(mh2) - * // - * - * mh3.decapsulate(mh2).toString() - * // '/ip4/8.8.8.8/tcp/1080' - */ -Multiaddr.prototype.decapsulate = function decapsulate (addr) { - addr = addr.toString() - const s = this.toString() - const i = s.lastIndexOf(addr) - if (i < 0) { - throw new Error('Address ' + this + ' does not contain subaddress: ' + addr) + /** + * Encapsulates a Multiaddr in another Multiaddr + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/8.8.8.8/tcp/1080') + * // + * + * const mh2 = new Multiaddr('/ip4/127.0.0.1/tcp/4001') + * // + * + * const mh3 = mh1.encapsulate(mh2) + * // + * + * mh3.toString() + * // '/ip4/8.8.8.8/tcp/1080/ip4/127.0.0.1/tcp/4001' + * ``` + * + * @param {MultiaddrInput} addr - Multiaddr to add into this Multiaddr + */ + encapsulate (addr) { + addr = new Multiaddr(addr) + return new Multiaddr(this.toString() + addr.toString()) } - return Multiaddr(s.slice(0, i)) -} -/** - * A more reliable version of `decapsulate` if you are targeting a - * specific code, such as 421 (the `p2p` protocol code). The last index of the code - * will be removed from the `Multiaddr`, and a new instance will be returned. - * If the code is not present, the original `Multiaddr` is returned. - * - * @param {number} code - The code of the protocol to decapsulate from this Multiaddr - * @returns {Multiaddr} - * @example - * const addr = Multiaddr('/ip4/0.0.0.0/tcp/8080/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') - * // - * - * addr.decapsulateCode(421).toString() - * // '/ip4/0.0.0.0/tcp/8080' - * - * Multiaddr('/ip4/127.0.0.1/tcp/8080').decapsulateCode(421).toString() - * // '/ip4/127.0.0.1/tcp/8080' - */ -Multiaddr.prototype.decapsulateCode = function decapsulateCode (code) { - const tuples = this.tuples() - for (let i = tuples.length - 1; i >= 0; i--) { - if (tuples[i][0] === code) { - return Multiaddr(codec.tuplesToBytes(tuples.slice(0, i))) + /** + * Decapsulates a Multiaddr from another Multiaddr + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/8.8.8.8/tcp/1080') + * // + * + * const mh2 = new Multiaddr('/ip4/127.0.0.1/tcp/4001') + * // + * + * const mh3 = mh1.encapsulate(mh2) + * // + * + * mh3.decapsulate(mh2).toString() + * // '/ip4/8.8.8.8/tcp/1080' + * ``` + * + * @param {Multiaddr | string} addr - Multiaddr to remove from this Multiaddr + * @returns {Multiaddr} + */ + decapsulate (addr) { + const addrString = addr.toString() + const s = this.toString() + const i = s.lastIndexOf(addrString) + if (i < 0) { + throw new Error('Address ' + this + ' does not contain subaddress: ' + addr) } + return new Multiaddr(s.slice(0, i)) } - return this -} -/** - * Extract the peerId if the multiaddr contains one - * - * @returns {string | null} peerId - The id of the peer or null if invalid or missing from the ma - * @example - * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080/ipfs/QmValidBase58string') - * // - * - * // should return QmValidBase58string or null if the id is missing or invalid - * const peerId = mh1.getPeerId() - */ -Multiaddr.prototype.getPeerId = function getPeerId () { - let b58str = null - try { - const tuples = this.stringTuples().filter((tuple) => { - if (tuple[0] === protocols.names.ipfs.code) { - return true + /** + * A more reliable version of `decapsulate` if you are targeting a + * specific code, such as 421 (the `p2p` protocol code). The last index of the code + * will be removed from the `Multiaddr`, and a new instance will be returned. + * If the code is not present, the original `Multiaddr` is returned. + * + * @example + * ```js + * const addr = new Multiaddr('/ip4/0.0.0.0/tcp/8080/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') + * // + * + * addr.decapsulateCode(421).toString() + * // '/ip4/0.0.0.0/tcp/8080' + * + * new Multiaddr('/ip4/127.0.0.1/tcp/8080').decapsulateCode(421).toString() + * // '/ip4/127.0.0.1/tcp/8080' + * ``` + * + * @param {number} code - The code of the protocol to decapsulate from this Multiaddr + * @returns {Multiaddr} + */ + 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))) } - }) - - // Get the last id - b58str = tuples.pop()[1] - // Get multihash, unwrap from CID if needed - b58str = uint8ArrayToString(new CID(b58str).multihash, 'base58btc') - } catch (e) { - b58str = null + } + return this } - return b58str -} + /** + * Extract the peerId if the multiaddr contains one + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/8.8.8.8/tcp/1080/ipfs/QmValidBase58string') + * // + * + * // should return QmValidBase58string or null if the id is missing or invalid + * const peerId = mh1.getPeerId() + * ``` + * + * @returns {string | null} peerId - The id of the peer or null if invalid or missing from the ma + */ + getPeerId () { + try { + const tuples = this.stringTuples().filter((tuple) => { + if (tuple[0] === protocols.names.ipfs.code) { + return true + } + return false + }) + + // Get the last ipfs tuple ['ipfs', 'peerid string'] + const tuple = tuples.pop() + if (tuple && tuple[1]) { + // Get multihash, unwrap from CID if needed + return uint8ArrayToString(new CID(tuple[1]).multihash, 'base58btc') + } else { + return null + } + } catch (e) { + return null + } + } -/** - * Extract the path if the multiaddr contains one - * - * @returns {string | null} path - The path of the multiaddr, or null if no path protocol is present - * @example - * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock') - * // - * - * // should return utf8 string or null if the id is missing or invalid - * const path = mh1.getPath() - */ -Multiaddr.prototype.getPath = function getPath () { - let path = null - try { - path = this.stringTuples().filter((tuple) => { - const proto = protocols(tuple[0]) - if (proto.path) { - return true + /** + * Extract the path if the multiaddr contains one + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock') + * // + * + * // should return utf8 string or null if the id is missing or invalid + * const path = mh1.getPath() + * ```js + * + * @returns {string | null} path - The path of the multiaddr, or null if no path protocol is present + */ + getPath () { + let path = null + try { + path = this.stringTuples().filter((tuple) => { + const proto = protocols(tuple[0]) + if (proto.path) { + return true + } + return false + })[0][1] + + if (!path) { + path = null } - })[0][1] - } catch (e) { - path = null + } catch (e) { + path = null + } + return path } - return path -} + /** + * Checks if two Multiaddrs are the same + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/8.8.8.8/tcp/1080') + * // + * + * const mh2 = new Multiaddr('/ip4/127.0.0.1/tcp/4001') + * // + * + * mh1.equals(mh1) + * // true + * + * mh1.equals(mh2) + * // false + * ``` + * + * @param {Multiaddr} addr + * @returns {boolean} + */ + equals (addr) { + return uint8ArrayEquals(this.bytes, addr.bytes) + } -/** - * Checks if two Multiaddrs are the same - * - * @param {Multiaddr} addr - * @returns {Bool} - * @example - * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080') - * // - * - * const mh2 = Multiaddr('/ip4/127.0.0.1/tcp/4001') - * // - * - * mh1.equals(mh1) - * // true - * - * mh1.equals(mh2) - * // false - */ -Multiaddr.prototype.equals = function equals (addr) { - return uint8ArrayEquals(this.bytes, addr.bytes) -} + /** + * Resolve multiaddr if containing resolvable hostname. + * + * @example + * ```js + * Multiaddr.resolvers.set('dnsaddr', resolverFunction) + * const mh1 = new Multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') + * const resolvedMultiaddrs = await mh1.resolve() + * // [ + * // , + * // , + * // + * // ] + * ``` + * + * @returns {Promise>} + */ + async resolve () { + const resolvableProto = this.protos().find((p) => p.resolvable) -/** - * Resolve multiaddr if containing resolvable hostname. - * - * @returns {Promise>} - * @example - * Multiaddr.resolvers.set('dnsaddr', resolverFunction) - * const mh1 = Multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') - * const resolvedMultiaddrs = await mh1.resolve() - * // [ - * // , - * // , - * // - * // ] - */ -Multiaddr.prototype.resolve = async function resolve () { - const resolvableProto = this.protos().find((p) => p.resolvable) + // Multiaddr is not resolvable? + if (!resolvableProto) { + return [this] + } - // Multiaddr is not resolvable? - if (!resolvableProto) { - return [this] - } + const resolver = resolvers.get(resolvableProto.name) + if (!resolver) { + throw errCode(new Error(`no available resolver for ${resolvableProto.name}`), 'ERR_NO_AVAILABLE_RESOLVER') + } - const resolver = resolvers.get(resolvableProto.name) - if (!resolver) { - 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)) } - const addresses = await resolver(this) - return addresses.map(a => Multiaddr(a)) -} + /** + * Gets a Multiaddrs node-friendly address object. Note that protocol information + * is left out: in Node (and most network systems) the protocol is unknowable + * given only the address. + * + * Has to be a ThinWaist Address, otherwise throws error + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').nodeAddress() + * // {family: 4, address: '127.0.0.1', port: 4001} + * ``` + * + * @returns {{family: 4 | 6, address: string, port: number}} + * @throws {Error} Throws error if Multiaddr is not a Thin Waist address + */ + 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}".`) + } -/** - * Gets a Multiaddrs node-friendly address object. Note that protocol information - * is left out: in Node (and most network systems) the protocol is unknowable - * given only the address. - * - * Has to be a ThinWaist Address, otherwise throws error - * - * @returns {{family: string, address: string, port: number}} - * @throws {Error} Throws error if Multiaddr is not a Thin Waist address - * @example - * Multiaddr('/ip4/127.0.0.1/tcp/4001').nodeAddress() - * // {family: 'IPv4', address: '127.0.0.1', port: '4001'} - */ -Multiaddr.prototype.nodeAddress = function 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]) // tcp or udp port + } } - return { - family: (codes[0] === 41 || codes[0] === 55) ? 6 : 4, - address: parts[1], // ip addr - port: parseInt(parts[3]) // tcp or udp port + /** + * Returns if a Multiaddr is a Thin Waist address or not. + * + * Thin Waist is if a Multiaddr adheres to the standard combination of: + * + * `{IPv4, IPv6}/{TCP, UDP}` + * + * @example + * ```js + * const mh1 = new Multiaddr('/ip4/127.0.0.1/tcp/4001') + * // + * const mh2 = new Multiaddr('/ip4/192.168.2.1/tcp/5001') + * // + * const mh3 = mh1.encapsulate(mh2) + * // + * const mh4 = new Multiaddr('/ip4/127.0.0.1/tcp/2000/wss/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a') + * // + * mh1.isThinWaistAddress() + * // true + * mh2.isThinWaistAddress() + * // true + * mh3.isThinWaistAddress() + * // false + * mh4.isThinWaistAddress() + * // false + * ``` + * + * @param {Multiaddr} [addr] - Defaults to using `this` instance + */ + 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 } -} -/** - * Creates a Multiaddr from a node-friendly address object - * - * @param {{family: string, address: string, port: number}} addr - * @param {string} transport - * @returns {Multiaddr} multiaddr - * @throws {Error} Throws error if addr is not truthy - * @throws {Error} Throws error if transport is not truthy - * @example - * Multiaddr.fromNodeAddress({address: '127.0.0.1', port: '4001'}, 'tcp') - * // - */ -Multiaddr.fromNodeAddress = function fromNodeAddress (addr, transport) { - if (!addr) throw new Error('requires node address object') - if (!transport) throw new Error('requires transport protocol') - let ip - switch (addr.family) { - case 'IPv4': - ip = 'ip4' - break - case 'IPv6': - ip = 'ip6' - break - default: - throw Error(`Invalid addr family. Got '${addr.family}' instead of 'IPv4' or 'IPv6'`) + /** + * Creates a Multiaddr from a node-friendly address object + * + * @example + * ```js + * Multiaddr.fromNodeAddress({address: '127.0.0.1', port: '4001'}, 'tcp') + * // + * ``` + * + * @param {{family: 4 | 6, address: string, port: number}} addr + * @param {string} transport + */ + static fromNodeAddress (addr, transport) { + if (!addr) { throw new Error('requires node address object') } + if (!transport) { 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. Got '${addr.family}' instead of 4 or 6`) + } + return new Multiaddr('/' + [ip, addr.address, transport, addr.port].join('/')) } - return Multiaddr('/' + [ip, addr.address, transport, addr.port].join('/')) -} -// TODO find a better example, not sure about it's good enough -/** - * Returns if a Multiaddr is a Thin Waist address or not. - * - * Thin Waist is if a Multiaddr adheres to the standard combination of: - * - * `{IPv4, IPv6}/{TCP, UDP}` - * - * @param {Multiaddr} [addr] - Defaults to using `this` instance - * @returns {boolean} isThinWaistAddress - * @example - * const mh1 = Multiaddr('/ip4/127.0.0.1/tcp/4001') - * // - * const mh2 = Multiaddr('/ip4/192.168.2.1/tcp/5001') - * // - * const mh3 = mh1.encapsulate(mh2) - * // - * mh1.isThinWaistAddress() - * // true - * mh2.isThinWaistAddress() - * // true - * mh3.isThinWaistAddress() - * // false - */ -Multiaddr.prototype.isThinWaistAddress = function isThinWaistAddress (addr) { - const protos = (addr || this).protos() + /** + * Returns if something is a Multiaddr that is a name + * + * @param {Multiaddr} addr + * @returns {boolean} isName + */ + static isName (addr) { + if (!Multiaddr.isMultiaddr(addr)) { + return false + } - if (protos.length !== 2) { - return false + // if a part of the multiaddr is resolvable, then return true + return addr.protos().some((proto) => proto.resolvable) } - if (protos[0].code !== 4 && protos[0].code !== 41) { - return false + /** + * Check if object is a CID instance + * + * @param {any} value + * @returns {value is Multiaddr} + */ + static isMultiaddr (value) { + return value instanceof Multiaddr || Boolean(value && value[symbol]) } - if (protos[1].code !== 6 && protos[1].code !== 273) { - return false + + /** + * Returns Multiaddr as a human-readable string. + * For post Node.js v10.0.0. + * https://nodejs.org/api/deprecations.html#deprecations_dep0079_custom_inspection_function_on_objects_via_inspect + * + * @example + * ```js + * console.log(new Multiaddr('/ip4/127.0.0.1/tcp/4001')) + * // '' + * ``` + * + * @returns {string} + */ + [inspect] () { + return '' + } + + /** + * Returns Multiaddr as a human-readable string. + * Fallback for pre Node.js v10.0.0. + * https://nodejs.org/api/deprecations.html#deprecations_dep0079_custom_inspection_function_on_objects_via_inspect + * + * @example + * ```js + * new Multiaddr('/ip4/127.0.0.1/tcp/4001').inspect() + * // '' + * ``` + * + * @returns {string} + */ + inspect () { + return '' } - return true } /** @@ -514,46 +597,19 @@ Multiaddr.prototype.isThinWaistAddress = function isThinWaistAddress (addr) { * [`.protoCodes()`](#multiaddrprotocodes) or * [`.protoNames()`](#multiaddrprotonames) * - * @instance * @returns {{table: Array, names: Object, codes: Object}} - * */ Multiaddr.protocols = protocols -/** - * Returns if something is a Multiaddr that is a name - * - * @param {Multiaddr} addr - * @returns {Bool} isName - */ -Multiaddr.isName = function isName (addr) { - if (!Multiaddr.isMultiaddr(addr)) { - return false - } - - // if a part of the multiaddr is resolvable, then return true - return addr.protos().some((proto) => proto.resolvable) -} +Multiaddr.resolvers = resolvers /** - * Returns an array of multiaddrs, by resolving the multiaddr that is a name + * Static factory * - * @async - * @param {Multiaddr} addr - * @returns {Multiaddr[]} + * @param {MultiaddrInput} addr */ -Multiaddr.resolve = function resolve (addr) { - if (!Multiaddr.isMultiaddr(addr) || !Multiaddr.isName(addr)) { - return Promise.reject(Error('not a valid name')) - } - - /* - * Needs more consideration from spec design: - * - what to return - * - how to achieve it in the browser? - */ - return Promise.reject(new Error('not implemented yet')) +function multiaddr (addr) { + return new Multiaddr(addr) } -Multiaddr.resolvers = resolvers -exports = module.exports = Multiaddr +module.exports = { Multiaddr, multiaddr, protocols, resolvers } diff --git a/src/ip.js b/src/ip.js index c1ffb273..958423ba 100644 --- a/src/ip.js +++ b/src/ip.js @@ -8,22 +8,25 @@ const isV4 = isIp.v4 const isV6 = isIp.v6 // Copied from https://github.com/indutny/node-ip/blob/master/lib/ip.js#L7 +// @ts-ignore - this is copied from the link above better to keep it the same const toBytes = function (ip, buff, offset) { offset = ~~offset - var result + let result if (isV4(ip)) { result = buff || new Uint8Array(offset + 4) + // @ts-ignore + // eslint-disable-next-line array-callback-return ip.split(/\./g).map(function (byte) { result[offset++] = parseInt(byte, 10) & 0xff }) } else if (isV6(ip)) { - var sections = ip.split(':', 8) + const sections = ip.split(':', 8) - var i + let i for (i = 0; i < sections.length; i++) { - var isv4 = isV4(sections[i]) + const isv4 = isV4(sections[i]) var v4Buffer if (isv4) { @@ -42,7 +45,7 @@ const toBytes = function (ip, buff, offset) { while (sections.length < 8) sections.push('0') } else if (sections.length < 8) { for (i = 0; i < sections.length && sections[i] !== ''; i++); - var argv = [i, '1'] + const argv = [i, '1'] for (i = 9 - sections.length; i > 0; i--) { argv.push('0') } @@ -51,7 +54,7 @@ const toBytes = function (ip, buff, offset) { result = buff || new Uint8Array(offset + 16) for (i = 0; i < sections.length; i++) { - var word = parseInt(sections[i], 16) + const word = parseInt(sections[i], 16) result[offset++] = (word >> 8) & 0xff result[offset++] = word & 0xff } @@ -65,12 +68,13 @@ const toBytes = function (ip, buff, offset) { } // Copied from https://github.com/indutny/node-ip/blob/master/lib/ip.js#L63 +// @ts-ignore - this is copied from the link above better to keep it the same const toString = function (buff, offset, length) { offset = ~~offset length = length || (buff.length - offset) - var result = [] - var string + const result = [] + let string const view = new DataView(buff.buffer) if (length === 4) { // IPv4 diff --git a/src/protocols-table.js b/src/protocols-table.js index 4578e436..3431af59 100644 --- a/src/protocols-table.js +++ b/src/protocols-table.js @@ -1,5 +1,12 @@ 'use strict' +/** @typedef {import("./types").Protocol} Protocol */ +/** + * Protocols + * + * @param {number | string} proto + * @returns {Protocol} + */ function Protocols (proto) { if (typeof (proto) === 'number') { if (Protocols.codes[proto]) { @@ -7,7 +14,7 @@ function Protocols (proto) { } throw new Error('no protocol with code: ' + proto) - } else if (typeof (proto) === 'string' || proto instanceof String) { + } else if (typeof (proto) === 'string') { if (Protocols.names[proto]) { return Protocols.names[proto] } @@ -22,6 +29,7 @@ const V = -1 Protocols.lengthPrefixedVarSize = V Protocols.V = V +/** @type {Array<[number, number, string, (string|boolean)?, string?]>} */ Protocols.table = [ [4, 32, 'ip4'], [6, 16, 'tcp'], @@ -58,8 +66,9 @@ Protocols.table = [ [480, 0, 'http'], [777, V, 'memory'] ] - +/** @type {Record} */ Protocols.names = {} +/** @type {Record} */ Protocols.codes = {} // populate tables @@ -67,10 +76,22 @@ Protocols.table.map(row => { const proto = p.apply(null, row) Protocols.codes[proto.code] = proto Protocols.names[proto.name] = proto + return null }) Protocols.object = p +/** + * + * Create a protocol + * + * @param {number} code + * @param {number} size + * @param {string} name + * @param {any} [resolvable] + * @param {any} [path] + * @returns {Protocol} + */ function p (code, size, name, resolvable, path) { return { code, diff --git a/src/resolvers/dns.browser.js b/src/resolvers/dns.browser.js new file mode 100644 index 00000000..b5d16980 --- /dev/null +++ b/src/resolvers/dns.browser.js @@ -0,0 +1,7 @@ +'use strict' + +/** @type {import('dns').promises.Resolver} */ +// @ts-ignore - has no types +const dns = require('dns-over-http-resolver') + +module.exports = dns diff --git a/src/resolvers/dns.js b/src/resolvers/dns.js index e85a5bd2..32bde6bf 100644 --- a/src/resolvers/dns.js +++ b/src/resolvers/dns.js @@ -1,14 +1,3 @@ 'use strict' -let dns - -try { - dns = require('dns').promises - if (!dns) { - throw new Error('no dns available') - } -} catch (err) { - dns = require('dns-over-http-resolver') -} - -module.exports = dns +module.exports = require('dns').promises.Resolver diff --git a/src/resolvers/index.js b/src/resolvers/index.js index d14c5c99..da082b24 100644 --- a/src/resolvers/index.js +++ b/src/resolvers/index.js @@ -1,25 +1,27 @@ 'use strict' -const Multiaddr = require('..') // eslint-disable-line no-unused-vars const protocols = require('../protocols-table') const { code: dnsaddrCode } = protocols('dnsaddr') +/** + * @typedef {import('..').Multiaddr} Multiaddr + */ + /** * Resolver for dnsaddr addresses. * * @param {Multiaddr} addr - * @returns {Promise>} + * @returns {Promise} */ async function dnsaddrResolver (addr) { - const { Resolver } = require('./dns') + const Resolver = require('./dns') const resolver = new Resolver() const peerId = addr.getPeerId() const [, hostname] = addr.stringTuples().find(([proto]) => proto === dnsaddrCode) || [] const records = await resolver.resolveTxt(`_dnsaddr.${hostname}`) - // @ts-ignore let addresses = records.flat().map((a) => a.split('=')[1]) if (peerId) { diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 00000000..5f3185fd --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,14 @@ +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 +} diff --git a/test/index.spec.js b/test/index.spec.js index c154eb4a..09999111 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -2,106 +2,108 @@ /* eslint-env mocha */ 'use strict' -const multiaddr = require('../src') +const { Multiaddr } = require('../src') const { expect } = require('aegir/utils/chai') const uint8ArrayFromString = require('uint8arrays/from-string') describe('construction', () => { + /** @type {Multiaddr} */ let udpAddr it('create multiaddr', () => { - udpAddr = multiaddr('/ip4/127.0.0.1/udp/1234') - expect(udpAddr instanceof multiaddr).to.equal(true) + udpAddr = new Multiaddr('/ip4/127.0.0.1/udp/1234') + expect(udpAddr instanceof Multiaddr).to.equal(true) }) it('clone multiaddr', () => { - const udpAddrClone = multiaddr(udpAddr) + const udpAddrClone = new Multiaddr(udpAddr) expect(udpAddrClone !== udpAddr).to.equal(true) }) it('reconstruct with buffer', () => { - expect(multiaddr(udpAddr.bytes).bytes === udpAddr.bytes).to.equal(false) - expect(multiaddr(udpAddr.bytes).bytes).to.deep.equal(udpAddr.bytes) + expect(new Multiaddr(udpAddr.bytes).bytes === udpAddr.bytes).to.equal(false) + expect(new Multiaddr(udpAddr.bytes).bytes).to.deep.equal(udpAddr.bytes) }) it('reconstruct with string', () => { - expect(multiaddr(udpAddr.toString()).bytes === udpAddr.bytes).to.equal(false) - expect(multiaddr(udpAddr.toString()).bytes).to.deep.equal(udpAddr.bytes) + expect(new Multiaddr(udpAddr.toString()).bytes === udpAddr.bytes).to.equal(false) + expect(new Multiaddr(udpAddr.toString()).bytes).to.deep.equal(udpAddr.bytes) }) it('reconstruct with object', () => { - expect(multiaddr(udpAddr).bytes === udpAddr.bytes).to.equal(false) - expect(multiaddr(udpAddr).bytes).to.deep.equal(udpAddr.bytes) + expect(new Multiaddr(udpAddr).bytes === udpAddr.bytes).to.equal(false) + expect(new Multiaddr(udpAddr).bytes).to.deep.equal(udpAddr.bytes) }) it('reconstruct with JSON', () => { - expect(multiaddr(JSON.parse(JSON.stringify(udpAddr))).bytes === udpAddr.bytes).to.equal(false) - expect(multiaddr(JSON.parse(JSON.stringify(udpAddr))).bytes).to.deep.equal(udpAddr.bytes) + expect(new Multiaddr(JSON.parse(JSON.stringify(udpAddr))).bytes === udpAddr.bytes).to.equal(false) + expect(new Multiaddr(JSON.parse(JSON.stringify(udpAddr))).bytes).to.deep.equal(udpAddr.bytes) }) it('empty construct still works', () => { - expect(multiaddr('').toString()).to.equal('/') + expect(new Multiaddr('').toString()).to.equal('/') }) it('null/undefined construct still works', () => { - expect(multiaddr().toString()).to.equal('/') - expect(multiaddr(null).toString()).to.equal('/') - expect(multiaddr(undefined).toString()).to.equal('/') + expect(new Multiaddr().toString()).to.equal('/') + expect(new Multiaddr(null).toString()).to.equal('/') + expect(new Multiaddr(undefined).toString()).to.equal('/') }) it('throws on truthy non string or buffer', () => { const errRegex = /addr must be a string/ // @ts-ignore - expect(() => multiaddr({})).to.throw(errRegex) + expect(() => new Multiaddr({})).to.throw(errRegex) // @ts-ignore - expect(() => multiaddr([])).to.throw(errRegex) + expect(() => new Multiaddr([])).to.throw(errRegex) // @ts-ignore - expect(() => multiaddr(138)).to.throw(errRegex) + expect(() => new Multiaddr(138)).to.throw(errRegex) // @ts-ignore - expect(() => multiaddr(true)).to.throw(errRegex) + expect(() => new Multiaddr(true)).to.throw(errRegex) }) it('throws on falsy non string or buffer', () => { const errRegex = /addr must be a string/ // @ts-ignore - expect(() => multiaddr(NaN)).to.throw(errRegex) + expect(() => new Multiaddr(NaN)).to.throw(errRegex) // @ts-ignore - expect(() => multiaddr(false)).to.throw(errRegex) + expect(() => new Multiaddr(false)).to.throw(errRegex) // @ts-ignore - expect(() => multiaddr(0)).to.throw(errRegex) + expect(() => new Multiaddr(0)).to.throw(errRegex) }) }) describe('requiring varint', () => { + /** @type {Multiaddr} */ let uTPAddr it('create multiaddr', () => { - uTPAddr = multiaddr('/ip4/127.0.0.1/udp/1234/utp') - expect(uTPAddr instanceof multiaddr).to.equal(true) + uTPAddr = new Multiaddr('/ip4/127.0.0.1/udp/1234/utp') + expect(uTPAddr instanceof Multiaddr).to.equal(true) }) it('clone multiaddr', () => { - const uTPAddrClone = multiaddr(uTPAddr) + const uTPAddrClone = new Multiaddr(uTPAddr) expect(uTPAddrClone !== uTPAddr).to.equal(true) }) it('reconstruct with buffer', () => { - expect(multiaddr(uTPAddr.bytes).bytes === uTPAddr.bytes).to.equal(false) - expect(multiaddr(uTPAddr.bytes).bytes).to.deep.equal(uTPAddr.bytes) + expect(new Multiaddr(uTPAddr.bytes).bytes === uTPAddr.bytes).to.equal(false) + expect(new Multiaddr(uTPAddr.bytes).bytes).to.deep.equal(uTPAddr.bytes) }) it('reconstruct with string', () => { - expect(multiaddr(uTPAddr.toString()).bytes === uTPAddr.bytes).to.equal(false) - expect(multiaddr(uTPAddr.toString()).bytes).to.deep.equal(uTPAddr.bytes) + expect(new Multiaddr(uTPAddr.toString()).bytes === uTPAddr.bytes).to.equal(false) + expect(new Multiaddr(uTPAddr.toString()).bytes).to.deep.equal(uTPAddr.bytes) }) it('reconstruct with object', () => { - expect(multiaddr(uTPAddr).bytes === uTPAddr.bytes).to.equal(false) - expect(multiaddr(uTPAddr).bytes).to.deep.equal(uTPAddr.bytes) + expect(new Multiaddr(uTPAddr).bytes === uTPAddr.bytes).to.equal(false) + expect(new Multiaddr(uTPAddr).bytes).to.deep.equal(uTPAddr.bytes) }) it('empty construct still works', () => { - expect(multiaddr('').toString()).to.equal('/') + expect(new Multiaddr('').toString()).to.equal('/') }) }) @@ -109,33 +111,33 @@ describe('manipulation', () => { it('basic', () => { const udpAddrStr = '/ip4/127.0.0.1/udp/1234' const udpAddrBuf = uint8ArrayFromString('047f000001910204d2', 'base16') - const udpAddr = multiaddr(udpAddrStr) + const udpAddr = new Multiaddr(udpAddrStr) expect(udpAddr.toString()).to.equal(udpAddrStr) expect(udpAddr.bytes).to.deep.equal(udpAddrBuf) expect(udpAddr.protoCodes()).to.deep.equal([4, 273]) expect(udpAddr.protoNames()).to.deep.equal(['ip4', 'udp']) - expect(udpAddr.protos()).to.deep.equal([multiaddr.protocols.codes[4], multiaddr.protocols.codes[273]]) - expect(udpAddr.protos()[0] === multiaddr.protocols.codes[4]).to.equal(false) + expect(udpAddr.protos()).to.deep.equal([Multiaddr.protocols.codes[4], Multiaddr.protocols.codes[273]]) + expect(udpAddr.protos()[0] === Multiaddr.protocols.codes[4]).to.equal(false) const udpAddrbytes2 = udpAddr.encapsulate('/udp/5678') expect(udpAddrbytes2.toString()).to.equal('/ip4/127.0.0.1/udp/1234/udp/5678') expect(udpAddrbytes2.decapsulate('/udp').toString()).to.equal('/ip4/127.0.0.1/udp/1234') expect(udpAddrbytes2.decapsulate('/ip4').toString()).to.equal('/') expect(function () { udpAddr.decapsulate('/').toString() }).to.throw() - expect(multiaddr('/').encapsulate(udpAddr).toString()).to.equal(udpAddr.toString()) - expect(multiaddr('/').decapsulate('/').toString()).to.equal('/') + expect(new Multiaddr('/').encapsulate(udpAddr).toString()).to.equal(udpAddr.toString()) + expect(new Multiaddr('/').decapsulate('/').toString()).to.equal('/') }) it('ipfs', () => { - const ipfsAddr = multiaddr('/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') - const ip6Addr = multiaddr('/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095') - const tcpAddr = multiaddr('/tcp/8000') - const webAddr = multiaddr('/ws') + const ipfsAddr = new Multiaddr('/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') + const ip6Addr = new Multiaddr('/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095') + const tcpAddr = new Multiaddr('/tcp/8000') + const webAddr = new Multiaddr('/ws') expect( - multiaddr('/') + new Multiaddr('/') .encapsulate(ip6Addr) .encapsulate(tcpAddr) .encapsulate(webAddr) @@ -149,7 +151,7 @@ describe('manipulation', () => { ].join('')) expect( - multiaddr('/') + new Multiaddr('/') .encapsulate(ip6Addr) .encapsulate(tcpAddr) .encapsulate(webAddr) @@ -163,7 +165,7 @@ describe('manipulation', () => { ].join('')) expect( - multiaddr('/') + new Multiaddr('/') .encapsulate(ip6Addr) .encapsulate(tcpAddr) .encapsulate(ipfsAddr) @@ -181,63 +183,63 @@ describe('manipulation', () => { describe('variants', () => { it('ip4', () => { const str = '/ip4/127.0.0.1' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + tcp', () => { const str = '/ip4/127.0.0.1/tcp/5000' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/5000' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + udp', () => { const str = '/ip4/127.0.0.1/udp/5000' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + udp', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/5000' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + p2p', () => { const str = '/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + ipfs', () => { const str = '/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('ip6 + p2p', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) @@ -250,14 +252,14 @@ describe('variants', () => { it('ip4 + udp + utp', () => { const str = '/ip4/127.0.0.1/udp/5000/utp' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + udp + utp', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/5000/utp' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.protoNames()) expect(addr.toString()).to.equal(str) @@ -265,212 +267,212 @@ describe('variants', () => { it('ip4 + tcp + http', () => { const str = '/ip4/127.0.0.1/tcp/8000/http' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + tcp + unix', () => { const str = '/ip4/127.0.0.1/tcp/80/unix/a/b/c/d/e/f' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp + http', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/http' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp + unix', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/unix/a/b/c/d/e/f' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + tcp + https', () => { const str = '/ip4/127.0.0.1/tcp/8000/https' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp + https', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/https' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip4 + tcp + websockets', () => { const str = '/ip4/127.0.0.1/tcp/8000/ws' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp + websockets', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + tcp + websockets + ipfs', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('ip6 + tcp + websockets + p2p', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('ip6 + udp + quic + ipfs', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/4001/quic/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('ip6 + udp + quic + p2p', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/4001/quic/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('unix', () => { const str = '/unix/a/b/c/d/e' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p', () => { const str = '/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p', () => { const str = '/p2p/bafzbeidt255unskpefjmqb2rc27vjuyxopkxgaylxij6pw35hhys4vnyp4' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal('/p2p/QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t') }) it('ipfs', () => { const str = '/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('onion', () => { const str = '/onion/timaq4ygg2iegci7:1234' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('onion bad length', () => { const str = '/onion/timaq4ygg2iegci:80' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('onion bad port', () => { const str = '/onion/timaq4ygg2iegci7:-1' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('onion no port', () => { const str = '/onion/timaq4ygg2iegci7' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('onion3', () => { const str = '/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('onion3 bad length', () => { const str = '/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopyyd:1234' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('onion3 bad port', () => { const str = '/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:-1' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('onion3 no port', () => { const str = '/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd' - expect(() => multiaddr(str)).to.throw() + expect(() => new Multiaddr(str)).to.throw() }) it('p2p-circuit', () => { const str = '/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p-circuit p2p', () => { const str = '/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/p2p-circuit' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p-circuit ipfs', () => { const str = '/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/p2p-circuit' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('p2p-webrtc-star', () => { const str = '/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p-webrtc-star ipfs', () => { const str = '/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str.replace('/ipfs/', '/p2p/')) }) it('p2p-webrtc-direct', () => { const str = '/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('p2p-websocket-star', () => { const str = '/ip4/127.0.0.1/tcp/9090/ws/p2p-websocket-star' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) it('memory + p2p', () => { const str = '/memory/test/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' - const addr = multiaddr(str) + const addr = new Multiaddr(str) expect(addr).to.have.property('bytes') expect(addr.toString()).to.equal(str) }) @@ -479,9 +481,9 @@ describe('variants', () => { describe('helpers', () => { describe('.toOptions', () => { it('returns a well formed options object', () => { - expect(multiaddr('/ip4/0.0.0.0/tcp/1234').toOptions()) + expect(new Multiaddr('/ip4/0.0.0.0/tcp/1234').toOptions()) .to.eql({ - family: 'ipv4', + family: 4, host: '0.0.0.0', transport: 'tcp', port: 1234 @@ -491,14 +493,14 @@ describe('helpers', () => { describe('.inspect', () => { it('renders the buffer as hex', () => { - expect(multiaddr('/ip4/0.0.0.0/tcp/1234').inspect()) + expect(new Multiaddr('/ip4/0.0.0.0/tcp/1234').inspect()) .to.eql('') }) }) describe('.protos', () => { it('returns a list of all protocols in the address', () => { - expect(multiaddr('/ip4/0.0.0.0/utp').protos()) + expect(new Multiaddr('/ip4/0.0.0.0/utp').protos()) .to.eql([{ code: 4, name: 'ip4', @@ -516,7 +518,7 @@ describe('helpers', () => { it('works with ipfs', () => { expect( - multiaddr('/ip4/0.0.0.0/utp/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos() + new Multiaddr('/ip4/0.0.0.0/utp/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos() ).to.be.eql([{ code: 4, name: 'ip4', @@ -540,7 +542,7 @@ describe('helpers', () => { it('works with p2p', () => { expect( - multiaddr('/ip4/0.0.0.0/utp/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos() + new Multiaddr('/ip4/0.0.0.0/utp/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos() ).to.be.eql([{ code: 4, name: 'ip4', @@ -564,7 +566,7 @@ describe('helpers', () => { it('works with unix', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos() + new Multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos() ).to.be.eql([{ code: 4, name: 'ip4', @@ -588,7 +590,7 @@ describe('helpers', () => { it('works with memory', () => { expect( - multiaddr('/memory/test/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6').protos() + new Multiaddr('/memory/test/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6').protos() ).to.be.eql([{ code: 777, name: 'memory', @@ -607,7 +609,7 @@ describe('helpers', () => { describe('.tuples', () => { it('returns the tuples', () => { - expect(multiaddr('/ip4/0.0.0.0/utp').tuples()) + expect(new Multiaddr('/ip4/0.0.0.0/utp').tuples()) .to.eql([ [4, Uint8Array.from([0, 0, 0, 0])], [302] @@ -617,7 +619,7 @@ describe('helpers', () => { describe('.stringTuples', () => { it('returns the string partss', () => { - expect(multiaddr('/ip4/0.0.0.0/utp').stringTuples()) + expect(new Multiaddr('/ip4/0.0.0.0/utp').stringTuples()) .to.eql([ [4, '0.0.0.0'], [302] @@ -628,7 +630,7 @@ describe('helpers', () => { describe('.decapsulate', () => { it('throws on address with no matching subaddress', () => { expect( - () => multiaddr('/ip4/127.0.0.1').decapsulate('/ip4/198.168.0.0') + () => new Multiaddr('/ip4/127.0.0.1').decapsulate('/ip4/198.168.0.0') ).to.throw( /does not contain subaddress/ ) @@ -637,31 +639,31 @@ describe('helpers', () => { describe('.decapsulateCode', () => { it('removes the last occurrence of the code from the multiaddr', () => { - const relayTCP = multiaddr('/ip4/0.0.0.0/tcp/8080') + const relayTCP = new Multiaddr('/ip4/0.0.0.0/tcp/8080') const relay = relayTCP.encapsulate('/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6/p2p-circuit') - const target = multiaddr('/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') + const target = new Multiaddr('/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') const original = relay.encapsulate(target) expect(original.decapsulateCode(421)).to.eql(relay) expect(relay.decapsulateCode(421)).to.eql(relayTCP) }) it('ignores missing codes', () => { - const tcp = multiaddr('/ip4/0.0.0.0/tcp/8080') + const tcp = new Multiaddr('/ip4/0.0.0.0/tcp/8080') expect(tcp.decapsulateCode(421)).to.eql(tcp) }) }) describe('.equals', () => { it('returns true for equal addresses', () => { - const addr1 = multiaddr('/ip4/192.168.0.1') - const addr2 = multiaddr('/ip4/192.168.0.1') + const addr1 = new Multiaddr('/ip4/192.168.0.1') + const addr2 = new Multiaddr('/ip4/192.168.0.1') expect(addr1.equals(addr2)).to.equal(true) }) it('returns false for non equal addresses', () => { - const addr1 = multiaddr('/ip4/192.168.1.1') - const addr2 = multiaddr('/ip4/192.168.0.1') + const addr1 = new Multiaddr('/ip4/192.168.1.1') + const addr2 = new Multiaddr('/ip4/192.168.0.1') expect(addr1.equals(addr2)).to.equal(false) }) @@ -670,7 +672,7 @@ describe('helpers', () => { describe('.nodeAddress', () => { it('throws on an invalid node address', () => { expect( - () => multiaddr('/ip4/192.168.0.1/utp').nodeAddress() + () => new Multiaddr('/ip4/192.168.0.1/utp').nodeAddress() ).to.throw( /multiaddr must have a valid format/ ) @@ -678,7 +680,7 @@ describe('helpers', () => { it('returns a node friendly address', () => { expect( - multiaddr('/ip4/192.168.0.1/tcp/1234').nodeAddress() + new Multiaddr('/ip4/192.168.0.1/tcp/1234').nodeAddress() ).to.be.eql({ address: '192.168.0.1', family: 4, @@ -688,7 +690,7 @@ describe('helpers', () => { it('returns a node friendly address with dns', () => { expect( - multiaddr('/dns4/wss0.bootstrap.libp2p.io/tcp/443').nodeAddress() + new Multiaddr('/dns4/wss0.bootstrap.libp2p.io/tcp/443').nodeAddress() ).to.be.eql({ address: 'wss0.bootstrap.libp2p.io', family: 4, @@ -698,7 +700,7 @@ describe('helpers', () => { it('throws on an invalid format address when the addr is not prefixed with a /', () => { expect( - () => multiaddr('ip4/192.168.0.1/udp').nodeAddress() + () => new Multiaddr('ip4/192.168.0.1/udp').nodeAddress() ).to.throw( /must start with a/ ) @@ -706,7 +708,7 @@ describe('helpers', () => { it('throws on an invalid protocol name when the addr has an invalid one', () => { expect( - () => multiaddr('/ip5/127.0.0.1/udp/5000') + () => new Multiaddr('/ip5/127.0.0.1/udp/5000') ).to.throw( /no protocol with name/ ) @@ -714,7 +716,7 @@ describe('helpers', () => { it('throws on an invalid protocol name when the transport protocol is not valid', () => { expect( - () => multiaddr('/ip4/127.0.0.1/utp/5000') + () => new Multiaddr('/ip4/127.0.0.1/utp/5000') ).to.throw( /no protocol with name/ ) @@ -725,7 +727,7 @@ describe('helpers', () => { it('throws on missing address object', () => { expect( // @ts-ignore - () => multiaddr.fromNodeAddress() + () => Multiaddr.fromNodeAddress() ).to.throw( /requires node address/ ) @@ -734,7 +736,7 @@ describe('helpers', () => { it('throws on missing transport', () => { expect( // @ts-ignore - () => multiaddr.fromNodeAddress({ address: '0.0.0.0' }) + () => Multiaddr.fromNodeAddress({ address: '0.0.0.0' }) ).to.throw( /requires transport protocol/ ) @@ -742,10 +744,10 @@ describe('helpers', () => { it('parses a node address', () => { expect( - multiaddr.fromNodeAddress({ + Multiaddr.fromNodeAddress({ address: '192.168.0.1', - family: 'IPv4', - port: '1234' + family: 4, + port: 1234 }, 'tcp').toString() ).to.be.eql( '/ip4/192.168.0.1/tcp/1234' @@ -756,6 +758,7 @@ describe('helpers', () => { describe('.isThinWaistAddress', () => { const families = ['ip4', 'ip6'] const transports = ['tcp', 'udp'] + /** @type {Record} */ const addresses = { ip4: '192.168.0.1', ip6: '2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095' @@ -764,9 +767,7 @@ describe('helpers', () => { transports.forEach((transport) => { it(`returns true for /${family}-${transport}`, () => { expect( - multiaddr( - `/${family}/${addresses[family]}/${transport}/1234` - ).isThinWaistAddress() + new Multiaddr(`/${family}/${addresses[family]}/${transport}/1234`).isThinWaistAddress() ).to.equal(true) }) }) @@ -774,17 +775,17 @@ describe('helpers', () => { it('returns false for two protocols not using {IPv4, IPv6}/{TCP, UDP}', () => { expect( - multiaddr('/ip4/192.168.0.1/utp').isThinWaistAddress() + new Multiaddr('/ip4/192.168.0.1/utp').isThinWaistAddress() ).to.equal(false) expect( - multiaddr('/sctp/192.168.0.1/tcp/1234').isThinWaistAddress() + new Multiaddr('/sctp/192.168.0.1/tcp/1234').isThinWaistAddress() ).to.eql( false ) expect( - multiaddr('/http/utp').isThinWaistAddress() + new Multiaddr('/http/utp').isThinWaistAddress() ).to.eql( false ) @@ -792,7 +793,7 @@ describe('helpers', () => { it('returns false for more than two protocols', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/1234/utp').isThinWaistAddress() + new Multiaddr('/ip4/0.0.0.0/tcp/1234/utp').isThinWaistAddress() ).to.equal( false ) @@ -802,27 +803,27 @@ describe('helpers', () => { describe('.getPeerId should parse id from multiaddr', () => { it('extracts the peer Id from a multiaddr, p2p', () => { expect( - multiaddr('/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() + new Multiaddr('/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() ).to.equal('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') }) it('extracts the correct peer Id from a circuit multiaddr', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/8080/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() + new Multiaddr('/ip4/0.0.0.0/tcp/8080/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() ).to.equal('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') }) it('extracts the peer Id from a multiaddr, ipfs', () => { expect( - multiaddr('/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() + new Multiaddr('/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPeerId() ).to.equal('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC') }) it('extracts the peer Id from a multiaddr, p2p and CIDv1 Base32', () => { expect( - multiaddr('/p2p-circuit/p2p/bafzbeigweq4zr4x4ky2dvv7nanbkw6egutvrrvzw6g3h2rftp7gidyhtt4').getPeerId() + new Multiaddr('/p2p-circuit/p2p/bafzbeigweq4zr4x4ky2dvv7nanbkw6egutvrrvzw6g3h2rftp7gidyhtt4').getPeerId() ).to.equal('QmckZzdVd72h9QUFuJJpQqhsZqGLwjhh81qSvZ9BhB2FQi') }) it('extracts the peer Id from a multiaddr, p2p and CIDv1 Base32, where Id contains non b58 chars', () => { expect( - multiaddr('/p2p-circuit/p2p/bafzbeidt255unskpefjmqb2rc27vjuyxopkxgaylxij6pw35hhys4vnyp4').getPeerId() + new Multiaddr('/p2p-circuit/p2p/bafzbeidt255unskpefjmqb2rc27vjuyxopkxgaylxij6pw35hhys4vnyp4').getPeerId() ).to.equal('QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t') }) }) @@ -830,7 +831,7 @@ describe('helpers', () => { describe('.getPeerId should return null on missing peer id in multiaddr', () => { it('parses extracts the peer Id from a multiaddr', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/1234/utp').getPeerId() + new Multiaddr('/ip4/0.0.0.0/tcp/1234/utp').getPeerId() ).to.be.null() }) }) @@ -838,30 +839,30 @@ describe('helpers', () => { describe('.getPath', () => { it('should return a path for unix', () => { expect( - multiaddr('/unix/tmp/p2p.sock').getPath() + new Multiaddr('/unix/tmp/p2p.sock').getPath() ).to.eql('/tmp/p2p.sock') }) it('should return a path for unix when other protos exist', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/1234/unix/tmp/p2p.sock').getPath() + new Multiaddr('/ip4/0.0.0.0/tcp/1234/unix/tmp/p2p.sock').getPath() ).to.eql('/tmp/p2p.sock') }) it('should not return a path when no path proto exists', () => { expect( - multiaddr('/ip4/0.0.0.0/tcp/1234/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPath() + new Multiaddr('/ip4/0.0.0.0/tcp/1234/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPath() ).to.eql(null) }) }) describe('multiaddr.isMultiaddr', () => { it('handles different inputs', () => { - expect(multiaddr.isMultiaddr(multiaddr('/'))).to.be.eql(true) - expect(multiaddr.isMultiaddr('/')).to.be.eql(false) - expect(multiaddr.isMultiaddr(123)).to.be.eql(false) + expect(Multiaddr.isMultiaddr(new Multiaddr('/'))).to.be.eql(true) + expect(Multiaddr.isMultiaddr('/')).to.be.eql(false) + expect(Multiaddr.isMultiaddr(123)).to.be.eql(false) - expect(multiaddr.isMultiaddr(uint8ArrayFromString('/hello'))).to.be.eql(false) + expect(Multiaddr.isMultiaddr(uint8ArrayFromString('/hello'))).to.be.eql(false) }) }) @@ -869,48 +870,32 @@ describe('helpers', () => { describe('.isName', () => { it('valid name dns', () => { const str = '/dns/ipfs.io' - const addr = multiaddr(str) - expect(multiaddr.isName(addr)).to.equal(true) + const addr = new Multiaddr(str) + expect(Multiaddr.isName(addr)).to.equal(true) }) it('valid name dnsaddr', () => { const str = '/dnsaddr/ipfs.io' - const addr = multiaddr(str) - expect(multiaddr.isName(addr)).to.equal(true) + const addr = new Multiaddr(str) + expect(Multiaddr.isName(addr)).to.equal(true) }) it('valid name dns4', () => { const str = '/dns4/ipfs.io' - const addr = multiaddr(str) - expect(multiaddr.isName(addr)).to.equal(true) + const addr = new Multiaddr(str) + expect(Multiaddr.isName(addr)).to.equal(true) }) it('valid name dns6', () => { const str = '/dns6/ipfs.io' - const addr = multiaddr(str) - expect(multiaddr.isName(addr)).to.equal(true) + const addr = new Multiaddr(str) + expect(Multiaddr.isName(addr)).to.equal(true) }) it('invalid name', () => { const str = '/ip4/127.0.0.1' - const addr = multiaddr(str) - expect(multiaddr.isName(addr)).to.equal(false) - }) - }) - - describe('.resolve', () => { - it.skip('valid and active DNS name', (done) => {}) - it.skip('valid but inactive DNS name', () => {}) - it('invalid DNS name', () => { - const str = '/ip4/127.0.0.1' - const addr = multiaddr(str) - - return multiaddr.resolve(addr) - // @ts-ignore - .then(expect.fail, (err) => { - expect(err).to.exist() - expect(err.message).to.eql('not a valid name') - }) + const addr = new Multiaddr(str) + expect(Multiaddr.isName(addr)).to.equal(false) }) }) }) diff --git a/test/protocols.spec.js b/test/protocols.spec.js index b5b53016..a6e12a01 100644 --- a/test/protocols.spec.js +++ b/test/protocols.spec.js @@ -24,6 +24,7 @@ describe('protocols', () => { it('else', () => { expect( + // @ts-expect-error () => protocols({ hi: 34 }) ).to.throw( /invalid protocol id type/ diff --git a/test/resolvers.spec.js b/test/resolvers.spec.js index 747c80de..9d5959f5 100644 --- a/test/resolvers.spec.js +++ b/test/resolvers.spec.js @@ -4,9 +4,9 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') -const multiaddr = require('../src') +const { Multiaddr } = require('../src') const resolvers = require('../src/resolvers') -const { Resolver } = require('../src/resolvers/dns') +const Resolver = require('../src/resolvers/dns') const dnsaddrStub1 = [ ['dnsaddr=/dnsaddr/ams-1.bootstrap.libp2p.io/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd'], @@ -28,7 +28,7 @@ const dnsaddrStub2 = [ describe('multiaddr resolve', () => { it('should throw if no resolver is available', async () => { - const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io') + const ma = new Multiaddr('/dnsaddr/bootstrap.libp2p.io') // Resolve await expect(ma.resolve()).to.eventually.be.rejected() @@ -38,7 +38,7 @@ describe('multiaddr resolve', () => { describe('dnsaddr', () => { before(() => { // Set resolvers - multiaddr.resolvers.set('dnsaddr', resolvers.dnsaddrResolver) + Multiaddr.resolvers.set('dnsaddr', resolvers.dnsaddrResolver) }) afterEach(() => { @@ -46,7 +46,7 @@ describe('multiaddr resolve', () => { }) it('can resolve dnsaddr without no peerId', async () => { - const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io') + const ma = new Multiaddr('/dnsaddr/bootstrap.libp2p.io') const stub = sinon.stub(Resolver.prototype, 'resolveTxt') stub.onCall(0).returns(Promise.resolve(dnsaddrStub1)) @@ -58,12 +58,12 @@ describe('multiaddr resolve', () => { resolvedMas.forEach((ma, index) => { const stubAddr = dnsaddrStub1[index][0].split('=')[1] - expect(ma.equals(multiaddr(stubAddr))).to.equal(true) + expect(ma.equals(new Multiaddr(stubAddr))).to.equal(true) }) }) it('can resolve dnsaddr with peerId', async () => { - const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') + const ma = new Multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') const stub = sinon.stub(Resolver.prototype, 'resolveTxt') stub.onCall(0).returns(Promise.resolve(dnsaddrStub1)) @@ -73,11 +73,11 @@ describe('multiaddr resolve', () => { const resolvedMas = await ma.resolve() expect(resolvedMas).to.have.length(1) - expect(resolvedMas[0].equals(multiaddr('/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb'))).to.eql(true) + expect(resolvedMas[0].equals(new Multiaddr('/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb'))).to.eql(true) }) it('can resolve dnsaddr with peerId two levels', async () => { - const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') + const ma = new Multiaddr('/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb') const stub = sinon.stub(Resolver.prototype, 'resolveTxt') stub.onCall(0).returns(Promise.resolve(dnsaddrStub1)) @@ -93,10 +93,11 @@ describe('multiaddr resolve', () => { const resolvedMas = resolvedSecondMas.flat() expect(resolvedMas).to.have.length(dnsaddrStub2.length) - resolvedMas.forEach((ma, index) => { + + resolvedMas.forEach((/** @type {Multiaddr} */ma, /** @type {number} */ index) => { const stubAddr = dnsaddrStub2[index][0].split('=')[1] - expect(ma.equals(multiaddr(stubAddr))).to.equal(true) + expect(ma.equals(new Multiaddr(stubAddr))).to.equal(true) }) }) }) diff --git a/test/types.spec.ts b/test/types.spec.ts deleted file mode 100644 index ba9129c9..00000000 --- a/test/types.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import Multiaddr from '../src' - -const testStr = '/ip4/127.0.0.1' - -export const maFromFunctionConstructor: Multiaddr = Multiaddr(testStr) - -export const maFromClassConstructor: Multiaddr = new Multiaddr(testStr) - -export const maFromMa: Multiaddr = Multiaddr(new Multiaddr(testStr)) - -export const maFromConstructorFunction: Multiaddr = Multiaddr.fromNodeAddress( - { - family: 'IPv4', - address: '127.0.0.1', - port: '12345' - }, - 'udp' -) - -export function doSthWithMa (ma: Multiaddr): void { - ma.toOptions() -} diff --git a/tsconfig.json b/tsconfig.json index 60e2c5b1..83d980a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,10 @@ { + "extends": "aegir/src/config/tsconfig.aegir.json", "compilerOptions": { - "module": "commonjs", - "lib": ["es6"], - "target": "ES5", - "noImplicitAny": false, - "noImplicitThis": true, - "strictFunctionTypes": true, - "strictNullChecks": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "allowJs": true, - "checkJs": true, - "noEmit": true, - "forceConsistentCasingInFileNames": true + "outDir": "dist" }, - "include": ["src/index.d.ts", "test/**/*.spec.js", "test/**/*.spec.ts"] -} + "include": [ + "test", + "src" + ] +} \ No newline at end of file