diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8641a8a5..ade1dcbc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - run: yarn - run: yarn lint - # - uses: gozala/typescript-error-reporter-action@v1.0.4 + - uses: gozala/typescript-error-reporter-action@v1.0.8 - run: yarn build - run: yarn aegir dep-check - uses: ipfs/aegir/actions/bundle-size@master @@ -64,4 +64,4 @@ jobs: steps: - uses: actions/checkout@v2 - run: yarn - - run: cd examples && yarn && npm run test -- auto-relay \ No newline at end of file + - run: cd examples && yarn && npm run test -- auto-relay diff --git a/src/circuit/circuit/hop.js b/src/circuit/circuit/hop.js index 59de474f..3c1730ce 100644 --- a/src/circuit/circuit/hop.js +++ b/src/circuit/circuit/hop.js @@ -18,15 +18,18 @@ const { stop } = require('./stop') const multicodec = require('./../multicodec') /** + * @typedef {import('../../types').CircuitRequest} Request * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection + * @typedef {import('./stream-handler')} StreamHandlerT + * @typedef {import('../transport')} Transport */ /** * @typedef {Object} HopRequest * @property {Connection} connection - * @property {any} request - * @property {any} streamHandler - * @property {import('../transport')} circuit + * @property {Request} request + * @property {StreamHandlerT} streamHandler + * @property {Transport} circuit */ /** @@ -110,7 +113,7 @@ async function handleHop ({ * * @param {object} options * @param {Connection} options.connection - Connection to the relay - * @param {CircuitPB} options.request + * @param {Request} options.request * @returns {Promise} */ async function hop ({ @@ -168,8 +171,8 @@ async function canHop ({ * * @param {Object} options * @param {Connection} options.connection - * @param {StreamHandler} options.streamHandler - * @param {import('../transport')} options.circuit + * @param {StreamHandlerT} options.streamHandler + * @param {Transport} options.circuit * @private */ function handleCanHop ({ diff --git a/src/circuit/circuit/stop.js b/src/circuit/circuit/stop.js index 16192ad5..2e41e48c 100644 --- a/src/circuit/circuit/stop.js +++ b/src/circuit/circuit/stop.js @@ -13,16 +13,18 @@ const { validateAddrs } = require('./utils') /** * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream + * @typedef {import('../../types').CircuitRequest} Request + * @typedef {import('./stream-handler')} StreamHandlerT */ /** * Handles incoming STOP requests * * @private - * @param {object} options + * @param {Object} options * @param {Connection} options.connection - * @param {CircuitPB} options.request - The CircuitRelay protobuf request (unencoded) - * @param {StreamHandler} options.streamHandler + * @param {Request} options.request - The CircuitRelay protobuf request (unencoded) + * @param {StreamHandlerT} options.streamHandler * @returns {Promise|void} Resolves a duplex iterable */ module.exports.handleStop = function handleStop ({ @@ -50,9 +52,9 @@ module.exports.handleStop = function handleStop ({ * Creates a STOP request * * @private - * @param {object} options + * @param {Object} options * @param {Connection} options.connection - * @param {CircuitPB} options.request - The CircuitRelay protobuf request (unencoded) + * @param {Request} options.request - The CircuitRelay protobuf request (unencoded) * @returns {Promise} Resolves a duplex iterable */ module.exports.stop = async function stop ({ diff --git a/src/circuit/circuit/stream-handler.js b/src/circuit/circuit/stream-handler.js index b63dcbff..5be2c6ed 100644 --- a/src/circuit/circuit/stream-handler.js +++ b/src/circuit/circuit/stream-handler.js @@ -9,13 +9,20 @@ const lp = require('it-length-prefixed') const handshake = require('it-handshake') const { CircuitRelay: CircuitPB } = require('../protocol') +/** + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream + */ + +/** + * @template T + */ class StreamHandler { /** * Create a stream handler for connection * * @class * @param {object} options - * @param {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} options.stream - A duplex iterable + * @param {MuxedStream} options.stream - A duplex iterable * @param {number} [options.maxLength = 4096] - max bytes length of message */ constructor ({ stream, maxLength = 4096 }) { @@ -29,7 +36,7 @@ class StreamHandler { * Read and decode message * * @async - * @returns {Promise} + * @returns {Promise} */ async read () { const msg = await this.decoder.next() @@ -48,6 +55,7 @@ class StreamHandler { * Encode and write array of buffers * * @param {CircuitPB} msg - An unencoded CircuitRelay protobuf message + * @returns {void} */ write (msg) { log('write message type %s', msg.type) diff --git a/src/circuit/transport.js b/src/circuit/transport.js index 4eea0610..650bb97d 100644 --- a/src/circuit/transport.js +++ b/src/circuit/transport.js @@ -8,7 +8,6 @@ const log = Object.assign(debug('libp2p:circuit'), { const mafmt = require('mafmt') const multiaddr = require('multiaddr') const PeerId = require('peer-id') -const withIs = require('class-is') const { CircuitRelay: CircuitPB } = require('./protocol') const toConnection = require('libp2p-utils/src/stream-to-ma-conn') @@ -19,9 +18,12 @@ const { handleCanHop, handleHop, hop } = require('./circuit/hop') const { handleStop } = require('./circuit/stop') const StreamHandler = require('./circuit/stream-handler') +const transportSymbol = Symbol.for('@libp2p/js-libp2p-circuit/circuit') + /** * @typedef {import('multiaddr')} Multiaddr * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream */ class Circuit { @@ -45,6 +47,11 @@ class Circuit { this._registrar.handle(multicodec, this._onProtocol.bind(this)) } + /** + * @param {Object} props + * @param {Connection} props.connection + * @param {MuxedStream} props.stream + */ async _onProtocol ({ connection, stream }) { const streamHandler = new StreamHandler({ stream }) const request = await streamHandler.read() @@ -190,9 +197,20 @@ class Circuit { return mafmt.Circuit.matches(ma) }) } + + get [Symbol.toStringTag] () { + return 'Circuit' + } + + /** + * Checks if the given value is a Transport instance. + * + * @param {any} other + * @returns {other is Transport} + */ + static isTransport (other) { + return Boolean(other && other[transportSymbol]) + } } -/** - * @type {Circuit} - */ -module.exports = withIs(Circuit, { className: 'Circuit', symbolName: '@libp2p/js-libp2p-circuit/circuit' }) +module.exports = Circuit diff --git a/src/connection-manager/index.js b/src/connection-manager/index.js index 4ebbd837..4add4840 100644 --- a/src/connection-manager/index.js +++ b/src/connection-manager/index.js @@ -52,7 +52,6 @@ const defaultOptions = { */ /** - * @extends EventEmitter * * @fires ConnectionManager#peer:connect Emitted when a new peer is connected. * @fires ConnectionManager#peer:disconnect Emitted when a peer is disconnected. diff --git a/src/connection-manager/visibility-change-emitter.js b/src/connection-manager/visibility-change-emitter.js index b69ba78f..ebe5e7d0 100644 --- a/src/connection-manager/visibility-change-emitter.js +++ b/src/connection-manager/visibility-change-emitter.js @@ -13,8 +13,6 @@ const debug = require('debug')('latency-monitor:VisibilityChangeEmitter') /** * Listen to page visibility change events (i.e. when the page is focused / blurred) by an event emitter. * - * @extends {EventEmitter} - * * Warning: This does not work on all browsers, but should work on all modern browsers * * @example diff --git a/src/content-routing.js b/src/content-routing.js index d2989d81..cba4a38b 100644 --- a/src/content-routing.js +++ b/src/content-routing.js @@ -70,14 +70,14 @@ class ContentRouting { * a provider of the given key. * * @param {CID} key - The CID key of the content to find - * @returns {Promise} + * @returns {Promise} */ - async provide (key) { // eslint-disable-line require-await + async provide (key) { if (!this.routers.length) { throw errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE') } - return Promise.all(this.routers.map((router) => router.provide(key))) + await Promise.all(this.routers.map((router) => router.provide(key))) } /** @@ -89,7 +89,7 @@ class ContentRouting { * @param {number} [options.minPeers] - minimum number of peers required to successfully put * @returns {Promise} */ - async put (key, value, options) { // eslint-disable-line require-await + put (key, value, options) { if (!this.libp2p.isStarted() || !this.dht.isStarted) { throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) } @@ -106,7 +106,7 @@ class ContentRouting { * @param {number} [options.timeout] - optional timeout (default: 60000) * @returns {Promise} */ - async get (key, options) { // eslint-disable-line require-await + get (key, options) { if (!this.libp2p.isStarted() || !this.dht.isStarted) { throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) } diff --git a/src/dialer/index.js b/src/dialer/index.js index c334d449..09ae2627 100644 --- a/src/dialer/index.js +++ b/src/dialer/index.js @@ -34,12 +34,14 @@ const { * @property {PeerStore} peerStore * @property {TransportManager} transportManager * + * @typedef {(addr:Multiaddr) => Promise} Resolver + * * @typedef {Object} DialerOptions - * @param {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial. + * @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial. * @property {number} [concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials. * @property {number} [perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer. * @property {number} [timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take. - * @property {Object} [resolvers = {}] - multiaddr resolvers to use when dialing + * @property {Record} [resolvers = {}] - multiaddr resolvers to use when dialing * * @typedef DialTarget * @property {string} id @@ -240,13 +242,13 @@ class Dialer { return this._resolve(nm) })) - return recursiveMultiaddrs.flat() - .reduce((/** @type {Multiaddr[]} */ array, /** @type {Multiaddr} */ newM) => { - if (!array.find(m => m.equals(newM))) { - array.push(newM) - } - return array - }, []) // Unique addresses + const addrs = recursiveMultiaddrs.flat() + return addrs.reduce((array, newM) => { + if (!array.find(m => m.equals(newM))) { + array.push(newM) + } + return array + }, /** @type {Multiaddr[]} */([])) } /** diff --git a/src/index.js b/src/index.js index f7daaa4c..7e620403 100644 --- a/src/index.js +++ b/src/index.js @@ -37,6 +37,9 @@ const IDENTIFY_PROTOCOLS = IdentifyService.multicodecs * @typedef {import('multiaddr')} Multiaddr * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream + * @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxerFactory} MuxerFactory + * @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto * @typedef {import('libp2p-interfaces/src/pubsub')} Pubsub */ @@ -54,14 +57,19 @@ const IDENTIFY_PROTOCOLS = IdentifyService.multicodecs * @property {import('./circuit').AutoRelayOptions} autoRelay * * @typedef {Object} Libp2pConfig - * @property {any} [dht] dht module options + * @property {Object} [dht] dht module options * @property {PeerDiscoveryOptions} [peerDiscovery] * @property {Pubsub} [pubsub] pubsub module options * @property {RelayOptions} [relay] - * @property {Object} [transport] transport options indexed by transport key + * @property {Record} [transport] transport options indexed by transport key + * + * @typedef {Object} Libp2pModules + * @property {TransportFactory[]} transport + * @property {MuxerFactory[]} streamMuxer + * @property {Crypto[]} connEncryption * * @typedef {Object} Libp2pOptions - * @property {Object[]} modules libp2p modules to use + * @property {Libp2pModules} modules libp2p modules to use * @property {import('./address-manager').AddressManagerOptions} [addresses] * @property {import('./connection-manager').ConnectionManagerOptions} [connectionManager] * @property {import('./dialer').DialerOptions} [dialer] @@ -133,7 +141,6 @@ class Libp2p extends EventEmitter { const keychainOpts = Keychain.generateOptions() - /** @type {Keychain} */ this.keychain = new Keychain(this._options.keychain.datastore, { passPhrase: this._options.keychain.pass, ...keychainOpts, @@ -342,6 +349,10 @@ class Libp2p extends EventEmitter { * @returns {Promise} */ async loadKeychain () { + if (!this.keychain) { + return + } + try { await this.keychain.findKeyByName('self') } catch (err) { @@ -373,7 +384,7 @@ class Libp2p extends EventEmitter { * @returns {Promise} */ dial (peer, options) { - return this.dialProtocol(peer, undefined, options) + return this.dialProtocol(peer, [], options) } /** @@ -383,7 +394,7 @@ class Libp2p extends EventEmitter { * * @async * @param {PeerId|Multiaddr|string} peer - The peer to dial - * @param {undefined|string[]|string} protocols + * @param {null|string[]|string} protocols * @param {object} [options] * @param {AbortSignal} [options.signal] * @returns {Promise} @@ -399,7 +410,7 @@ class Libp2p extends EventEmitter { } // If a protocol was provided, create a new stream - if (protocols) { + if (protocols && protocols.length) { return connection.newStream(protocols) } diff --git a/src/keychain/cms.js b/src/keychain/cms.js index c808ed69..3ba99cfb 100644 --- a/src/keychain/cms.js +++ b/src/keychain/cms.js @@ -22,7 +22,7 @@ class CMS { /** * Creates a new instance with a keychain * - * @param {Keychain} keychain - the available keys + * @param {import('./index')} keychain - the available keys */ constructor (keychain) { if (!keychain) { @@ -39,7 +39,7 @@ class CMS { * * @param {string} name - The local key name. * @param {Uint8Array} plain - The data to encrypt. - * @returns {undefined} + * @returns {Promise} */ async encrypt (name, plain) { if (!(plain instanceof Uint8Array)) { @@ -69,7 +69,7 @@ class CMS { * exists, an Error is returned with the property 'missingKeys'. It is array of key ids. * * @param {Uint8Array} cmsData - The CMS encrypted data to decrypt. - * @returns {undefined} + * @returns {Promise} */ async decrypt (cmsData) { if (!(cmsData instanceof Uint8Array)) { diff --git a/src/peer-store/address-book.js b/src/peer-store/address-book.js index e23fc6dc..ebbd260c 100644 --- a/src/peer-store/address-book.js +++ b/src/peer-store/address-book.js @@ -207,7 +207,7 @@ class AddressBook extends Book { log(`stored provided multiaddrs for ${id}`) // Notify the existance of a new peer - if (!(entry && entry.addresses)) { + if (!entry) { this._ps.emit('peer', peerId) } diff --git a/src/ping/index.js b/src/ping/index.js index 53e3f679..eb8d7b96 100644 --- a/src/ping/index.js +++ b/src/ping/index.js @@ -33,7 +33,7 @@ async function ping (node, peer) { const { stream } = await node.dialProtocol(peer, PROTOCOL) - const start = new Date().getTime() + const start = Date.now() const data = crypto.randomBytes(PING_LENGTH) const [result] = await pipe( diff --git a/src/types.ts b/src/types.ts index fe58c0e5..3e87d7c8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -43,6 +43,17 @@ export type CAN_HOP = 4; export type CircuitType = HOP | STOP | STATUS | CAN_HOP +export type CircuitPeer = { + id: Uint8Array + addrs: Uint8Array[] +} + +export type CircuitRequest = { + type: CircuitType + dstPeer: CircuitPeer + srcPeer: CircuitPeer +} + export type CircuitMessageProto = { encode(value: any): Uint8Array decode(bytes: Uint8Array): any