diff --git a/.aegir.js b/.aegir.js index ab0e020c8c..9b5aefa98e 100644 --- a/.aegir.js +++ b/.aegir.js @@ -71,6 +71,7 @@ const after = (done) => { } module.exports = { + bundlesize: { maxSize: '215kB' }, hooks: { pre: before, post: after diff --git a/.travis.yml b/.travis.yml index 461d2aefc7..4b71d1a28d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ node_js: os: - linux - osx + script: npx nyc -s npm run test:node -- --bail after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov @@ -18,6 +19,7 @@ jobs: include: - stage: check script: + - npx aegir build --bundlesize - npx aegir commitlint --travis - npx aegir dep-check -- -i wrtc -i electron-webrtc - npm run lint diff --git a/README.md b/README.md index 2d07558882..afdcc98478 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,9 @@
-
-
+
+
+
diff --git a/package.json b/package.json
index d538271d75..e60cbbcf9c 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,6 @@
},
"homepage": "https://github.com/libp2p/js-libp2p",
"browser": {
- "joi": "joi-browser",
"./test/utils/bundle-nodejs": "./test/utils/bundle-browser"
},
"dependencies": {
@@ -43,23 +42,23 @@
"debug": "^4.1.0",
"err-code": "^1.1.2",
"fsm-event": "^2.1.0",
- "joi": "^14.0.6",
- "joi-browser": "^13.4.0",
+ "kind-of": "^6.0.2",
"libp2p-connection-manager": "~0.0.2",
- "libp2p-floodsub": "~0.15.1",
- "libp2p-ping": "~0.8.3",
- "libp2p-switch": "~0.41.3",
- "libp2p-websockets": "~0.12.0",
- "mafmt": "^6.0.2",
- "multiaddr": "^6.0.2",
+ "libp2p-floodsub": "~0.15.7",
+ "libp2p-ping": "~0.8.5",
+ "libp2p-switch": "~0.41.5",
+ "libp2p-websockets": "~0.12.1",
+ "mafmt": "^6.0.4",
+ "multiaddr": "^6.0.3",
"once": "^1.4.0",
- "peer-book": "~0.9.0",
- "peer-id": "~0.12.0",
- "peer-info": "~0.15.0"
+ "peer-book": "~0.9.1",
+ "peer-id": "~0.12.2",
+ "peer-info": "~0.15.1",
+ "superstruct": "~0.6.0"
},
"devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0",
- "aegir": "^18.1.0",
+ "aegir": "^18.2.0",
"chai": "^4.2.0",
"chai-checkmark": "^1.0.1",
"cids": "~0.5.5",
@@ -85,7 +84,7 @@
"pull-mplex": "~0.1.0",
"pull-serializer": "~0.3.2",
"pull-stream": "^3.6.9",
- "sinon": "^7.1.1",
+ "sinon": "^7.2.4",
"wrtc": "~0.3.2"
},
"contributors": [
diff --git a/src/config.js b/src/config.js
index aa38063b0f..0962784075 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,60 +1,89 @@
'use strict'
-const Joi = require('joi')
+const { struct, superstruct } = require('superstruct')
+const kind = require('kind-of')
+const { optional, list } = struct
-const ModuleSchema = Joi.alternatives().try(Joi.func(), Joi.object())
+const transports = ['tcp', 'utp', 'webrtcstar', 'webrtcdirect', 'websockets', 'websocketstar']
+// Define custom types
+const s = superstruct({
+ types: {
+ tcp: v => kind(v) === 'tcp',
+ utp: v => kind(v) === 'utp',
+ webrtcstar: v => kind(v) === 'webrtcstar',
+ webrtcdirect: v => kind(v) === 'webrtcdirect',
+ websockets: v => kind(v) === 'websockets',
+ websocketstar: v => kind(v) === 'websocketstar',
+ transport: value => {
+ const [error] = list([s.union([ ...transports, 'function' ])]).validate(value)
+ if (error) return error.message
-const OptionsSchema = Joi.object({
- // TODO: create proper validators for the generics
- connectionManager: Joi.object(),
- datastore: Joi.object(),
- peerInfo: Joi.object().required(),
- peerBook: Joi.object(),
- modules: Joi.object().keys({
- connEncryption: Joi.array().items(ModuleSchema).allow(null),
- connProtector: Joi.object().keys({
- protect: Joi.func().required()
- }).unknown(),
- contentRouting: Joi.array().items(Joi.object()).allow(null),
- dht: ModuleSchema.allow(null),
- peerDiscovery: Joi.array().items(ModuleSchema).allow(null),
- peerRouting: Joi.array().items(Joi.object()).allow(null),
- streamMuxer: Joi.array().items(ModuleSchema).allow(null),
- transport: Joi.array().items(ModuleSchema).min(1).required()
- }).required(),
- config: Joi.object().keys({
- peerDiscovery: Joi.object().allow(null),
- relay: Joi.object().keys({
- enabled: Joi.boolean().default(true),
- hop: Joi.object().keys({
- enabled: Joi.boolean().default(false),
- active: Joi.boolean().default(false)
- })
- }).default(),
- dht: Joi.object().keys({
- kBucketSize: Joi.number().default(20),
- enabled: Joi.boolean().default(true),
- randomWalk: Joi.object().keys({
- enabled: Joi.boolean().default(true),
- queriesPerPeriod: Joi.number().default(1),
- interval: Joi.number().default(30000),
- timeout: Joi.number().default(10000)
- }).default(),
- validators: Joi.object().allow(null),
- selectors: Joi.object().allow(null)
- }).default(),
- EXPERIMENTAL: Joi.object().keys({
- pubsub: Joi.boolean().default(false)
- }).default()
- }).default()
+ return value.length > 0
+ ? true
+ : 'You need to provide at least one transport.'
+ }
+ }
})
-module.exports.validate = (options) => {
- options = Joi.attempt(options, OptionsSchema)
+const optionsSchema = s(
+ {
+ connectionManager: 'object?',
+ datastore: 'object?',
+ peerInfo: 'object',
+ peerBook: 'object?',
+ modules: s({
+ connEncryption: optional(list([s('object|function')])),
+ // this is hacky to simulate optional because interface doesnt work correctly with it
+ // change to optional when fixed upstream
+ connProtector: s.union(['undefined', s.interface({ protect: 'function' })]),
+ contentRouting: optional(list(['object'])),
+ dht: optional(s('null|function|object')),
+ peerDiscovery: optional(list([s('object|function')])),
+ peerRouting: optional(list(['object'])),
+ streamMuxer: optional(list([s('object|function')])),
+ transport: 'transport'
+ }),
+ config: s({
+ peerDiscovery: 'object?',
+ relay: s({
+ enabled: 'boolean',
+ hop: optional(s({
+ enabled: 'boolean',
+ active: 'boolean'
+ },
+ { enabled: false, active: false }))
+ }, { enabled: true, hop: {} }),
+ dht: s({
+ kBucketSize: 'number',
+ enabled: 'boolean?',
+ randomWalk: optional(s({
+ enabled: 'boolean?',
+ queriesPerPeriod: 'number?',
+ interval: 'number?',
+ timeout: 'number?'
+ }, { enabled: true, queriesPerPeriod: 1, interval: 30000, timeout: 10000 })),
+ validators: 'object?',
+ selectors: 'object?'
+ }, { enabled: true, kBucketSize: 20, enabledDiscovery: true }),
+ EXPERIMENTAL: s({
+ pubsub: 'boolean'
+ }, { pubsub: false })
+ }, { relay: {}, dht: {}, EXPERIMENTAL: {} })
+ },
+ { config: {}, modules: {} }
+)
+
+module.exports.validate = (opts) => {
+ const [error, options] = optionsSchema.validate(opts)
- // Ensure dht is correct
- if (options.config.dht.enabled) {
- Joi.assert(options.modules.dht, ModuleSchema.required())
+ // Improve errors throwed, reduce stack by throwing here and add reason to the message
+ if (error) {
+ throw new Error(`${error.message}${error.reason ? ' - ' + error.reason : ''}`)
+ } else {
+ // Throw when dht is enabled but no dht module provided
+ if (options.config.dht.enabled) {
+ s('function|object')(options.modules.dht)
+ }
}
return options
diff --git a/test/config.spec.js b/test/config.spec.js
index b8c00f0881..0d429f8edd 100644
--- a/test/config.spec.js
+++ b/test/config.spec.js
@@ -104,7 +104,11 @@ describe('configuration', () => {
}
},
relay: {
- enabled: true
+ enabled: true,
+ hop: {
+ active: false,
+ enabled: false
+ }
}
}
}
@@ -185,7 +189,11 @@ describe('configuration', () => {
pubsub: false
},
relay: {
- enabled: true
+ enabled: true,
+ hop: {
+ active: false,
+ enabled: false
+ }
},
dht: {
kBucketSize: 20,