diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..25fc395 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,74 @@ +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 nyc --reporter=lcov aegir test -t node -- --bail + - uses: codecov/codecov-action@v1 + test-chrome: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx aegir test -t browser -t webworker --bail + test-firefox: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless + 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 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bd3dcaf..0000000 --- a/.travis.yml +++ /dev/null @@ -1,52 +0,0 @@ -language: node_js -cache: npm -stages: - - check - - test - - cov - -node_js: - - '10' - - '12' - -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 - filter_secrets: false - cache: false - - - stage: check - script: - - npx aegir commitlint --travis - - npx aegir dep-check - - npm run lint - - - 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 - - - stage: test - name: electron - services: - - xvfb - script: - - npm run test:electron - - npm run test:electron-renderer - -notifications: - email: false diff --git a/package.json b/package.json index be3f1d7..1d50cfa 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,21 @@ "description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem", "leadMaintainer": "Vasco Santos ", "main": "src/index.js", + "types": "dist/src/index.d.ts", + "typesVersions": { + "*": { + "src/*": [ + "dist/src/*", + "dist/src/*/index" + ] + } + }, + "files": [ + "src", + "dist" + ], "scripts": { + "prepare": "aegir build --no-bundle", "test": "aegir test", "test:browser": "aegir test -t browser", "test:node": "aegir test -t node", @@ -29,18 +43,21 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-utils#readme", "devDependencies": { - "aegir": "^27.0.0", + "@types/debug": "^4.1.5", + "aegir": "^32.1.0", "it-pair": "^1.0.0", "it-pipe": "^1.1.0", - "streaming-iterables": "^5.0.3" + "libp2p-interfaces": "^0.9.0", + "streaming-iterables": "^5.0.3", + "util": "^0.12.3" }, "dependencies": { "abortable-iterator": "^3.0.0", - "debug": "^4.2.0", - "err-code": "^2.0.3", - "ip-address": "^6.1.0", + "debug": "^4.3.0", + "err-code": "^3.0.1", + "ip-address": "^7.1.0", "is-loopback-addr": "^1.0.0", - "multiaddr": "^8.0.0", + "multiaddr": "^8.1.2", "private-ip": "^2.1.1" }, "contributors": [ diff --git a/src/address-sort.js b/src/address-sort.js index 0a49143..9e9468e 100644 --- a/src/address-sort.js +++ b/src/address-sort.js @@ -2,6 +2,16 @@ const isPrivate = require('./multiaddr/is-private') +/** + * @typedef {import('multiaddr')} Multiaddr + */ + +/** + * @typedef {Object} Address + * @property {Multiaddr} multiaddr peer multiaddr. + * @property {boolean} isCertified obtained from a signed peer record. + */ + /** * Compare function for array.sort(). * This sort aims to move the private adresses to the end of the array. diff --git a/src/ip-port-to-multiaddr.js b/src/ip-port-to-multiaddr.js index f928b60..dfd27f0 100644 --- a/src/ip-port-to-multiaddr.js +++ b/src/ip-port-to-multiaddr.js @@ -1,5 +1,9 @@ 'use strict' +const debug = require('debug') +const log = Object.assign(debug('libp2p:ip-port-to-multiaddr'), { + error: debug('libp2p:ip-port-to-multiaddr:err') +}) const multiaddr = require('multiaddr') const errCode = require('err-code') const { Address4, Address6 } = require('ip-address') @@ -21,25 +25,31 @@ function ipPortToMultiaddr (ip, port) { throw errCode(new Error(`invalid ip provided: ${ip}`), errors.ERR_INVALID_IP_PARAMETER) } - port = parseInt(port) + if (typeof port === 'string') { + port = parseInt(port) + } if (isNaN(port)) { throw errCode(new Error(`invalid port provided: ${port}`), errors.ERR_INVALID_PORT_PARAMETER) } - if (new Address4(ip).isValid()) { + try { + // Test valid IPv4 + new Address4(ip) // eslint-disable-line no-new return multiaddr(`/ip4/${ip}/tcp/${port}`) - } + } catch {} - const ip6 = new Address6(ip) - - if (ip6.isValid()) { + try { + // Test valid IPv6 + const ip6 = new Address6(ip) return ip6.is4() ? multiaddr(`/ip4/${ip6.to4().correctForm()}/tcp/${port}`) : multiaddr(`/ip6/${ip}/tcp/${port}`) + } catch (err) { + const errMsg = `invalid ip:port for creating a multiaddr: ${ip}:${port}` + log.error(errMsg) + throw errCode(new Error(errMsg), errors.ERR_INVALID_IP) } - - throw errCode(new Error(`invalid ip:port for creating a multiaddr: ${ip}:${port}`), errors.ERR_INVALID_IP) } module.exports = ipPortToMultiaddr diff --git a/src/multiaddr/is-loopback.js b/src/multiaddr/is-loopback.js index 1c11c1c..b30b709 100644 --- a/src/multiaddr/is-loopback.js +++ b/src/multiaddr/is-loopback.js @@ -1,7 +1,12 @@ 'use strict' +// @ts-ignore is-loopback-addr does not publish types const isLoopbackAddr = require('is-loopback-addr') +/** + * @typedef {import('multiaddr')} Multiaddr + */ + /** * Check if a given multiaddr is a loopback address. * diff --git a/src/multiaddr/is-private.js b/src/multiaddr/is-private.js index 69192b7..67e293b 100644 --- a/src/multiaddr/is-private.js +++ b/src/multiaddr/is-private.js @@ -1,7 +1,12 @@ 'use strict' +// @ts-ignore private-ip does not publish types const isIpPrivate = require('private-ip') +/** + * @typedef {import('multiaddr')} Multiaddr + */ + /** * Check if a given multiaddr has a private address. * diff --git a/src/stream-to-ma-conn.js b/src/stream-to-ma-conn.js index 91a3f4b..335d461 100644 --- a/src/stream-to-ma-conn.js +++ b/src/stream-to-ma-conn.js @@ -1,24 +1,40 @@ 'use strict' -const abortable = require('abortable-iterator') -const log = require('debug')('libp2p:stream:converter') +const { source: abortable } = require('abortable-iterator') +const debug = require('debug') +const log = debug('libp2p:stream:converter') + +/** + * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream + * + * @typedef {Object} Timeline + * @property {number} open - connection opening timestamp. + * @property {number} [upgraded] - connection upgraded timestamp. + * @property {number} [close] + */ /** * Convert a duplex iterable into a MultiaddrConnection. * https://github.com/libp2p/interface-transport#multiaddrconnection * * @param {object} streamProperties - * @param {DuplexStream} streamProperties.stream + * @param {MuxedStream} streamProperties.stream * @param {Multiaddr} streamProperties.remoteAddr * @param {Multiaddr} streamProperties.localAddr * @param {object} [options] * @param {AbortSignal} [options.signal] + * @returns {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} */ function streamToMaConnection ({ stream, remoteAddr, localAddr }, options = {}) { const { sink, source } = stream const maConn = { + /** + * @param {Uint8Array} source + */ async sink (source) { if (options.signal) { + // @ts-ignore ts infers source template will be a number source = abortable(source, options.signal) } @@ -35,16 +51,15 @@ function streamToMaConnection ({ stream, remoteAddr, localAddr }, options = {}) } close() }, - source: options.signal ? abortable(source, options.signal) : source, conn: stream, localAddr, remoteAddr, - timeline: { open: Date.now() }, - + /** @type {Timeline} */ + timeline: { open: Date.now(), close: undefined }, close () { - sink([]) - close() + sink(new Uint8Array(0)) + return close() } } @@ -52,6 +67,7 @@ function streamToMaConnection ({ stream, remoteAddr, localAddr }, options = {}) if (!maConn.timeline.close) { maConn.timeline.close = Date.now() } + return Promise.resolve() } return maConn diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5fe8ea4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +}