From eacdc246da5895167e621a2bc65ef3ff7c3b4311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Wed, 30 Sep 2020 11:21:11 +0200 Subject: [PATCH] chore: add type generation from jsdoc (#64) --- package.json | 8 +- src/connection/connection.d.ts | 149 +++++++++ src/connection/connection.js | 15 +- src/connection/index.d.ts | 1 + src/connection/index.js | 4 + src/connection/status.d.ts | 3 + src/crypto/errors.d.ts | 15 + src/index.d.ts | 0 src/pubsub/errors.d.ts | 4 + src/pubsub/index.d.ts | 307 ++++++++++++++++++ src/pubsub/index.js | 20 +- src/pubsub/message/index.d.ts | 5 + src/pubsub/message/index.js | 3 + src/pubsub/message/rpc.proto.d.ts | 2 + src/pubsub/message/sign.d.ts | 23 ++ .../message/topic-descriptor.proto.d.ts | 2 + src/pubsub/peer-streams.d.ts | 113 +++++++ src/pubsub/peer-streams.js | 26 +- src/pubsub/utils.d.ts | 6 + src/pubsub/utils.js | 10 +- src/record/index.d.ts | 23 ++ src/topology/index.d.ts | 42 +++ src/topology/index.js | 10 +- src/topology/multicodec-topology.d.ts | 52 +++ src/topology/multicodec-topology.js | 4 + src/transport/errors.d.ts | 6 + tsconfig.json | 18 + 27 files changed, 851 insertions(+), 20 deletions(-) create mode 100644 src/connection/connection.d.ts create mode 100644 src/connection/index.d.ts create mode 100644 src/connection/status.d.ts create mode 100644 src/crypto/errors.d.ts create mode 100644 src/index.d.ts create mode 100644 src/pubsub/errors.d.ts create mode 100644 src/pubsub/index.d.ts create mode 100644 src/pubsub/message/index.d.ts create mode 100644 src/pubsub/message/rpc.proto.d.ts create mode 100644 src/pubsub/message/sign.d.ts create mode 100644 src/pubsub/message/topic-descriptor.proto.d.ts create mode 100644 src/pubsub/peer-streams.d.ts create mode 100644 src/pubsub/utils.d.ts create mode 100644 src/record/index.d.ts create mode 100644 src/topology/index.d.ts create mode 100644 src/topology/multicodec-topology.d.ts create mode 100644 src/transport/errors.d.ts create mode 100644 tsconfig.json diff --git a/package.json b/package.json index bd2eb07..193ab11 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,18 @@ "main": "src/index.js", "files": [ "src", + "types", "dist" ], "scripts": { "lint": "aegir lint", "build": "aegir build", + "pregenerate:types": "rimraf './src/**/*.d.ts'", + "generate:types": "tsc", "test": "aegir test", "test:node": "aegir test --target node", "test:browser": "aegir test --target browser", + "prepublishOnly": "npm run generate:types", "release": "aegir release -t node -t browser", "release-minor": "aegir release --type minor -t node -t browser", "release-major": "aegir release --type major -t node -t browser" @@ -63,7 +67,9 @@ }, "devDependencies": { "aegir": "^25.0.0", - "it-handshake": "^1.0.1" + "it-handshake": "^1.0.1", + "rimraf": "^3.0.2", + "typescript": "3.7.5" }, "contributors": [ "Alan Shaw ", diff --git a/src/connection/connection.d.ts b/src/connection/connection.d.ts new file mode 100644 index 0000000..f74e296 --- /dev/null +++ b/src/connection/connection.d.ts @@ -0,0 +1,149 @@ +declare const _exports: typeof Connection; +export = _exports; +/** + * An implementation of the js-libp2p connection. + * Any libp2p transport should use an upgrader to return this connection. + */ +declare class Connection { + /** + * Creates an instance of Connection. + * @param {object} properties properties of the connection. + * @param {multiaddr} [properties.localAddr] local multiaddr of the connection if known. + * @param {multiaddr} [properties.remoteAddr] remote multiaddr of the connection. + * @param {PeerId} properties.localPeer local peer-id. + * @param {PeerId} properties.remotePeer remote peer-id. + * @param {function} properties.newStream new stream muxer function. + * @param {function} properties.close close raw connection function. + * @param {function(): Stream[]} properties.getStreams get streams from muxer function. + * @param {object} properties.stat metadata of the connection. + * @param {string} properties.stat.direction connection establishment direction ("inbound" or "outbound"). + * @param {object} properties.stat.timeline connection relevant events timestamp. + * @param {string} properties.stat.timeline.open connection opening timestamp. + * @param {string} properties.stat.timeline.upgraded connection upgraded timestamp. + * @param {string} [properties.stat.multiplexer] connection multiplexing identifier. + * @param {string} [properties.stat.encryption] connection encryption method identifier. + */ + constructor({ localAddr, remoteAddr, localPeer, remotePeer, newStream, close, getStreams, stat }: { + localAddr?: import("multiaddr"); + remoteAddr?: import("multiaddr"); + localPeer: import("peer-id"); + remotePeer: import("peer-id"); + newStream: Function; + close: Function; + getStreams: () => any[]; + stat: { + direction: string; + timeline: { + open: string; + upgraded: string; + }; + multiplexer?: string; + encryption?: string; + }; + }); + /** + * Connection identifier. + */ + id: any; + /** + * Observed multiaddr of the local peer + */ + localAddr: import("multiaddr"); + /** + * Observed multiaddr of the remote peer + */ + remoteAddr: import("multiaddr"); + /** + * Local peer id. + */ + localPeer: import("peer-id"); + /** + * Remote peer id. + */ + remotePeer: import("peer-id"); + /** + * Connection metadata. + */ + _stat: { + status: string; + direction: string; + timeline: { + open: string; + upgraded: string; + }; + multiplexer?: string; + encryption?: string; + }; + /** + * Reference to the new stream function of the multiplexer + */ + _newStream: Function; + /** + * Reference to the close function of the raw connection + */ + _close: Function; + /** + * Reference to the getStreams function of the muxer + */ + _getStreams: () => any[]; + /** + * Connection streams registry + */ + registry: Map; + /** + * User provided tags + * @type {string[]} + */ + tags: string[]; + /** + * Get connection metadata + * @this {Connection} + */ + get stat(): { + status: string; + direction: string; + timeline: { + open: string; + upgraded: string; + }; + multiplexer?: string; + encryption?: string; + }; + /** + * Get all the streams of the muxer. + * @this {Connection} + */ + get streams(): any[]; + /** + * Create a new stream from this connection + * @param {string[]} protocols intended protocol for the stream + * @return {Promise<{stream: Stream, protocol: string}>} with muxed+multistream-selected stream and selected protocol + */ + newStream(protocols: string[]): Promise<{ + stream: any; + protocol: string; + }>; + /** + * Add a stream when it is opened to the registry. + * @param {*} muxedStream a muxed stream + * @param {object} properties the stream properties to be registered + * @param {string} properties.protocol the protocol used by the stream + * @param {object} properties.metadata metadata of the stream + * @return {void} + */ + addStream(muxedStream: any, { protocol, metadata }: { + protocol: string; + metadata: any; + }): void; + /** + * Remove stream registry after it is closed. + * @param {string} id identifier of the stream + */ + removeStream(id: string): void; + /** + * Close the connection. + * @return {Promise} + */ + close(): Promise; + _closing: any; +} diff --git a/src/connection/connection.js b/src/connection/connection.js index c2b58e8..d1ff248 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.js @@ -66,7 +66,7 @@ class Connection { * @param {PeerId} properties.remotePeer remote peer-id. * @param {function} properties.newStream new stream muxer function. * @param {function} properties.close close raw connection function. - * @param {function} properties.getStreams get streams from muxer function. + * @param {function(): Stream[]} properties.getStreams get streams from muxer function. * @param {object} properties.stat metadata of the connection. * @param {string} properties.stat.direction connection establishment direction ("inbound" or "outbound"). * @param {object} properties.stat.timeline connection relevant events timestamp. @@ -133,13 +133,14 @@ class Connection { /** * User provided tags + * @type {string[]} */ this.tags = [] } /** * Get connection metadata - * @return {Object} + * @this {Connection} */ get stat () { return this._stat @@ -147,7 +148,7 @@ class Connection { /** * Get all the streams of the muxer. - * @return {Array<*>} + * @this {Connection} */ get streams () { return this._getStreams() @@ -156,7 +157,7 @@ class Connection { /** * Create a new stream from this connection * @param {string[]} protocols intended protocol for the stream - * @return {Promise} with muxed+multistream-selected stream and selected protocol + * @return {Promise<{stream: Stream, protocol: string}>} with muxed+multistream-selected stream and selected protocol */ async newStream (protocols) { if (this.stat.status === Status.CLOSING) { @@ -205,7 +206,7 @@ class Connection { /** * Close the connection. - * @return {Promise} + * @return {Promise} */ async close () { if (this.stat.status === Status.CLOSED) { @@ -226,4 +227,8 @@ class Connection { } } +/** + * @module + * @type {typeof Connection} + */ module.exports = withIs(Connection, { className: 'Connection', symbolName: '@libp2p/interface-connection/connection' }) diff --git a/src/connection/index.d.ts b/src/connection/index.d.ts new file mode 100644 index 0000000..5dc4503 --- /dev/null +++ b/src/connection/index.d.ts @@ -0,0 +1 @@ +export var Connection: typeof import('./connection'); diff --git a/src/connection/index.js b/src/connection/index.js index c4c79fd..38cd616 100644 --- a/src/connection/index.js +++ b/src/connection/index.js @@ -1,3 +1,7 @@ 'use strict' +/** + * @module connection/index + * @type {typeof import('./connection')} + */ exports.Connection = require('./connection') diff --git a/src/connection/status.d.ts b/src/connection/status.d.ts new file mode 100644 index 0000000..fc476fa --- /dev/null +++ b/src/connection/status.d.ts @@ -0,0 +1,3 @@ +export declare const OPEN: string; +export declare const CLOSING: string; +export declare const CLOSED: string; diff --git a/src/crypto/errors.d.ts b/src/crypto/errors.d.ts new file mode 100644 index 0000000..0e1afe5 --- /dev/null +++ b/src/crypto/errors.d.ts @@ -0,0 +1,15 @@ +export class UnexpectedPeerError extends Error { + static get code(): string; + constructor(message?: string); + code: string; +} +export class InvalidCryptoExchangeError extends Error { + static get code(): string; + constructor(message?: string); + code: string; +} +export class InvalidCryptoTransmissionError extends Error { + static get code(): string; + constructor(message?: string); + code: string; +} diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/pubsub/errors.d.ts b/src/pubsub/errors.d.ts new file mode 100644 index 0000000..98256b4 --- /dev/null +++ b/src/pubsub/errors.d.ts @@ -0,0 +1,4 @@ +export namespace codes { + export const ERR_MISSING_SIGNATURE: string; + export const ERR_INVALID_SIGNATURE: string; +} diff --git a/src/pubsub/index.d.ts b/src/pubsub/index.d.ts new file mode 100644 index 0000000..d4f7dbd --- /dev/null +++ b/src/pubsub/index.d.ts @@ -0,0 +1,307 @@ +export = PubsubBaseProtocol; +/** + * @typedef {Object} InMessage + * @property {string} [from] + * @property {string} receivedFrom + * @property {string[]} topicIDs + * @property {Uint8Array} [seqno] + * @property {Uint8Array} data + * @property {Uint8Array} [signature] + * @property {Uint8Array} [key] + * + * @typedef PeerId + * @type import('peer-id') + */ +/** +* PubsubBaseProtocol handles the peers and connections logic for pubsub routers +* and specifies the API that pubsub routers should have. +*/ +declare class PubsubBaseProtocol { + /** + * @param {Object} props + * @param {String} props.debugName log namespace + * @param {Array|string} props.multicodecs protocol identificers to connect + * @param {Libp2p} props.libp2p + * @param {boolean} [props.signMessages = true] if messages should be signed + * @param {boolean} [props.strictSigning = true] if message signing should be required + * @param {boolean} [props.canRelayMessage = false] if can relay messages not subscribed + * @param {boolean} [props.emitSelf = false] if publish should emit to self, if subscribed + * @abstract + */ + constructor({ debugName, multicodecs, libp2p, signMessages, strictSigning, canRelayMessage, emitSelf }: { + debugName: string; + multicodecs: string | string[]; + libp2p: any; + signMessages?: boolean; + strictSigning?: boolean; + canRelayMessage?: boolean; + emitSelf?: boolean; + }); + log: any; + /** + * @type {Array} + */ + multicodecs: Array; + _libp2p: any; + registrar: any; + /** + * @type {PeerId} + */ + peerId: PeerId; + started: boolean; + /** + * Map of topics to which peers are subscribed to + * + * @type {Map>} + */ + topics: Map>; + /** + * List of our subscriptions + * @type {Set} + */ + subscriptions: Set; + /** + * Map of peer streams + * + * @type {Map} + */ + peers: Map; + signMessages: boolean; + /** + * If message signing should be required for incoming messages + * @type {boolean} + */ + strictSigning: boolean; + /** + * If router can relay received messages, even if not subscribed + * @type {boolean} + */ + canRelayMessage: boolean; + /** + * if publish should emit to self, if subscribed + * @type {boolean} + */ + emitSelf: boolean; + /** + * Topic validator function + * @typedef {function(string, InMessage): Promise} validator + */ + /** + * Topic validator map + * + * Keyed by topic + * Topic validators are functions with the following input: + * @type {Map} + */ + topicValidators: Map; + _registrarId: any; + /** + * On an inbound stream opened. + * @private + * @param {Object} props + * @param {string} props.protocol + * @param {DuplexIterableStream} props.stream + * @param {Connection} props.connection connection + */ + _onIncomingStream({ protocol, stream, connection }: { + protocol: string; + stream: any; + connection: any; + }): void; + /** + * Registrar notifies an established connection with pubsub protocol. + * @private + * @param {PeerId} peerId remote peer-id + * @param {Connection} conn connection to the peer + */ + _onPeerConnected(peerId: import("peer-id"), conn: any): Promise; + /** + * Registrar notifies a closing connection with pubsub protocol. + * @private + * @param {PeerId} peerId peerId + * @param {Error} err error for connection end + */ + _onPeerDisconnected(peerId: import("peer-id"), err: Error): void; + /** + * Register the pubsub protocol onto the libp2p node. + * @returns {void} + */ + start(): void; + /** + * Unregister the pubsub protocol and the streams with other peers will be closed. + * @returns {void} + */ + stop(): void; + /** + * Notifies the router that a peer has been connected + * @private + * @param {PeerId} peerId + * @param {string} protocol + * @returns {PeerStreams} + */ + _addPeer(peerId: import("peer-id"), protocol: string): import("./peer-streams"); + /** + * Notifies the router that a peer has been disconnected. + * @private + * @param {PeerId} peerId + * @returns {PeerStreams | undefined} + */ + _removePeer(peerId: import("peer-id")): import("./peer-streams"); + /** + * Responsible for processing each RPC message received by other peers. + * @param {string} idB58Str peer id string in base58 + * @param {DuplexIterableStream} stream inbound stream + * @param {PeerStreams} peerStreams PubSub peer + * @returns {Promise} + */ + _processMessages(idB58Str: string, stream: any, peerStreams: import("./peer-streams")): Promise; + /** + * Handles an rpc request from a peer + * @param {String} idB58Str + * @param {PeerStreams} peerStreams + * @param {RPC} rpc + * @returns {boolean} + */ + _processRpc(idB58Str: string, peerStreams: import("./peer-streams"), rpc: any): boolean; + /** + * Handles a subscription change from a peer + * @param {string} id + * @param {RPC.SubOpt} subOpt + */ + _processRpcSubOpt(id: string, subOpt: any): void; + /** + * Handles an message from a peer + * @param {InMessage} msg + * @returns {Promise} + */ + _processRpcMessage(msg: InMessage): Promise; + /** + * Emit a message from a peer + * @param {InMessage} message + */ + _emitMessage(message: InMessage): void; + /** + * The default msgID implementation + * Child class can override this. + * @param {RPC.Message} msg the message object + * @returns {string} message id as string + */ + getMsgId(msg: any): string; + /** + * Whether to accept a message from a peer + * Override to create a graylist + * @override + * @param {string} id + * @returns {boolean} + */ + _acceptFrom(id: string): boolean; + /** + * Decode Uint8Array into an RPC object. + * This can be override to use a custom router protobuf. + * @param {Uint8Array} bytes + * @returns {RPC} + */ + _decodeRpc(bytes: Uint8Array): any; + /** + * Encode RPC object into a Uint8Array. + * This can be override to use a custom router protobuf. + * @param {RPC} rpc + * @returns {Uint8Array} + */ + _encodeRpc(rpc: any): Uint8Array; + /** + * Send an rpc object to a peer + * @param {string} id peer id + * @param {RPC} rpc + * @returns {void} + */ + _sendRpc(id: string, rpc: any): void; + /** + * Send subscroptions to a peer + * @param {string} id peer id + * @param {string[]} topics + * @param {boolean} subscribe set to false for unsubscriptions + * @returns {void} + */ + _sendSubscriptions(id: string, topics: string[], subscribe: boolean): void; + /** + * Validates the given message. The signature will be checked for authenticity. + * Throws an error on invalid messages + * @param {InMessage} message + * @returns {Promise} + */ + validate(message: InMessage): Promise; + /** + * Normalizes the message and signs it, if signing is enabled. + * Should be used by the routers to create the message to send. + * @private + * @param {Message} message + * @returns {Promise} + */ + _buildMessage(message: any): Promise; + /** + * Get a list of the peer-ids that are subscribed to one topic. + * @param {string} topic + * @returns {Array} + */ + getSubscribers(topic: string): string[]; + /** + * Publishes messages to all subscribed peers + * @override + * @param {string} topic + * @param {Buffer} message + * @returns {Promise} + */ + publish(topic: string, message: Buffer): Promise; + /** + * Overriding the implementation of publish should handle the appropriate algorithms for the publish/subscriber implementation. + * For example, a Floodsub implementation might simply publish each message to each topic for every peer + * @abstract + * @param {InMessage} message + * @returns {Promise} + * + */ + _publish(message: InMessage): Promise; + /** + * Subscribes to a given topic. + * @abstract + * @param {string} topic + * @returns {void} + */ + subscribe(topic: string): void; + /** + * Unsubscribe from the given topic. + * @override + * @param {string} topic + * @returns {void} + */ + unsubscribe(topic: string): void; + /** + * Get the list of topics which the peer is subscribed to. + * @override + * @returns {Array} + */ + getTopics(): string[]; +} +declare namespace PubsubBaseProtocol { + export { message, utils, InMessage, PeerId }; +} +type PeerId = import("peer-id"); +/** + * Topic validator function + */ +type validator = (arg0: string, arg1: InMessage) => Promise; +type InMessage = { + from?: string; + receivedFrom: string; + topicIDs: string[]; + seqno?: Uint8Array; + data: Uint8Array; + signature?: Uint8Array; + key?: Uint8Array; +}; +/** + * @type {typeof import('./message')} + */ +declare const message: typeof import('./message'); +declare const utils: typeof import("./utils"); diff --git a/src/pubsub/index.js b/src/pubsub/index.js index db878e9..f7d1af6 100644 --- a/src/pubsub/index.js +++ b/src/pubsub/index.js @@ -8,9 +8,13 @@ const pipe = require('it-pipe') const MulticodecTopology = require('../topology/multicodec-topology') const { codes } = require('./errors') +/** + * @type {typeof import('./message')} + */ const message = require('./message') const PeerStreams = require('./peer-streams') const utils = require('./utils') + const { signMessage, verifySignature @@ -18,12 +22,16 @@ const { /** * @typedef {Object} InMessage - * @property {string} from + * @property {string} [from] * @property {string} receivedFrom * @property {string[]} topicIDs + * @property {Uint8Array} [seqno] * @property {Uint8Array} data * @property {Uint8Array} [signature] * @property {Uint8Array} [key] + * + * @typedef PeerId + * @type import('peer-id') */ /** @@ -68,9 +76,15 @@ class PubsubBaseProtocol extends EventEmitter { this.log = debug(debugName) this.log.err = debug(`${debugName}:error`) + /** + * @type {Array} + */ this.multicodecs = utils.ensureArray(multicodecs) this._libp2p = libp2p this.registrar = libp2p.registrar + /** + * @type {PeerId} + */ this.peerId = libp2p.peerId this.started = false @@ -91,7 +105,7 @@ class PubsubBaseProtocol extends EventEmitter { /** * Map of peer streams * - * @type {Map} + * @type {Map} */ this.peers = new Map() @@ -118,7 +132,7 @@ class PubsubBaseProtocol extends EventEmitter { /** * Topic validator function - * @typedef {function(string, RPC): boolean} validator + * @typedef {function(string, InMessage): Promise} validator */ /** * Topic validator map diff --git a/src/pubsub/message/index.d.ts b/src/pubsub/message/index.d.ts new file mode 100644 index 0000000..62df1ce --- /dev/null +++ b/src/pubsub/message/index.d.ts @@ -0,0 +1,5 @@ +export var rpc: any; +export var td: any; +export var RPC: any; +export var Message: any; +export var SubOpts: any; diff --git a/src/pubsub/message/index.js b/src/pubsub/message/index.js index 320ab4c..c5e6329 100644 --- a/src/pubsub/message/index.js +++ b/src/pubsub/message/index.js @@ -6,6 +6,9 @@ const rpcProto = protons(require('./rpc.proto.js')) const RPC = rpcProto.RPC const topicDescriptorProto = protons(require('./topic-descriptor.proto.js')) +/** + * @module pubsub/message/index + */ exports = module.exports exports.rpc = rpcProto exports.td = topicDescriptorProto diff --git a/src/pubsub/message/rpc.proto.d.ts b/src/pubsub/message/rpc.proto.d.ts new file mode 100644 index 0000000..763ab62 --- /dev/null +++ b/src/pubsub/message/rpc.proto.d.ts @@ -0,0 +1,2 @@ +declare const _exports: string; +export = _exports; diff --git a/src/pubsub/message/sign.d.ts b/src/pubsub/message/sign.d.ts new file mode 100644 index 0000000..3e1bee2 --- /dev/null +++ b/src/pubsub/message/sign.d.ts @@ -0,0 +1,23 @@ +/** + * Returns the PublicKey associated with the given message. + * If no, valid PublicKey can be retrieved an error will be returned. + * + * @param {InMessage} message + * @returns {Promise} + */ +export function messagePublicKey(message: any): Promise; +/** + * Signs the provided message with the given `peerId` + * + * @param {PeerId} peerId + * @param {Message} message + * @returns {Promise} + */ +export function signMessage(peerId: import("peer-id"), message: any): Promise; +export const SignPrefix: any; +/** + * Verifies the signature of the given message + * @param {InMessage} message + * @returns {Promise} + */ +export function verifySignature(message: any): Promise; diff --git a/src/pubsub/message/topic-descriptor.proto.d.ts b/src/pubsub/message/topic-descriptor.proto.d.ts new file mode 100644 index 0000000..763ab62 --- /dev/null +++ b/src/pubsub/message/topic-descriptor.proto.d.ts @@ -0,0 +1,2 @@ +declare const _exports: string; +export = _exports; diff --git a/src/pubsub/peer-streams.d.ts b/src/pubsub/peer-streams.d.ts new file mode 100644 index 0000000..632fe2c --- /dev/null +++ b/src/pubsub/peer-streams.d.ts @@ -0,0 +1,113 @@ +export = PeerStreams; +/** + * @callback Sink + * @param {Uint8Array} source + * @returns {Promise} + * + * @typedef {object} DuplexIterableStream + * @property {Sink} sink + * @property {() AsyncIterator} source + * + * @typedef PeerId + * @type import('peer-id') + */ +/** + * Thin wrapper around a peer's inbound / outbound pubsub streams + */ +declare class PeerStreams { + /** + * @param {object} properties properties of the PeerStreams. + * @param {PeerId} properties.id + * @param {string} properties.protocol + */ + constructor({ id, protocol }: { + id: import("peer-id"); + protocol: string; + }); + /** + * @type {import('peer-id')} + */ + id: import('peer-id'); + /** + * Established protocol + * @type {string} + */ + protocol: string; + /** + * The raw outbound stream, as retrieved from conn.newStream + * @private + * @type {DuplexIterableStream} + */ + _rawOutboundStream: DuplexIterableStream; + /** + * The raw inbound stream, as retrieved from the callback from libp2p.handle + * @private + * @type {DuplexIterableStream} + */ + _rawInboundStream: DuplexIterableStream; + /** + * An AbortController for controlled shutdown of the inbound stream + * @private + * @type {typeof AbortController} + */ + _inboundAbortController: typeof AbortController; + /** + * Write stream -- its preferable to use the write method + * @type {import('it-pushable').Pushable>} + */ + outboundStream: import('it-pushable').Pushable; + /** + * Read stream + * @type {DuplexIterableStream} + */ + inboundStream: DuplexIterableStream; + /** + * Do we have a connection to read from? + * + * @type {boolean} + */ + get isReadable(): boolean; + /** + * Do we have a connection to write on? + * + * @type {boolean} + */ + get isWritable(): boolean; + /** + * Send a message to this peer. + * Throws if there is no `stream` to write to available. + * + * @param {Uint8Array} data + * @returns {void} + */ + write(data: Uint8Array): void; + /** + * Attach a raw inbound stream and setup a read stream + * + * @param {DuplexIterableStream} stream + * @returns {void} + */ + attachInboundStream(stream: DuplexIterableStream): void; + /** + * Attach a raw outbound stream and setup a write stream + * + * @param {Stream} stream + * @returns {Promise} + */ + attachOutboundStream(stream: any): Promise; + /** + * Closes the open connection to peer + * @returns {void} + */ + close(): void; +} +declare namespace PeerStreams { + export { Sink, DuplexIterableStream, PeerId }; +} +type DuplexIterableStream = { + sink: Sink; + source: () => AsyncIterator; +}; +declare const AbortController: typeof import("abort-controller"); +type Sink = (source: Uint8Array) => Promise; +type PeerId = import("peer-id"); diff --git a/src/pubsub/peer-streams.js b/src/pubsub/peer-streams.js index 8877762..a41e1d8 100644 --- a/src/pubsub/peer-streams.js +++ b/src/pubsub/peer-streams.js @@ -12,19 +12,33 @@ const debug = require('debug') const log = debug('libp2p-pubsub:peer-streams') log.error = debug('libp2p-pubsub:peer-streams:error') +/** + * @callback Sink + * @param {Uint8Array} source + * @returns {Promise} + * + * @typedef {object} DuplexIterableStream + * @property {Sink} sink + * @property {() AsyncIterator} source + * + * @typedef PeerId + * @type import('peer-id') + */ + /** * Thin wrapper around a peer's inbound / outbound pubsub streams */ class PeerStreams extends EventEmitter { /** - * @param {PeerId} id - * @param {string} protocol + * @param {object} properties properties of the PeerStreams. + * @param {PeerId} properties.id + * @param {string} properties.protocol */ constructor ({ id, protocol }) { super() /** - * @type {PeerId} + * @type {import('peer-id')} */ this.id = id /** @@ -47,12 +61,12 @@ class PeerStreams extends EventEmitter { /** * An AbortController for controlled shutdown of the inbound stream * @private - * @type {AbortController} + * @type {typeof AbortController} */ this._inboundAbortController = null /** * Write stream -- its preferable to use the write method - * @type {Pushable} + * @type {import('it-pushable').Pushable>} */ this.outboundStream = null /** @@ -85,7 +99,7 @@ class PeerStreams extends EventEmitter { * Throws if there is no `stream` to write to available. * * @param {Uint8Array} data - * @returns {undefined} + * @returns {void} */ write (data) { if (!this.isWritable) { diff --git a/src/pubsub/utils.d.ts b/src/pubsub/utils.d.ts new file mode 100644 index 0000000..b237b3f --- /dev/null +++ b/src/pubsub/utils.d.ts @@ -0,0 +1,6 @@ +export function randomSeqno(): Uint8Array; +export function msgId(from: string, seqno: Uint8Array): string; +export function anyMatch(a: any[] | Set, b: any[] | Set): boolean; +export function ensureArray(maybeArray: any): any[]; +export function normalizeInRpcMessage(message: any, peerId: string): any; +export function normalizeOutRpcMessage(message: any): any; diff --git a/src/pubsub/utils.js b/src/pubsub/utils.js index 4d26bef..3663676 100644 --- a/src/pubsub/utils.js +++ b/src/pubsub/utils.js @@ -3,7 +3,6 @@ const randomBytes = require('libp2p-crypto/src/random-bytes') const uint8ArrayToString = require('uint8arrays/to-string') const uint8ArrayFromString = require('uint8arrays/from-string') - exports = module.exports /** @@ -71,10 +70,9 @@ exports.ensureArray = (maybeArray) => { /** * Ensures `message.from` is base58 encoded - * @param {Object} message - * @param {Uint8Array|String} message.from + * @param {object} message * @param {String} peerId - * @return {Object} + * @return {object} */ exports.normalizeInRpcMessage = (message, peerId) => { const m = Object.assign({}, message) @@ -87,6 +85,10 @@ exports.normalizeInRpcMessage = (message, peerId) => { return m } +/** + * @param {object} message + * @return {object} + */ exports.normalizeOutRpcMessage = (message) => { const m = Object.assign({}, message) if (typeof message.from === 'string' || message.from instanceof String) { diff --git a/src/record/index.d.ts b/src/record/index.d.ts new file mode 100644 index 0000000..53007cb --- /dev/null +++ b/src/record/index.d.ts @@ -0,0 +1,23 @@ +export = Record; +/** + * Record is the base implementation of a record that can be used as the payload of a libp2p envelope. + */ +declare class Record { + /** + * @constructor + * @param {String} domain signature domain + * @param {Uint8Array} codec identifier of the type of record + */ + constructor(domain: string, codec: Uint8Array); + domain: string; + codec: Uint8Array; + /** + * Marshal a record to be used in an envelope. + */ + marshal(): void; + /** + * Verifies if the other provided Record is identical to this one. + * @param {Record} other + */ + equals(other: Record): void; +} diff --git a/src/topology/index.d.ts b/src/topology/index.d.ts new file mode 100644 index 0000000..d2e1141 --- /dev/null +++ b/src/topology/index.d.ts @@ -0,0 +1,42 @@ +declare const _exports: Topology; +export = _exports; +declare class Topology { + /** + * @param {Object} props + * @param {number} props.min minimum needed connections (default: 0) + * @param {number} props.max maximum needed connections (default: Infinity) + * @param {Object} [props.handlers] + * @param {function} [props.handlers.onConnect] protocol "onConnect" handler + * @param {function} [props.handlers.onDisconnect] protocol "onDisconnect" handler + * @constructor + */ + constructor({ min, max, handlers }: { + min: number; + max: number; + handlers?: { + onConnect?: Function; + onDisconnect?: Function; + }; + }); + min: number; + max: number; + _onConnect: Function; + _onDisconnect: Function; + /** + * Set of peers that support the protocol. + * @type {Set} + */ + peers: Set; + set registrar(arg: any); + _registrar: any; + /** + * @typedef PeerId + * @type {import('peer-id')} + */ + /** + * Notify about peer disconnected event. + * @param {PeerId} peerId + * @returns {void} + */ + disconnect(peerId: import("peer-id")): void; +} diff --git a/src/topology/index.js b/src/topology/index.js index 53fac3d..77af929 100644 --- a/src/topology/index.js +++ b/src/topology/index.js @@ -1,7 +1,6 @@ 'use strict' const withIs = require('class-is') - const noop = () => {} class Topology { @@ -37,6 +36,11 @@ class Topology { this._registrar = registrar } + /** + * @typedef PeerId + * @type {import('peer-id')} + */ + /** * Notify about peer disconnected event. * @param {PeerId} peerId @@ -47,4 +51,8 @@ class Topology { } } +/** + * @module + * @type {Topology} + */ module.exports = withIs(Topology, { className: 'Topology', symbolName: '@libp2p/js-interfaces/topology' }) diff --git a/src/topology/multicodec-topology.d.ts b/src/topology/multicodec-topology.d.ts new file mode 100644 index 0000000..8752aff --- /dev/null +++ b/src/topology/multicodec-topology.d.ts @@ -0,0 +1,52 @@ +declare const _exports: MulticodecTopology; +export = _exports; +declare class MulticodecTopology { + /** + * @param {Object} props + * @param {number} props.min minimum needed connections (default: 0) + * @param {number} props.max maximum needed connections (default: Infinity) + * @param {Array} props.multicodecs protocol multicodecs + * @param {Object} props.handlers + * @param {function} props.handlers.onConnect protocol "onConnect" handler + * @param {function} props.handlers.onDisconnect protocol "onDisconnect" handler + * @constructor + */ + constructor({ min, max, multicodecs, handlers }: { + min: number; + max: number; + multicodecs: string[]; + handlers: { + onConnect: Function; + onDisconnect: Function; + }; + }); + multicodecs: string[]; + _registrar: any; + /** + * Check if a new peer support the multicodecs for this topology. + * @param {Object} props + * @param {PeerId} props.peerId + * @param {Array} props.protocols + */ + _onProtocolChange({ peerId, protocols }: { + peerId: any; + protocols: string[]; + }): void; + /** + * Verify if a new connected peer has a topology multicodec and call _onConnect. + * @param {Connection} connection + * @returns {void} + */ + _onPeerConnect(connection: any): void; + set registrar(arg: any); + /** + * Update topology. + * @param {Array<{id: PeerId, multiaddrs: Array, protocols: Array}>} peerDataIterable + * @returns {void} + */ + _updatePeers(peerDataIterable: { + id: any; + multiaddrs: any[]; + protocols: string[]; + }[]): void; +} diff --git a/src/topology/multicodec-topology.js b/src/topology/multicodec-topology.js index 76ef03d..2cdc076 100644 --- a/src/topology/multicodec-topology.js +++ b/src/topology/multicodec-topology.js @@ -120,4 +120,8 @@ class MulticodecTopology extends Topology { } } +/** + * @module + * @type {MulticodecTopology} + */ module.exports = withIs(MulticodecTopology, { className: 'MulticodecTopology', symbolName: '@libp2p/js-interfaces/topology/multicodec-topology' }) diff --git a/src/transport/errors.d.ts b/src/transport/errors.d.ts new file mode 100644 index 0000000..45b4751 --- /dev/null +++ b/src/transport/errors.d.ts @@ -0,0 +1,6 @@ +export class AbortError extends Error { + static get code(): string; + static get type(): string; + code: string; + type: string; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..482bfe8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "include": ["src/**/*.js"], + "exclude": ["src/**/tests/*", "src/utils"], + + "compilerOptions": { + // Tells TypeScript to read JS files, as + // normally they are ignored as source files + "allowJs": true, + // Generate d.ts files + "declaration": true, + // This compiler run should + // only output d.ts files + "emitDeclarationOnly": true, + "esModuleInterop": true, + "rootDir": "./src", + "outDir": "./src" + } +}