@libp2p/utils 0.0.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,2 @@
1
+ MIT: https://www.opensource.org/licenses/mit
2
+ Apache-2.0: https://www.apache.org/licenses/license-2.0
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # js-libp2p-utils
2
+
3
+ [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
4
+ [![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/)
5
+ [![](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p)
6
+ [![Discourse posts](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg)](https://discuss.libp2p.io)
7
+ [![](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-utils.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utils)
8
+ [![](https://img.shields.io/travis/libp2p/js-libp2p-utils.svg?style=flat-square)](https://travis-ci.com/libp2p/js-libp2p-utils)
9
+ [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utils.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utils)
10
+ [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
11
+
12
+ > This package serves as a central repository for shared logic and dependencies for all libp2p packages, using `libp2p-utils` helps to easily re-use small scoped blocks of logic across all libp2p modules and also as a dependency proxy (think `aegir` for domain logic dependencies).
13
+
14
+
15
+ The libp2p ecosystem has lots of repos with it comes several problems like:
16
+ - Domain logic dedupe - all modules shared a lot of logic like validation, streams handling, etc.
17
+ - Dependencies management - it's really easy with so many repos for dependencies to go out of control, they become outdated, different repos use different modules to do the same thing (like merging defaults options), browser bundles ends up with multiple versions of the same package, bumping versions is cumbersome to do because we need to go through several repos, etc.
18
+
19
+ These problems are the motivation for this package, having shared logic in this package avoids creating cyclic dependencies, centralizes common use modules/functions (exactly like aegir does for the tooling), semantic versioning for 3rd party dependencies is handled in one single place (a good example is going from streams 2 to 3) and maintainers should only care about having `libp2p-utils` updated.
20
+
21
+ ## Lead Maintainer
22
+
23
+ [Vasco Santos](https://github.com/vasco-santos)
24
+
25
+ ## Install
26
+
27
+
28
+ ```bash
29
+ $ npm install --save @libp2p/utils
30
+ ```
31
+
32
+ ## Usage
33
+ Each function should be imported directly.
34
+
35
+ ```js
36
+ import ipAndPortToMultiaddr from '@libp2p/utils/ip-port-to-multiaddr'
37
+
38
+ const ma = ipAndPortToMultiaddr('127.0.0.1', 9000)
39
+ ```
40
+
41
+ You can check the [API docs](./API.md).
42
+
43
+ ## Contribute
44
+
45
+ Contributions welcome. Please check out [the issues](https://github.com/libp2p/js-libp2p-utils/issues).
46
+
47
+ Check out our [contributing document](https://github.com/ipfs/community/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to this repo are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
48
+
49
+ ## License
50
+
51
+ [MIT](LICENSE) © Protocol Labs Inc.
@@ -0,0 +1,12 @@
1
+ import type { Multiaddr } from '@multiformats/multiaddr';
2
+ interface Address {
3
+ multiaddr: Multiaddr;
4
+ isCertified: boolean;
5
+ }
6
+ /**
7
+ * Sort given addresses by putting public addresses first.
8
+ * In case of equality, a certified address will come first.
9
+ */
10
+ export declare function publicAddressesFirst(addresses: Address[]): Address[];
11
+ export {};
12
+ //# sourceMappingURL=address-sort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-sort.d.ts","sourceRoot":"","sources":["../../src/address-sort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAGxD,UAAU,OAAO;IACf,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,OAAO,CAAA;CACrB;AAoCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAE,SAAS,EAAE,OAAO,EAAE,aAEzD"}
@@ -0,0 +1,41 @@
1
+ import { isPrivate } from './multiaddr/is-private.js';
2
+ /**
3
+ * @typedef {Object} Address
4
+ * @property {Multiaddr} multiaddr peer multiaddr.
5
+ * @property {boolean} isCertified obtained from a signed peer record.
6
+ */
7
+ /**
8
+ * Compare function for array.sort().
9
+ * This sort aims to move the private adresses to the end of the array.
10
+ * In case of equality, a certified address will come first.
11
+ *
12
+ * @param {Address} a
13
+ * @param {Address} b
14
+ * @returns {number}
15
+ */
16
+ function addressesPublicFirstCompareFunction(a, b) {
17
+ const isAPrivate = isPrivate(a.multiaddr);
18
+ const isBPrivate = isPrivate(b.multiaddr);
19
+ if (isAPrivate && !isBPrivate) {
20
+ return 1;
21
+ }
22
+ else if (!isAPrivate && isBPrivate) {
23
+ return -1;
24
+ }
25
+ // Check certified?
26
+ if (a.isCertified && !b.isCertified) {
27
+ return -1;
28
+ }
29
+ else if (!a.isCertified && b.isCertified) {
30
+ return 1;
31
+ }
32
+ return 0;
33
+ }
34
+ /**
35
+ * Sort given addresses by putting public addresses first.
36
+ * In case of equality, a certified address will come first.
37
+ */
38
+ export function publicAddressesFirst(addresses) {
39
+ return [...addresses].sort(addressesPublicFirstCompareFunction);
40
+ }
41
+ //# sourceMappingURL=address-sort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address-sort.js","sourceRoot":"","sources":["../../src/address-sort.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAOrD;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,SAAS,mCAAmC,CAAE,CAAU,EAAE,CAAU;IAClE,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACzC,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAEzC,IAAI,UAAU,IAAI,CAAC,UAAU,EAAE;QAC7B,OAAO,CAAC,CAAA;KACT;SAAM,IAAI,CAAC,UAAU,IAAI,UAAU,EAAE;QACpC,OAAO,CAAC,CAAC,CAAA;KACV;IACD,mBAAmB;IACnB,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;QACnC,OAAO,CAAC,CAAC,CAAA;KACV;SAAM,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,EAAE;QAC1C,OAAO,CAAC,CAAA;KACT;IAED,OAAO,CAAC,CAAA;AACV,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAE,SAAoB;IACxD,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAA;AACjE,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Verify if two arrays of non primitive types with the "equals" function are equal.
3
+ * Compatible with multiaddr, peer-id and others.
4
+ */
5
+ export declare function arrayEquals(a: any[], b: any[]): boolean;
6
+ //# sourceMappingURL=array-equals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array-equals.d.ts","sourceRoot":"","sources":["../../src/array-equals.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,WAG9C"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Verify if two arrays of non primitive types with the "equals" function are equal.
3
+ * Compatible with multiaddr, peer-id and others.
4
+ */
5
+ export function arrayEquals(a, b) {
6
+ const sort = (a, b) => a.toString().localeCompare(b.toString());
7
+ return a.length === b.length && b.sort(sort) && a.sort(sort).every((item, index) => b[index].equals(item));
8
+ }
9
+ //# sourceMappingURL=array-equals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array-equals.js","sourceRoot":"","sources":["../../src/array-equals.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAE,CAAQ,EAAE,CAAQ;IAC7C,MAAM,IAAI,GAAG,CAAC,CAAM,EAAE,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;IACzE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;AAC5G,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Multiaddr } from '@multiformats/multiaddr';
2
+ export declare const Errors: {
3
+ ERR_INVALID_IP_PARAMETER: string;
4
+ ERR_INVALID_PORT_PARAMETER: string;
5
+ ERR_INVALID_IP: string;
6
+ };
7
+ /**
8
+ * Transform an IP, Port pair into a multiaddr
9
+ */
10
+ export declare function ipPortToMultiaddr(ip: string, port: number | string): Multiaddr;
11
+ //# sourceMappingURL=ip-port-to-multiaddr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip-port-to-multiaddr.d.ts","sourceRoot":"","sources":["../../src/ip-port-to-multiaddr.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAQnD,eAAO,MAAM,MAAM;;;;CAIlB,CAAA;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,aA8BnE"}
@@ -0,0 +1,45 @@
1
+ import debug from 'debug';
2
+ import { Multiaddr } from '@multiformats/multiaddr';
3
+ import errCode from 'err-code';
4
+ import { Address4, Address6 } from '@achingbrain/ip-address';
5
+ const log = Object.assign(debug('libp2p:ip-port-to-multiaddr'), {
6
+ error: debug('libp2p:ip-port-to-multiaddr:err')
7
+ });
8
+ export const Errors = {
9
+ ERR_INVALID_IP_PARAMETER: 'ERR_INVALID_IP_PARAMETER',
10
+ ERR_INVALID_PORT_PARAMETER: 'ERR_INVALID_PORT_PARAMETER',
11
+ ERR_INVALID_IP: 'ERR_INVALID_IP'
12
+ };
13
+ /**
14
+ * Transform an IP, Port pair into a multiaddr
15
+ */
16
+ export function ipPortToMultiaddr(ip, port) {
17
+ if (typeof ip !== 'string') {
18
+ throw errCode(new Error(`invalid ip provided: ${ip}`), Errors.ERR_INVALID_IP_PARAMETER); // eslint-disable-line @typescript-eslint/restrict-template-expressions
19
+ }
20
+ if (typeof port === 'string') {
21
+ port = parseInt(port);
22
+ }
23
+ if (isNaN(port)) {
24
+ throw errCode(new Error(`invalid port provided: ${port}`), Errors.ERR_INVALID_PORT_PARAMETER);
25
+ }
26
+ try {
27
+ // Test valid IPv4
28
+ new Address4(ip); // eslint-disable-line no-new
29
+ return new Multiaddr(`/ip4/${ip}/tcp/${port}`);
30
+ }
31
+ catch { }
32
+ try {
33
+ // Test valid IPv6
34
+ const ip6 = new Address6(ip);
35
+ return ip6.is4()
36
+ ? new Multiaddr(`/ip4/${ip6.to4().correctForm()}/tcp/${port}`)
37
+ : new Multiaddr(`/ip6/${ip}/tcp/${port}`);
38
+ }
39
+ catch (err) {
40
+ const errMsg = `invalid ip:port for creating a multiaddr: ${ip}:${port}`;
41
+ log.error(errMsg);
42
+ throw errCode(new Error(errMsg), Errors.ERR_INVALID_IP);
43
+ }
44
+ }
45
+ //# sourceMappingURL=ip-port-to-multiaddr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip-port-to-multiaddr.js","sourceRoot":"","sources":["../../src/ip-port-to-multiaddr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAE5D,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,EAAE;IAC9D,KAAK,EAAE,KAAK,CAAC,iCAAiC,CAAC;CAChD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,wBAAwB,EAAE,0BAA0B;IACpD,0BAA0B,EAAE,4BAA4B;IACxD,cAAc,EAAE,gBAAgB;CACjC,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAE,EAAU,EAAE,IAAqB;IAClE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE;QAC1B,MAAM,OAAO,CAAC,IAAI,KAAK,CAAC,wBAAwB,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,wBAAwB,CAAC,CAAA,CAAC,uEAAuE;KAChK;IAED,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;KACtB;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE;QACf,MAAM,OAAO,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,0BAA0B,CAAC,CAAA;KAC9F;IAED,IAAI;QACF,kBAAkB;QAClB,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAA,CAAC,6BAA6B;QAC9C,OAAO,IAAI,SAAS,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAA;KAC/C;IAAC,MAAM,GAAE;IAEV,IAAI;QACF,kBAAkB;QAClB,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC5B,OAAO,GAAG,CAAC,GAAG,EAAE;YACd,CAAC,CAAC,IAAI,SAAS,CAAC,QAAQ,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,QAAQ,IAAI,EAAE,CAAC;YAC9D,CAAC,CAAC,IAAI,SAAS,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAA;KAC5C;IAAC,OAAO,GAAG,EAAE;QACZ,MAAM,MAAM,GAAG,6CAA6C,EAAE,IAAI,IAAI,EAAE,CAAA;QACxE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACjB,MAAM,OAAO,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,CAAA;KACxD;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Multiaddr } from '@multiformats/multiaddr';
2
+ /**
3
+ * Check if a given multiaddr is a loopback address.
4
+ */
5
+ export declare function isLoopback(ma: Multiaddr): any;
6
+ //# sourceMappingURL=is-loopback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-loopback.d.ts","sourceRoot":"","sources":["../../../src/multiaddr/is-loopback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD;;GAEG;AACH,wBAAgB,UAAU,CAAE,EAAE,EAAE,SAAS,OAIxC"}
@@ -0,0 +1,10 @@
1
+ // @ts-expect-error is-loopback-addr does not publish types
2
+ import isLoopbackAddr from 'is-loopback-addr';
3
+ /**
4
+ * Check if a given multiaddr is a loopback address.
5
+ */
6
+ export function isLoopback(ma) {
7
+ const { address } = ma.nodeAddress();
8
+ return isLoopbackAddr(address);
9
+ }
10
+ //# sourceMappingURL=is-loopback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-loopback.js","sourceRoot":"","sources":["../../../src/multiaddr/is-loopback.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAG7C;;GAEG;AACH,MAAM,UAAU,UAAU,CAAE,EAAa;IACvC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;IAEpC,OAAO,cAAc,CAAC,OAAO,CAAC,CAAA;AAChC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Multiaddr } from '@multiformats/multiaddr';
2
+ /**
3
+ * Check if a given multiaddr has a private address.
4
+ */
5
+ export declare function isPrivate(ma: Multiaddr): boolean;
6
+ //# sourceMappingURL=is-private.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-private.d.ts","sourceRoot":"","sources":["../../../src/multiaddr/is-private.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAGxD;;GAEG;AACH,wBAAgB,SAAS,CAAE,EAAE,EAAE,SAAS,WAIvC"}
@@ -0,0 +1,9 @@
1
+ import isIpPrivate from 'private-ip';
2
+ /**
3
+ * Check if a given multiaddr has a private address.
4
+ */
5
+ export function isPrivate(ma) {
6
+ const { address } = ma.nodeAddress();
7
+ return Boolean(isIpPrivate(address));
8
+ }
9
+ //# sourceMappingURL=is-private.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-private.js","sourceRoot":"","sources":["../../../src/multiaddr/is-private.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,YAAY,CAAA;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAE,EAAa;IACtC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;IAEpC,OAAO,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAA;AACtC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { MuxedStream } from '@libp2p/interfaces/stream-muxer';
2
+ import type { Multiaddr } from '@multiformats/multiaddr';
3
+ import type { MultiaddrConnection } from '@libp2p/interfaces/transport';
4
+ /**
5
+ * @typedef {Object} Timeline
6
+ * @property {number} open -
7
+ * @property {number} [upgraded] - .
8
+ * @property {number} [close]
9
+ */
10
+ export interface Timeline {
11
+ /**
12
+ * Connection opening timestamp
13
+ */
14
+ open: number;
15
+ /**
16
+ * Connection upgraded timestamp
17
+ */
18
+ upgraded?: number;
19
+ /**
20
+ * Connection closed timestamp
21
+ */
22
+ close?: number;
23
+ }
24
+ interface StreamOptions {
25
+ signal?: AbortSignal;
26
+ }
27
+ interface StreamProperties {
28
+ stream: MuxedStream<Uint8Array>;
29
+ remoteAddr: Multiaddr;
30
+ localAddr: Multiaddr;
31
+ }
32
+ /**
33
+ * Convert a duplex iterable into a MultiaddrConnection.
34
+ * https://github.com/libp2p/interface-transport#multiaddrconnection
35
+ */
36
+ export declare function streamToMaConnection(props: StreamProperties, options?: StreamOptions): MultiaddrConnection<Uint8Array>;
37
+ export {};
38
+ //# sourceMappingURL=stream-to-ma-conn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-to-ma-conn.d.ts","sourceRoot":"","sources":["../../src/stream-to-ma-conn.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAIvE;;;;;GAKG;AAEH,MAAM,WAAW,QAAQ;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,WAAW,CAAA;CAErB;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,WAAW,CAAC,UAAU,CAAC,CAAA;IAC/B,UAAU,EAAE,SAAS,CAAA;IACrB,SAAS,EAAE,SAAS,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,GAAE,aAAkB,mCA4CzF"}
@@ -0,0 +1,51 @@
1
+ import { source as abortable } from 'abortable-iterator';
2
+ import debug from 'debug';
3
+ const log = debug('libp2p:stream:converter');
4
+ /**
5
+ * Convert a duplex iterable into a MultiaddrConnection.
6
+ * https://github.com/libp2p/interface-transport#multiaddrconnection
7
+ */
8
+ export function streamToMaConnection(props, options = {}) {
9
+ const { stream, remoteAddr, localAddr } = props;
10
+ const { sink, source } = stream;
11
+ const maConn = {
12
+ async sink(source) {
13
+ if (options.signal != null) {
14
+ source = abortable(source, options.signal);
15
+ }
16
+ try {
17
+ await sink(source);
18
+ await close();
19
+ }
20
+ catch (err) {
21
+ // If aborted we can safely ignore
22
+ if (err.type !== 'aborted') {
23
+ // If the source errored the socket will already have been destroyed by
24
+ // toIterable.duplex(). If the socket errored it will already be
25
+ // destroyed. There's nothing to do here except log the error & return.
26
+ log(err);
27
+ }
28
+ }
29
+ },
30
+ source: (options.signal != null) ? abortable(source, options.signal) : source,
31
+ conn: stream,
32
+ localAddr,
33
+ remoteAddr,
34
+ /** @type {Timeline} */
35
+ timeline: { open: Date.now(), close: undefined },
36
+ async close() {
37
+ await sink(async function* () {
38
+ yield new Uint8Array(0);
39
+ }());
40
+ await close();
41
+ }
42
+ };
43
+ async function close() {
44
+ if (maConn.timeline.close == null) {
45
+ maConn.timeline.close = Date.now();
46
+ }
47
+ return await Promise.resolve();
48
+ }
49
+ return maConn;
50
+ }
51
+ //# sourceMappingURL=stream-to-ma-conn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-to-ma-conn.js","sourceRoot":"","sources":["../../src/stream-to-ma-conn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,MAAM,GAAG,GAAG,KAAK,CAAC,yBAAyB,CAAC,CAAA;AAqC5C;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAE,KAAuB,EAAE,UAAyB,EAAE;IACxF,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IAC/C,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAC/B,MAAM,MAAM,GAAwB;QAClC,KAAK,CAAC,IAAI,CAAE,MAAM;YAChB,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE;gBAC1B,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;aAC3C;YAED,IAAI;gBACF,MAAM,IAAI,CAAC,MAAM,CAAC,CAAA;gBAClB,MAAM,KAAK,EAAE,CAAA;aACd;YAAC,OAAO,GAAQ,EAAE;gBACjB,kCAAkC;gBAClC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE;oBAC1B,uEAAuE;oBACvE,gEAAgE;oBAChE,uEAAuE;oBACvE,GAAG,CAAC,GAAG,CAAC,CAAA;iBACT;aACF;QACH,CAAC;QACD,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM;QAC7E,IAAI,EAAE,MAAM;QACZ,SAAS;QACT,UAAU;QACV,uBAAuB;QACvB,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;QAChD,KAAK,CAAC,KAAK;YACT,MAAM,IAAI,CAAC,KAAK,SAAU,CAAC;gBACzB,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;YACzB,CAAC,EAAE,CAAC,CAAA;YACJ,MAAM,KAAK,EAAE,CAAA;QACf,CAAC;KACF,CAAA;IAED,KAAK,UAAU,KAAK;QAClB,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,EAAE;YACjC,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;SACnC;QACD,OAAO,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;IAChC,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,91 @@
1
1
  {
2
2
  "name": "@libp2p/utils",
3
- "version": "0.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "license": "(Apache-2.0 OR MIT)"
3
+ "version": "1.0.0",
4
+ "description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem",
5
+ "leadMaintainer": "Vasco Santos <santos.vasco10@gmail.com>",
6
+ "type": "module",
7
+ "exports": {
8
+ "multiaddr/is-loopback": {
9
+ "import": "./dist/src/multiaddr/is-loopback.js",
10
+ "types": "./dist/src/multiaddr/is-loopback.d.ts"
11
+ },
12
+ "multiaddr/is-private": {
13
+ "import": "./dist/src/multiaddr/is-private.js",
14
+ "types": "./dist/src/multiaddr/is-private.d.ts"
15
+ },
16
+ "address-sort": {
17
+ "import": "./dist/src/address-sort.js",
18
+ "types": "./dist/src/address-sort.d.ts"
19
+ },
20
+ "array-equals": {
21
+ "import": "./dist/src/array-equals.js",
22
+ "types": "./dist/src/array-equals.d.ts"
23
+ },
24
+ "ip-port-to-multiaddr": {
25
+ "import": "./dist/src/ip-port-to-multiaddr.js",
26
+ "types": "./dist/src/ip-port-to-multiaddr.d.ts"
27
+ },
28
+ "stream-to-ma-conn": {
29
+ "import": "./dist/src/stream-to-ma-connr.js",
30
+ "types": "./dist/src/stream-to-ma-connr.d.ts"
31
+ }
32
+ },
33
+ "typesVersions": {
34
+ "*": {
35
+ "src/*": [
36
+ "dist/src/*",
37
+ "dist/src/*/index"
38
+ ]
39
+ }
40
+ },
41
+ "files": [
42
+ "src",
43
+ "dist/src"
44
+ ],
45
+ "scripts": {
46
+ "lint": "aegir lint",
47
+ "dep-check": "aegir dep-check dist/src/**/*.js dist/test/**/*.js",
48
+ "build": "tsc",
49
+ "pretest": "npm run build",
50
+ "test": "aegir test -f ./dist/test/**/*.js",
51
+ "test:chrome": "npm run test -- -t browser",
52
+ "test:chrome-webworker": "npm run test -- -t webworker",
53
+ "test:firefox": "npm run test -- -t browser -- --browser firefox",
54
+ "test:firefox-webworker": "npm run test -- -t webworker -- --browser firefox",
55
+ "test:node": "npm run test -- -t node --cov",
56
+ "test:electron-main": "npm run test -- -t electron-main",
57
+ "release": "semantic-release"
58
+ },
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/libp2p/js-libp2p-utils.git"
62
+ },
63
+ "license": "(Apache-2.0 OR MIT)",
64
+ "bugs": {
65
+ "url": "https://github.com/libp2p/js-libp2p-utils/issues"
66
+ },
67
+ "homepage": "https://github.com/libp2p/js-libp2p-utils#readme",
68
+ "devDependencies": {
69
+ "@libp2p/interfaces": "^0.2.0",
70
+ "@types/debug": "^4.1.5",
71
+ "aegir": "^36.1.2",
72
+ "it-pair": "^1.0.0",
73
+ "it-pipe": "^1.1.0",
74
+ "streaming-iterables": "^6.0.0",
75
+ "util": "^0.12.3"
76
+ },
77
+ "dependencies": {
78
+ "@achingbrain/ip-address": "^8.1.0",
79
+ "@multiformats/multiaddr": "^10.1.1",
80
+ "abortable-iterator": "^3.0.0",
81
+ "debug": "^4.3.0",
82
+ "err-code": "^3.0.1",
83
+ "is-loopback-addr": "^1.0.0",
84
+ "private-ip": "^2.1.1"
85
+ },
86
+ "contributors": [
87
+ "Vasco Santos <vasco.santos@moxy.studio>",
88
+ "Alex Potsides <alex@achingbrain.net>",
89
+ "Jacob Heun <jacobheun@gmail.com>"
90
+ ]
7
91
  }
@@ -0,0 +1,49 @@
1
+ import type { Multiaddr } from '@multiformats/multiaddr'
2
+ import { isPrivate } from './multiaddr/is-private.js'
3
+
4
+ interface Address {
5
+ multiaddr: Multiaddr
6
+ isCertified: boolean
7
+ }
8
+
9
+ /**
10
+ * @typedef {Object} Address
11
+ * @property {Multiaddr} multiaddr peer multiaddr.
12
+ * @property {boolean} isCertified obtained from a signed peer record.
13
+ */
14
+
15
+ /**
16
+ * Compare function for array.sort().
17
+ * This sort aims to move the private adresses to the end of the array.
18
+ * In case of equality, a certified address will come first.
19
+ *
20
+ * @param {Address} a
21
+ * @param {Address} b
22
+ * @returns {number}
23
+ */
24
+ function addressesPublicFirstCompareFunction (a: Address, b: Address) {
25
+ const isAPrivate = isPrivate(a.multiaddr)
26
+ const isBPrivate = isPrivate(b.multiaddr)
27
+
28
+ if (isAPrivate && !isBPrivate) {
29
+ return 1
30
+ } else if (!isAPrivate && isBPrivate) {
31
+ return -1
32
+ }
33
+ // Check certified?
34
+ if (a.isCertified && !b.isCertified) {
35
+ return -1
36
+ } else if (!a.isCertified && b.isCertified) {
37
+ return 1
38
+ }
39
+
40
+ return 0
41
+ }
42
+
43
+ /**
44
+ * Sort given addresses by putting public addresses first.
45
+ * In case of equality, a certified address will come first.
46
+ */
47
+ export function publicAddressesFirst (addresses: Address[]) {
48
+ return [...addresses].sort(addressesPublicFirstCompareFunction)
49
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Verify if two arrays of non primitive types with the "equals" function are equal.
3
+ * Compatible with multiaddr, peer-id and others.
4
+ */
5
+ export function arrayEquals (a: any[], b: any[]) {
6
+ const sort = (a: any, b: any) => a.toString().localeCompare(b.toString())
7
+ return a.length === b.length && b.sort(sort) && a.sort(sort).every((item, index) => b[index].equals(item))
8
+ }
@@ -0,0 +1,49 @@
1
+ import debug from 'debug'
2
+ import { Multiaddr } from '@multiformats/multiaddr'
3
+ import errCode from 'err-code'
4
+ import { Address4, Address6 } from '@achingbrain/ip-address'
5
+
6
+ const log = Object.assign(debug('libp2p:ip-port-to-multiaddr'), {
7
+ error: debug('libp2p:ip-port-to-multiaddr:err')
8
+ })
9
+
10
+ export const Errors = {
11
+ ERR_INVALID_IP_PARAMETER: 'ERR_INVALID_IP_PARAMETER',
12
+ ERR_INVALID_PORT_PARAMETER: 'ERR_INVALID_PORT_PARAMETER',
13
+ ERR_INVALID_IP: 'ERR_INVALID_IP'
14
+ }
15
+
16
+ /**
17
+ * Transform an IP, Port pair into a multiaddr
18
+ */
19
+ export function ipPortToMultiaddr (ip: string, port: number | string) {
20
+ if (typeof ip !== 'string') {
21
+ throw errCode(new Error(`invalid ip provided: ${ip}`), Errors.ERR_INVALID_IP_PARAMETER) // eslint-disable-line @typescript-eslint/restrict-template-expressions
22
+ }
23
+
24
+ if (typeof port === 'string') {
25
+ port = parseInt(port)
26
+ }
27
+
28
+ if (isNaN(port)) {
29
+ throw errCode(new Error(`invalid port provided: ${port}`), Errors.ERR_INVALID_PORT_PARAMETER)
30
+ }
31
+
32
+ try {
33
+ // Test valid IPv4
34
+ new Address4(ip) // eslint-disable-line no-new
35
+ return new Multiaddr(`/ip4/${ip}/tcp/${port}`)
36
+ } catch {}
37
+
38
+ try {
39
+ // Test valid IPv6
40
+ const ip6 = new Address6(ip)
41
+ return ip6.is4()
42
+ ? new Multiaddr(`/ip4/${ip6.to4().correctForm()}/tcp/${port}`)
43
+ : new Multiaddr(`/ip6/${ip}/tcp/${port}`)
44
+ } catch (err) {
45
+ const errMsg = `invalid ip:port for creating a multiaddr: ${ip}:${port}`
46
+ log.error(errMsg)
47
+ throw errCode(new Error(errMsg), Errors.ERR_INVALID_IP)
48
+ }
49
+ }
@@ -0,0 +1,12 @@
1
+ // @ts-expect-error is-loopback-addr does not publish types
2
+ import isLoopbackAddr from 'is-loopback-addr'
3
+ import type { Multiaddr } from '@multiformats/multiaddr'
4
+
5
+ /**
6
+ * Check if a given multiaddr is a loopback address.
7
+ */
8
+ export function isLoopback (ma: Multiaddr) {
9
+ const { address } = ma.nodeAddress()
10
+
11
+ return isLoopbackAddr(address)
12
+ }
@@ -0,0 +1,11 @@
1
+ import type { Multiaddr } from '@multiformats/multiaddr'
2
+ import isIpPrivate from 'private-ip'
3
+
4
+ /**
5
+ * Check if a given multiaddr has a private address.
6
+ */
7
+ export function isPrivate (ma: Multiaddr) {
8
+ const { address } = ma.nodeAddress()
9
+
10
+ return Boolean(isIpPrivate(address))
11
+ }
@@ -0,0 +1,92 @@
1
+ import { source as abortable } from 'abortable-iterator'
2
+ import debug from 'debug'
3
+ import type { MuxedStream } from '@libp2p/interfaces/stream-muxer'
4
+ import type { Multiaddr } from '@multiformats/multiaddr'
5
+ import type { MultiaddrConnection } from '@libp2p/interfaces/transport'
6
+
7
+ const log = debug('libp2p:stream:converter')
8
+
9
+ /**
10
+ * @typedef {Object} Timeline
11
+ * @property {number} open -
12
+ * @property {number} [upgraded] - .
13
+ * @property {number} [close]
14
+ */
15
+
16
+ export interface Timeline {
17
+ /**
18
+ * Connection opening timestamp
19
+ */
20
+ open: number
21
+
22
+ /**
23
+ * Connection upgraded timestamp
24
+ */
25
+ upgraded?: number
26
+
27
+ /**
28
+ * Connection closed timestamp
29
+ */
30
+ close?: number
31
+ }
32
+
33
+ interface StreamOptions {
34
+ signal?: AbortSignal
35
+
36
+ }
37
+
38
+ interface StreamProperties {
39
+ stream: MuxedStream<Uint8Array>
40
+ remoteAddr: Multiaddr
41
+ localAddr: Multiaddr
42
+ }
43
+
44
+ /**
45
+ * Convert a duplex iterable into a MultiaddrConnection.
46
+ * https://github.com/libp2p/interface-transport#multiaddrconnection
47
+ */
48
+ export function streamToMaConnection (props: StreamProperties, options: StreamOptions = {}) {
49
+ const { stream, remoteAddr, localAddr } = props
50
+ const { sink, source } = stream
51
+ const maConn: MultiaddrConnection = {
52
+ async sink (source) {
53
+ if (options.signal != null) {
54
+ source = abortable(source, options.signal)
55
+ }
56
+
57
+ try {
58
+ await sink(source)
59
+ await close()
60
+ } catch (err: any) {
61
+ // If aborted we can safely ignore
62
+ if (err.type !== 'aborted') {
63
+ // If the source errored the socket will already have been destroyed by
64
+ // toIterable.duplex(). If the socket errored it will already be
65
+ // destroyed. There's nothing to do here except log the error & return.
66
+ log(err)
67
+ }
68
+ }
69
+ },
70
+ source: (options.signal != null) ? abortable(source, options.signal) : source,
71
+ conn: stream,
72
+ localAddr,
73
+ remoteAddr,
74
+ /** @type {Timeline} */
75
+ timeline: { open: Date.now(), close: undefined },
76
+ async close () {
77
+ await sink(async function * () {
78
+ yield new Uint8Array(0)
79
+ }())
80
+ await close()
81
+ }
82
+ }
83
+
84
+ async function close () {
85
+ if (maConn.timeline.close == null) {
86
+ maConn.timeline.close = Date.now()
87
+ }
88
+ return await Promise.resolve()
89
+ }
90
+
91
+ return maConn
92
+ }