Merge pull request #860 from status-im/organize-modules

This commit is contained in:
fryorcraken.eth 2022-08-07 16:05:23 +10:00 committed by GitHub
commit b4e0fb59e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 610 additions and 466 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ coverage
*.log *.log
/tsconfig.tsbuildinfo /tsconfig.tsbuildinfo
/tsconfig.dev.tsbuildinfo /tsconfig.dev.tsbuildinfo
/bundle/

View File

@ -1,37 +1,40 @@
module.exports = [ module.exports = [
{ {
name: "Waku core", name: "Waku core",
path: "dist/bundle.min.js", path: "bundle/index.js",
import: "{ Waku }", import: "{ Waku }",
}, },
{ {
name: "Waku default setup", name: "Waku default setup",
path: "dist/bundle.min.js", path: ["bundle/index.js", "bundle/lib/create_waku.js"],
import: "{ createWaku, waitForRemotePeer }", import: {
"./bundle/lib/create_waku.js": "{ createWaku }",
"./bundle/index.js": "{ waitForRemotePeer }",
},
}, },
{ {
name: "Asymmetric, symmetric encryption and signature", name: "Asymmetric, symmetric encryption and signature",
path: "dist/bundle.min.js", path: "bundle/index.js",
import: "{ waku_message }", import: "{ WakuMessage }",
}, },
{ {
name: "DNS discovery", name: "DNS discovery",
path: "dist/bundle.min.js", path: "bundle/lib/peer_discovery_dns.js",
import: "{ discovery }", import: "{ PeerDiscoveryDns }",
}, },
{ {
name: "Privacy preserving protocols", name: "Privacy preserving protocols",
path: "dist/bundle.min.js", path: "bundle/index.js",
import: "{ WakuRelay }", import: "{ WakuRelay }",
}, },
{ {
name: "Light protocols", name: "Light protocols",
path: "dist/bundle.min.js", path: "bundle/index.js",
import: "{ WakuLightPush, WakuFilter }", import: "{ WakuLightPush, WakuFilter }",
}, },
{ {
name: "History retrieval protocols", name: "History retrieval protocols",
path: "dist/bundle.min.js", path: "bundle/index.js",
import: "{ WakuStore }", import: "{ WakuStore }",
}, },
]; ];

View File

@ -20,12 +20,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Examples: Updated store-js and relay-js to demonstrate usage of ESM bundle in `<script>` tag. - Examples: Updated store-js and relay-js to demonstrate usage of ESM bundle in `<script>` tag.
- Remove need to polyfill `buffer`. - Remove need to polyfill `buffer`.
- **breaking**: Various API changes. Refer to tests to check proper usage of the new API. - **breaking**: Various API changes. Refer to tests to check proper usage of the new API.
- **breaking**: `createWaku` is in separate exports path.
- **breaking**: Bootstrap class split: dns discovery, static list.
- **breaking**: bundled files are now under `bundle/`.
### Fix ### Fixed
- size-limit config to test several usages of Waku. - size-limit config to test several usages of Waku.
- `buffer` is not needed in the browser. - `buffer` is not needed in the browser.
### Removed
- `terser` minification and `gzip` compressions have been removed.
## [0.24.0] - 2022-05-27 ## [0.24.0] - 2022-05-27
### Added ### Added

View File

@ -27,10 +27,12 @@
*/ */
import { import {
createWaku,
waitForRemotePeer, waitForRemotePeer,
WakuMessage WakuMessage
} from '../../dist/bundle.js'; } from '../../bundle/index.js';
import {
createWaku,
} from '../../bundle/lib/create_waku.js';
const statusDiv = document.getElementById('status'); const statusDiv = document.getElementById('status');
const messagesDiv = document.getElementById('messages'); const messagesDiv = document.getElementById('messages');
@ -56,7 +58,7 @@
// We are currently working on migrating this method to DNS Discovery. // We are currently working on migrating this method to DNS Discovery.
// //
// https://js-waku.wakuconnect.dev/classes/waku.Waku.html#create // https://js-waku.wakuconnect.dev/classes/waku.Waku.html#create
const waku = await createWaku({ bootstrap: { default: true } }); const waku = await createWaku({ defaultBootstrap: true });
await waku.start(); await waku.start();
// Had a hook to process all incoming messages on a specified content topic. // Had a hook to process all incoming messages on a specified content topic.

View File

@ -14,10 +14,12 @@
<script type='module'> <script type='module'>
import { import {
createWaku,
waitForRemotePeer, waitForRemotePeer,
Protocols Protocols
} from '../../dist/bundle.min.js'; } from '../../bundle/index.js';
import {
createWaku,
} from '../../bundle/lib/create_waku.js';
/** /**
* This example demonstrates how to use the js-waku minified bundle * This example demonstrates how to use the js-waku minified bundle
@ -30,7 +32,7 @@
try { try {
timestampDiv.innerHTML = '<p>Creating waku.</p>'; timestampDiv.innerHTML = '<p>Creating waku.</p>';
const node = await createWaku({ bootstrap: { default: true } }); const node = await createWaku({ defaultBootstrap: true });
timestampDiv.innerHTML = '<p>Starting waku.</p>'; timestampDiv.innerHTML = '<p>Starting waku.</p>';
await node.start(); await node.start();

209
package-lock.json generated
View File

@ -83,7 +83,6 @@
"rollup": "^2.75.0", "rollup": "^2.75.0",
"size-limit": "^8.0.0", "size-limit": "^8.0.0",
"tail": "^2.2.0", "tail": "^2.2.0",
"terser": "^5.13.1",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",
"typedoc": "^0.22.10", "typedoc": "^0.22.10",
@ -798,6 +797,64 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true "dev": true
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.14",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@leichtgewicht/base64-codec": { "node_modules/@leichtgewicht/base64-codec": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz",
@ -7571,12 +7628,6 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"node_modules/lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@ -10568,14 +10619,14 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.13.1", "version": "5.14.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
"integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0", "acorn": "^8.5.0",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map": "~0.8.0-beta.0",
"source-map-support": "~0.5.20" "source-map-support": "~0.5.20"
}, },
"bin": { "bin": {
@ -10664,44 +10715,6 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"node_modules/terser/node_modules/source-map": {
"version": "0.8.0-beta.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
"integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
"dev": true,
"dependencies": {
"whatwg-url": "^7.0.0"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/terser/node_modules/tr46": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
"dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/terser/node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true
},
"node_modules/terser/node_modules/whatwg-url": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
"dev": true,
"dependencies": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
},
"node_modules/text-table": { "node_modules/text-table": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -12381,6 +12394,55 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true "dev": true
}, },
"@jridgewell/gen-mapping": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"dev": true
},
"@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true
},
"@jridgewell/source-map": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.14",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"@leichtgewicht/base64-codec": { "@leichtgewicht/base64-codec": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz",
@ -17593,12 +17655,6 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true "dev": true
}, },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
"log-symbols": { "log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@ -19794,14 +19850,14 @@
} }
}, },
"terser": { "terser": {
"version": "5.13.1", "version": "5.14.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
"integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0", "acorn": "^8.5.0",
"commander": "^2.20.0", "commander": "^2.20.0",
"source-map": "~0.8.0-beta.0",
"source-map-support": "~0.5.20" "source-map-support": "~0.5.20"
}, },
"dependencies": { "dependencies": {
@ -19810,41 +19866,6 @@
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
},
"source-map": {
"version": "0.8.0-beta.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
"integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
"dev": true,
"requires": {
"whatwg-url": "^7.0.0"
}
},
"tr46": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
},
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true
},
"whatwg-url": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
"dev": true,
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
} }
} }
}, },

View File

@ -8,6 +8,14 @@
".": { ".": {
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"import": "./dist/index.js" "import": "./dist/index.js"
},
"./lib/create_waku": {
"types": "./dist/lib/create_waku.d.ts",
"import": "./dist/lib/create_waku.js"
},
"./lib/peer_discovery_dns": {
"types": "./dist/lib/peer_discovery_dns/index.d.ts",
"import": "./dist/lib/peer_discovery_dns/index.js"
} }
}, },
"type": "module", "type": "module",
@ -25,8 +33,7 @@
"prepare": "husky install", "prepare": "husky install",
"build": "run-s build:**", "build": "run-s build:**",
"build:esm": "tsc && node build-scripts/fix-imports.js", "build:esm": "tsc && node build-scripts/fix-imports.js",
"build:bundle": "rollup --config rollup.config.js -- dist/index.js", "build:bundle": "rollup --config rollup.config.js",
"build:bundle:min": "terser --ecma 11 --compress --mangle -o dist/bundle.min.js -- dist/bundle.js && gzip -9 -c dist/bundle.min.js > dist/bundle.min.js.gz",
"size": "npm run build && size-limit", "size": "npm run build && size-limit",
"fix": "run-s fix:*", "fix": "run-s fix:*",
"fix:prettier": "prettier \"src/**/*.ts\" \"./*.json\" \"*.*js\" \".github/**/*.yml\" --write", "fix:prettier": "prettier \"src/**/*.ts\" \"./*.json\" \"*.*js\" \".github/**/*.yml\" --write",
@ -137,7 +144,6 @@
"rollup": "^2.75.0", "rollup": "^2.75.0",
"size-limit": "^8.0.0", "size-limit": "^8.0.0",
"tail": "^2.2.0", "tail": "^2.2.0",
"terser": "^5.13.1",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",
"typedoc": "^0.22.10", "typedoc": "^0.22.10",
@ -146,6 +152,7 @@
}, },
"files": [ "files": [
"dist", "dist",
"bundle",
"src/*.ts", "src/*.ts",
"src/lib/**/*.ts", "src/lib/**/*.ts",
"src/proto/**/*.ts", "src/proto/**/*.ts",

View File

@ -3,10 +3,14 @@ import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json"; import json from "@rollup/plugin-json";
export default { export default {
input: {
index: "dist/index.js",
"lib/create_waku": "dist/lib/create_waku.js",
"lib/peer_discovery_dns": "dist/lib/peer_discovery_dns/index.js",
},
output: { output: {
file: "dist/bundle.js", dir: "bundle",
format: "esm", format: "esm",
name: "waku",
}, },
plugins: [ plugins: [
commonjs(), commonjs(),

View File

@ -6,9 +6,6 @@ export {
getPublicKey, getPublicKey,
} from "./lib/crypto"; } from "./lib/crypto";
export { getPredefinedBootstrapNodes } from "./lib/discovery";
export * as discovery from "./lib/discovery";
export * as enr from "./lib/enr"; export * as enr from "./lib/enr";
export * as utils from "./lib/utils"; export * as utils from "./lib/utils";
@ -18,7 +15,7 @@ export { waitForRemotePeer } from "./lib/wait_for_remote_peer";
export * as proto_message from "./proto/message"; export * as proto_message from "./proto/message";
export * as waku from "./lib/waku"; export * as waku from "./lib/waku";
export { createWaku, Waku, Protocols } from "./lib/waku"; export { Waku, Protocols } from "./lib/waku";
export * as waku_message from "./lib/waku_message"; export * as waku_message from "./lib/waku_message";
export { WakuMessage } from "./lib/waku_message"; export { WakuMessage } from "./lib/waku_message";

90
src/lib/create_waku.ts Normal file
View File

@ -0,0 +1,90 @@
import { Noise } from "@chainsafe/libp2p-noise";
import type { PeerDiscovery } from "@libp2p/interface-peer-discovery";
import { Mplex } from "@libp2p/mplex";
import { WebSockets } from "@libp2p/websockets";
import { all as filterAll } from "@libp2p/websockets/filters";
import { createLibp2p, Libp2pOptions } from "libp2p";
import type { Libp2p } from "libp2p";
import { PeerDiscoveryStaticPeers } from "./peer_discovery_static_list";
import { getPredefinedBootstrapNodes } from "./predefined_bootstrap_nodes";
import { Waku, WakuOptions } from "./waku";
import { WakuFilter } from "./waku_filter";
import { WakuLightPush } from "./waku_light_push";
import { WakuRelay } from "./waku_relay";
import { WakuStore } from "./waku_store";
export interface CreateOptions {
/**
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
*
* One and only one pubsub topic is used by Waku. This is used by:
* - WakuRelay to receive, route and send messages,
* - WakuLightPush to send messages,
* - WakuStore to retrieve messages.
*
* The usage of the default pubsub topic is recommended.
* See [Waku v2 Topic Usage Recommendations](https://rfc.vac.dev/spec/23/) for details.
*
* @default {@link DefaultPubSubTopic}
*/
pubSubTopic?: string;
/**
* You can pass options to the `Libp2p` instance used by {@link Waku} using the {@link CreateOptions.libp2p} property.
* This property is the same type than the one passed to [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create)
* apart that we made the `modules` property optional and partial,
* allowing its omission and letting Waku set good defaults.
* Notes that some values are overridden by {@link Waku} to ensure it implements the Waku protocol.
*/
libp2p?: Partial<Libp2pOptions>;
/**
* Byte array used as key for the noise protocol used for connection encryption
* by [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create)
* This is only used for test purposes to not run out of entropy during CI runs.
*/
staticNoiseKey?: Uint8Array;
/**
* Use recommended bootstrap method to discovery and connect to new nodes.
*/
defaultBootstrap?: boolean;
}
export async function createWaku(
options?: CreateOptions & WakuOptions
): Promise<Waku> {
const libp2pOptions = options?.libp2p ?? {};
const peerDiscovery = libp2pOptions.peerDiscovery ?? [];
if (options?.defaultBootstrap) {
peerDiscovery.push(defaultPeerDiscovery());
Object.assign(libp2pOptions, { peerDiscovery });
}
const libp2p = await defaultLibp2p(new WakuRelay(options), libp2pOptions);
const wakuStore = new WakuStore(libp2p, options);
const wakuLightPush = new WakuLightPush(libp2p, options);
const wakuFilter = new WakuFilter(libp2p, options);
return new Waku(options ?? {}, libp2p, wakuStore, wakuLightPush, wakuFilter);
}
export function defaultPeerDiscovery(): PeerDiscovery {
return new PeerDiscoveryStaticPeers(getPredefinedBootstrapNodes());
}
export async function defaultLibp2p(
wakuRelay: WakuRelay,
options?: Partial<Libp2pOptions>
): Promise<Libp2p> {
const libp2pOpts = Object.assign(
{
transports: [new WebSockets({ filter: filterAll })],
streamMuxers: [new Mplex()],
connectionEncryption: [new Noise()],
},
{ pubsub: wakuRelay },
options ?? {}
);
return createLibp2p(libp2pOpts);
}

View File

@ -1,244 +0,0 @@
import type {
PeerDiscovery,
PeerDiscoveryEvents,
} from "@libp2p/interface-peer-discovery";
import { symbol } from "@libp2p/interface-peer-discovery";
import type { PeerInfo } from "@libp2p/interface-peer-info";
import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
import { peerIdFromString } from "@libp2p/peer-id";
import { Multiaddr } from "@multiformats/multiaddr";
import debug from "debug";
import { DnsNodeDiscovery, NodeCapabilityCount } from "./dns";
import { getPredefinedBootstrapNodes } from "./predefined";
import { getPseudoRandomSubset } from "./random_subset";
const log = debug("waku:discovery:bootstrap");
/**
* Setup discovery method used to bootstrap.
*
* Only one method is used. [[default]], [[peers]], [[getPeers]] and [[enrUrl]] options are mutually exclusive.
*/
export interface BootstrapOptions {
/**
* The maximum of peers to connect to as part of the bootstrap process.
* This only applies if [[peers]] or [[getPeers]] is used.
*
* @default [[Bootstrap.DefaultMaxPeers]]
*/
maxPeers?: number;
/**
* Use the default discovery method. Overrides all other options but `maxPeers`
*
* The default discovery method is likely to change overtime as new discovery
* methods are implemented.
*
* @default false
*/
default?: boolean;
/**
* Multiaddrs of peers to connect to.
*/
peers?: string[] | Multiaddr[];
/**
* Getter that retrieve multiaddrs of peers to connect to.
* will be called once.
*/
getPeers?: () => Promise<string[] | Multiaddr[]>;
/**
* The interval between emitting addresses in milliseconds.
* Used if [[peers]] is passed or a sync function is passed for [[getPeers]]
*/
interval?: number;
/**
* An EIP-1459 ENR Tree URL. For example:
* "enrtree://AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C@test.nodes.vac.dev"
*
* [[wantedNodeCapabilityCount]] MUST be passed when using this option.
*/
enrUrl?: string;
/**
* Specifies what node capabilities (protocol) must be returned.
* This only applies when [[enrUrl]] is passed (EIP-1459 DNS Discovery).
*/
wantedNodeCapabilityCount?: Partial<NodeCapabilityCount>;
}
/**
* Parse options and expose function to return bootstrap peer addresses.
*
* @throws if an invalid combination of options is passed, see [[BootstrapOptions]] for details.
*/
export class Bootstrap
extends EventEmitter<PeerDiscoveryEvents>
implements PeerDiscovery
{
static DefaultMaxPeers = 1;
private readonly asyncGetBootstrapPeers:
| (() => Promise<Multiaddr[]>)
| undefined;
private peers: PeerInfo[];
private timer?: ReturnType<typeof setInterval>;
private readonly interval: number;
constructor(opts?: BootstrapOptions) {
super();
opts = opts ?? {};
const methods = [
!!opts.default,
!!opts.peers,
!!opts.getPeers,
!!opts.enrUrl,
].filter((x) => x);
if (methods.length > 1) {
throw new Error(
"Bootstrap does not support several discovery methods (yet)"
);
}
this.interval = opts.interval ?? 10000;
opts.default =
opts.default ?? (!opts.peers && !opts.getPeers && !opts.enrUrl);
const maxPeers = opts.maxPeers ?? Bootstrap.DefaultMaxPeers;
this.peers = [];
if (opts.default) {
log("Use hosted list of peers.");
this.peers = multiaddrsToPeerInfo(
getPredefinedBootstrapNodes(undefined, maxPeers)
);
return;
}
if (!!opts.peers && opts.peers.length > 0) {
const allPeers: Multiaddr[] = opts.peers.map(
(node: string | Multiaddr) => {
if (typeof node === "string") {
return new Multiaddr(node);
} else {
return node;
}
}
);
this.peers = multiaddrsToPeerInfo(
getPseudoRandomSubset(allPeers, maxPeers)
);
log(
"Use provided list of peers (reduced to maxPeers)",
this.peers.map((ma) => ma.toString())
);
return;
}
if (typeof opts.getPeers === "function") {
log("Bootstrap: Use provided getPeers function.");
const getPeers = opts.getPeers;
this.asyncGetBootstrapPeers = async () => {
const allPeers = await getPeers();
return getPseudoRandomSubset<string | Multiaddr>(
allPeers,
maxPeers
).map((node) => new Multiaddr(node));
};
return;
}
if (opts.enrUrl) {
const wantedNodeCapabilityCount = opts.wantedNodeCapabilityCount;
if (!wantedNodeCapabilityCount)
throw "`wantedNodeCapabilityCount` must be defined when using `enrUrl`";
const enrUrl = opts.enrUrl;
log("Use provided EIP-1459 ENR Tree URL.");
const dns = DnsNodeDiscovery.dnsOverHttp();
this.asyncGetBootstrapPeers = async () => {
const enrs = await dns.getPeers([enrUrl], wantedNodeCapabilityCount);
log(`Found ${enrs.length} peers`);
return enrs.map((enr) => enr.getFullMultiaddrs()).flat();
};
return;
}
}
/**
* Start discovery process
*/
start(): void {
if (this.asyncGetBootstrapPeers) {
// TODO: This should emit the peer as they are discovered instead of having
// to wait for the full DNS discovery process to be done first.
// TODO: PeerInfo should be returned by discovery
this.asyncGetBootstrapPeers().then((peers) => {
this.peers = multiaddrsToPeerInfo(peers);
this._startTimer();
});
} else {
this._startTimer();
}
}
private _startTimer(): void {
if (this.peers) {
log("Starting bootstrap node discovery");
if (this.timer != null) {
return;
}
this.timer = setInterval(() => this._returnPeers(), this.interval);
this._returnPeers();
}
}
_returnPeers(): void {
if (this.timer == null) {
return;
}
this.peers.forEach((peerData) => {
this.dispatchEvent(
new CustomEvent<PeerInfo>("peer", { detail: peerData })
);
});
}
/**
* Stop emitting events
*/
stop(): void {
if (this.timer != null) {
clearInterval(this.timer);
}
this.timer = undefined;
}
get [symbol](): true {
return true;
}
get [Symbol.toStringTag](): string {
return "@waku/bootstrap";
}
}
function multiaddrsToPeerInfo(mas: Multiaddr[]): PeerInfo[] {
return mas
.map((ma) => {
const peerIdStr = ma.getPeerId();
const protocols: string[] = [];
return {
id: peerIdStr ? peerIdFromString(peerIdStr) : null,
multiaddrs: [ma.decapsulateCode(421)],
protocols,
};
})
.filter((peerInfo): peerInfo is PeerInfo => peerInfo.id !== null);
}

View File

@ -1,6 +0,0 @@
export { getPredefinedBootstrapNodes } from "./predefined";
export * as predefined from "./predefined";
export { Bootstrap, BootstrapOptions } from "./bootstrap";
export * as dns from "./dns";
export { DnsOverHttps } from "./dns_over_https";
export { ENRTree, ENRTreeValues, ENRRootValues } from "./enrtree";

View File

@ -1,8 +1,9 @@
import { expect } from "chai"; import { expect } from "chai";
import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils"; import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils";
import { createWaku } from "../create_waku";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { ENR } from "./enr"; import { ENR } from "./enr";

View File

@ -0,0 +1,17 @@
import { PeerInfo } from "@libp2p/interface-peer-info";
import { peerIdFromString } from "@libp2p/peer-id";
import { Multiaddr } from "@multiformats/multiaddr";
export function multiaddrsToPeerInfo(mas: Multiaddr[]): PeerInfo[] {
return mas
.map((ma) => {
const peerIdStr = ma.getPeerId();
const protocols: string[] = [];
return {
id: peerIdStr ? peerIdFromString(peerIdStr) : null,
multiaddrs: [ma.decapsulateCode(421)],
protocols,
};
})
.filter((peerInfo): peerInfo is PeerInfo => peerInfo.id !== null);
}

View File

@ -4,7 +4,10 @@ import { ENR } from "../enr";
import { DnsOverHttps } from "./dns_over_https"; import { DnsOverHttps } from "./dns_over_https";
import { ENRTree } from "./enrtree"; import { ENRTree } from "./enrtree";
import fetchNodesUntilCapabilitiesFulfilled from "./fetch_nodes"; import {
fetchNodesUntilCapabilitiesFulfilled,
yieldNodesUntilCapabilitiesFulfilled,
} from "./fetch_nodes";
const dbg = debug("waku:discovery:dns"); const dbg = debug("waku:discovery:dns");
@ -70,6 +73,30 @@ export class DnsNodeDiscovery {
this.dns = dns; this.dns = dns;
} }
/**
* {@docInherit getPeers}
*/
async *getNextPeer(
enrTreeUrls: string[],
wantedNodeCapabilityCount: Partial<NodeCapabilityCount>
): AsyncGenerator<ENR> {
const networkIndex = Math.floor(Math.random() * enrTreeUrls.length);
const { publicKey, domain } = ENRTree.parseTree(enrTreeUrls[networkIndex]);
const context: SearchContext = {
domain,
publicKey,
visits: {},
};
for await (const peer of yieldNodesUntilCapabilitiesFulfilled(
wantedNodeCapabilityCount,
this._errorTolerance,
() => this._search(domain, context)
)) {
yield peer;
}
}
/** /**
* Runs a recursive, randomized descent of the DNS tree to retrieve a single * Runs a recursive, randomized descent of the DNS tree to retrieve a single
* ENR record as an ENR. Returns null if parsing or DNS resolution fails. * ENR record as an ENR. Returns null if parsing or DNS resolution fails.

View File

@ -4,7 +4,7 @@ import { expect } from "chai";
import { ENR, Waku2 } from "../enr"; import { ENR, Waku2 } from "../enr";
import fetchNodesUntilCapabilitiesFulfilled from "./fetch_nodes"; import { fetchNodesUntilCapabilitiesFulfilled } from "./fetch_nodes";
async function createEnr(waku2: Waku2): Promise<ENR> { async function createEnr(waku2: Waku2): Promise<ENR> {
const peerId = await createSecp256k1PeerId(); const peerId = await createSecp256k1PeerId();

View File

@ -11,7 +11,7 @@ const dbg = debug("waku:discovery:fetch_nodes");
* fulfilled or the number of [[getNode]] call exceeds the sum of * fulfilled or the number of [[getNode]] call exceeds the sum of
* [[wantedNodeCapabilityCount]] plus [[errorTolerance]]. * [[wantedNodeCapabilityCount]] plus [[errorTolerance]].
*/ */
export default async function fetchNodesUntilCapabilitiesFulfilled( export async function fetchNodesUntilCapabilitiesFulfilled(
wantedNodeCapabilityCount: Partial<NodeCapabilityCount>, wantedNodeCapabilityCount: Partial<NodeCapabilityCount>,
errorTolerance: number, errorTolerance: number,
getNode: () => Promise<ENR | null> getNode: () => Promise<ENR | null>
@ -57,6 +57,56 @@ export default async function fetchNodesUntilCapabilitiesFulfilled(
return peers; return peers;
} }
/**
* Fetch nodes using passed [[getNode]] until all wanted capabilities are
* fulfilled or the number of [[getNode]] call exceeds the sum of
* [[wantedNodeCapabilityCount]] plus [[errorTolerance]].
*/
export async function* yieldNodesUntilCapabilitiesFulfilled(
wantedNodeCapabilityCount: Partial<NodeCapabilityCount>,
errorTolerance: number,
getNode: () => Promise<ENR | null>
): AsyncGenerator<ENR> {
const wanted = {
relay: wantedNodeCapabilityCount.relay ?? 0,
store: wantedNodeCapabilityCount.store ?? 0,
filter: wantedNodeCapabilityCount.filter ?? 0,
lightPush: wantedNodeCapabilityCount.lightPush ?? 0,
};
const maxSearches =
wanted.relay + wanted.store + wanted.filter + wanted.lightPush;
const actual = {
relay: 0,
store: 0,
filter: 0,
lightPush: 0,
};
let totalSearches = 0;
const peerNodeIds = new Set();
while (
!isSatisfied(wanted, actual) &&
totalSearches < maxSearches + errorTolerance
) {
const peer = await getNode();
if (peer && peer.nodeId && !peerNodeIds.has(peer.nodeId)) {
peerNodeIds.add(peer.nodeId);
// ENRs without a waku2 key are ignored.
if (peer.waku2) {
if (helpsSatisfyCapabilities(peer.waku2, wanted, actual)) {
addCapabilities(peer.waku2, actual);
yield peer;
}
}
dbg(`got new peer candidate from DNS address=${peer.nodeId}@${peer.ip}`);
}
totalSearches++;
}
}
function isSatisfied( function isSatisfied(
wanted: NodeCapabilityCount, wanted: NodeCapabilityCount,
actual: NodeCapabilityCount actual: NodeCapabilityCount

View File

@ -1,6 +1,6 @@
import { expect } from "chai"; import { expect } from "chai";
import { getPseudoRandomSubset } from "./random_subset"; import { getPseudoRandomSubset } from "../random_subset";
describe("Discovery", () => { describe("Discovery", () => {
it("returns all values when wanted number matches available values", function () { it("returns all values when wanted number matches available values", function () {

View File

@ -0,0 +1,84 @@
import type {
PeerDiscovery,
PeerDiscoveryEvents,
} from "@libp2p/interface-peer-discovery";
import { symbol } from "@libp2p/interface-peer-discovery";
import type { PeerInfo } from "@libp2p/interface-peer-info";
import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
import debug from "debug";
import { ENR } from "../enr";
import { multiaddrsToPeerInfo } from "../multiaddr_to_peer_info";
import { DnsNodeDiscovery, NodeCapabilityCount } from "./dns";
const log = debug("waku:peer-discovery-dns");
/**
* Parse options and expose function to return bootstrap peer addresses.
*
* @throws if an invalid combination of options is passed, see [[BootstrapOptions]] for details.
*/
export class PeerDiscoveryDns
extends EventEmitter<PeerDiscoveryEvents>
implements PeerDiscovery
{
private readonly nextPeer: () => AsyncGenerator<ENR>;
private _started: boolean;
/**
* @param enrUrl An EIP-1459 ENR Tree URL. For example:
* "enrtree://AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C@test.nodes.vac.dev"
* @param wantedNodeCapabilityCount Specifies what node capabilities
* (protocol) must be returned.
*/
constructor(
enrUrl: string,
wantedNodeCapabilityCount: Partial<NodeCapabilityCount>
) {
super();
this._started = false;
log("Use following EIP-1459 ENR Tree URL: ", enrUrl);
const dns = DnsNodeDiscovery.dnsOverHttp();
this.nextPeer = dns.getNextPeer.bind(
{},
[enrUrl],
wantedNodeCapabilityCount
);
}
/**
* Start discovery process
*/
async start(): Promise<void> {
log("Starting peer discovery via dns");
this._started = true;
for await (const peer of this.nextPeer()) {
if (!this._started) return;
const peerInfos = multiaddrsToPeerInfo(peer.getFullMultiaddrs());
peerInfos.forEach((peerInfo) => {
this.dispatchEvent(
new CustomEvent<PeerInfo>("peer", { detail: peerInfo })
);
});
}
}
/**
* Stop emitting events
*/
stop(): void {
this._started = false;
}
get [symbol](): true {
return true;
}
get [Symbol.toStringTag](): string {
return "@waku/bootstrap";
}
}

View File

@ -0,0 +1,119 @@
import type {
PeerDiscovery,
PeerDiscoveryEvents,
} from "@libp2p/interface-peer-discovery";
import { symbol } from "@libp2p/interface-peer-discovery";
import type { PeerInfo } from "@libp2p/interface-peer-info";
import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
import { Multiaddr } from "@multiformats/multiaddr";
import debug from "debug";
import { multiaddrsToPeerInfo } from "./multiaddr_to_peer_info";
import { getPseudoRandomSubset } from "./random_subset";
const log = debug("waku:peer-discovery-static-list");
export interface Options {
/**
* The maximum of peers to connect to as part of the bootstrap process.
*
* @default The length of the passed `peers` array.
*/
maxPeers?: number;
/**
* The interval between emitting addresses in milliseconds.
*
* @default {@link PeerDiscoveryEvents.DefaultInterval}
*/
interval?: number;
}
/**
* Parse options and expose function to return bootstrap peer addresses.
*
* @throws if an invalid combination of options is passed, see [[BootstrapOptions]] for details.
*/
export class PeerDiscoveryStaticPeers
extends EventEmitter<PeerDiscoveryEvents>
implements PeerDiscovery
{
static DefaultInterval = 200;
private readonly peers: PeerInfo[];
private timer?: ReturnType<typeof setInterval>;
private readonly interval: number;
/**
* @param peers Multiaddrs of peers to connect to.
* @param opts
*/
constructor(peers: string[] | Multiaddr[], opts?: Options) {
super();
this.interval = opts?.interval ?? PeerDiscoveryStaticPeers.DefaultInterval;
const maxPeers = opts?.maxPeers ?? peers?.length;
const peerMas = peers.map((peer: string | Multiaddr) => {
if (typeof peer === "string") {
return new Multiaddr(peer);
} else {
return peer;
}
});
this.peers = multiaddrsToPeerInfo(getPseudoRandomSubset(peerMas, maxPeers));
log(
"Use provided list of peers (reduced to maxPeers)",
this.peers.map((ma) => ma.toString())
);
}
/**
* Start emitting static peers.
*/
start(): void {
this._startTimer();
}
private _startTimer(): void {
if (this.peers) {
log("Starting to emit static peers.");
if (this.timer != null) {
return;
}
this.timer = setInterval(() => this._returnPeers(), this.interval);
this._returnPeers();
}
}
_returnPeers(): void {
if (this.timer == null) {
return;
}
this.peers.forEach((peerData) => {
this.dispatchEvent(
new CustomEvent<PeerInfo>("peer", { detail: peerData })
);
});
}
/**
* Stop emitting peers.
*/
stop(): void {
if (this.timer != null) {
clearInterval(this.timer);
}
this.timer = undefined;
}
get [symbol](): true {
return true;
}
get [Symbol.toStringTag](): string {
return "@waku/peer-discovery-static-list";
}
}

View File

@ -3,8 +3,9 @@ import { expect } from "chai";
import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../test_utils"; import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../test_utils";
import { delay } from "../test_utils/delay"; import { delay } from "../test_utils/delay";
import { createWaku } from "./create_waku";
import { waitForRemotePeer } from "./wait_for_remote_peer"; import { waitForRemotePeer } from "./wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "./waku"; import { Protocols, Waku } from "./waku";
describe("Wait for remote peer", function () { describe("Wait for remote peer", function () {
let waku: Waku; let waku: Waku;

View File

@ -22,7 +22,8 @@ interface WakuGossipSubProtocol extends GossipSub {
/** /**
* Wait for a remote peer to be ready given the passed protocols. * Wait for a remote peer to be ready given the passed protocols.
* Useful when using the [[CreateOptions.bootstrap]] with [[createWaku]]. * Must be used after attempting to connect to nodes, using {@link Waku.dial} or
* a bootstrap method with {@link Waku.constructor}.
* *
* If the passed protocols is a GossipSub protocol, then it resolves only once * If the passed protocols is a GossipSub protocol, then it resolves only once
* a peer is in a mesh, to help ensure that other peers will send and receive * a peer is in a mesh, to help ensure that other peers will send and receive

View File

@ -8,9 +8,11 @@ import {
Nwaku, Nwaku,
} from "../test_utils/"; } from "../test_utils/";
import { createWaku } from "./create_waku";
import { generateSymmetricKey } from "./crypto"; import { generateSymmetricKey } from "./crypto";
import { PeerDiscoveryStaticPeers } from "./peer_discovery_static_list";
import { waitForRemotePeer } from "./wait_for_remote_peer"; import { waitForRemotePeer } from "./wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "./waku"; import { Protocols, Waku } from "./waku";
import { WakuMessage } from "./waku_message"; import { WakuMessage } from "./waku_message";
const TestContentTopic = "/test/1/waku/utf8"; const TestContentTopic = "/test/1/waku/utf8";
@ -60,7 +62,9 @@ describe("Waku Dial [node only]", function () {
const multiAddrWithId = await nwaku.getMultiaddrWithId(); const multiAddrWithId = await nwaku.getMultiaddrWithId();
waku = await createWaku({ waku = await createWaku({
staticNoiseKey: NOISE_KEY_1, staticNoiseKey: NOISE_KEY_1,
bootstrap: { peers: [multiAddrWithId] }, libp2p: {
peerDiscovery: [new PeerDiscoveryStaticPeers([multiAddrWithId])],
},
}); });
await waku.start(); await waku.start();
@ -76,7 +80,7 @@ describe("Waku Dial [node only]", function () {
expect(connectedPeerID.toString()).to.eq(multiAddrWithId.getPeerId()); expect(connectedPeerID.toString()).to.eq(multiAddrWithId.getPeerId());
}); });
it("Passing a function", async function () { it("Using a function", async function () {
this.timeout(10_000); this.timeout(10_000);
nwaku = new Nwaku(makeLogFileName(this)); nwaku = new Nwaku(makeLogFileName(this));
@ -84,10 +88,10 @@ describe("Waku Dial [node only]", function () {
waku = await createWaku({ waku = await createWaku({
staticNoiseKey: NOISE_KEY_1, staticNoiseKey: NOISE_KEY_1,
bootstrap: { libp2p: {
getPeers: async () => { peerDiscovery: [
return [await nwaku.getMultiaddrWithId()]; new PeerDiscoveryStaticPeers([await nwaku.getMultiaddrWithId()]),
}, ],
}, },
}); });
await waku.start(); await waku.start();

View File

@ -1,7 +1,8 @@
import type { PeerId } from "@libp2p/interface-peer-id"; import type { PeerId } from "@libp2p/interface-peer-id";
import { expect } from "chai"; import { expect } from "chai";
import { createWaku, Waku } from "./waku"; import { createWaku } from "./create_waku";
import { Waku } from "./waku";
describe("Waku Dial", function () { describe("Waku Dial", function () {
describe("Bootstrap [live data]", function () { describe("Bootstrap [live data]", function () {
@ -23,7 +24,7 @@ describe("Waku Dial", function () {
this.timeout(20_000); this.timeout(20_000);
waku = await createWaku({ waku = await createWaku({
bootstrap: { default: true }, defaultBootstrap: true,
}); });
await waku.start(); await waku.start();

View File

@ -1,15 +1,11 @@
import { Noise } from "@chainsafe/libp2p-noise";
import type { Stream } from "@libp2p/interface-connection"; import type { Stream } from "@libp2p/interface-connection";
import type { PeerId } from "@libp2p/interface-peer-id"; import type { PeerId } from "@libp2p/interface-peer-id";
import { Mplex } from "@libp2p/mplex";
import { peerIdFromString } from "@libp2p/peer-id"; import { peerIdFromString } from "@libp2p/peer-id";
import { WebSockets } from "@libp2p/websockets"; import type { Multiaddr } from "@multiformats/multiaddr";
import { all as filterAll } from "@libp2p/websockets/filters"; import { multiaddr } from "@multiformats/multiaddr";
import { Multiaddr, multiaddr } from "@multiformats/multiaddr";
import debug from "debug"; import debug from "debug";
import { createLibp2p, Libp2p, Libp2pOptions } from "libp2p"; import type { Libp2p } from "libp2p";
import { Bootstrap, BootstrapOptions } from "./discovery";
import { FilterCodec, WakuFilter } from "./waku_filter"; import { FilterCodec, WakuFilter } from "./waku_filter";
import { LightPushCodec, WakuLightPush } from "./waku_light_push"; import { LightPushCodec, WakuLightPush } from "./waku_light_push";
import { DecryptionMethod, WakuMessage } from "./waku_message"; import { DecryptionMethod, WakuMessage } from "./waku_message";
@ -29,21 +25,7 @@ export enum Protocols {
Filter = "filter", Filter = "filter",
} }
export interface CreateOptions { export interface WakuOptions {
/**
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
*
* One and only one pubsub topic is used by Waku. This is used by:
* - WakuRelay to receive, route and send messages,
* - WakuLightPush to send messages,
* - WakuStore to retrieve messages.
*
* The usage of the default pubsub topic is recommended.
* See [Waku v2 Topic Usage Recommendations](https://rfc.vac.dev/spec/23/) for details.
*
* @default {@link DefaultPubSubTopic}
*/
pubSubTopic?: string;
/** /**
* Set keep alive frequency in seconds: Waku will send a `/ipfs/ping/1.0.0` * Set keep alive frequency in seconds: Waku will send a `/ipfs/ping/1.0.0`
* request to each peer after the set number of seconds. Set to 0 to disable. * request to each peer after the set number of seconds. Set to 0 to disable.
@ -58,58 +40,9 @@ export interface CreateOptions {
* @default {@link DefaultRelayKeepAliveValueSecs} * @default {@link DefaultRelayKeepAliveValueSecs}
*/ */
relayKeepAlive?: number; relayKeepAlive?: number;
/**
* You can pass options to the `Libp2p` instance used by {@link Waku} using the {@link CreateOptions.libp2p} property.
* This property is the same type than the one passed to [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create)
* apart that we made the `modules` property optional and partial,
* allowing its omission and letting Waku set good defaults.
* Notes that some values are overridden by {@link Waku} to ensure it implements the Waku protocol.
*/
libp2p?: Partial<Libp2pOptions>;
/**
* Byte array used as key for the noise protocol used for connection encryption
* by [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create)
* This is only used for test purposes to not run out of entropy during CI runs.
*/
staticNoiseKey?: Uint8Array;
/**
* Use libp2p-bootstrap to discover and connect to new nodes.
*
* See [[BootstrapOptions]] for available parameters.
*
* Note: It overrides any other peerDiscovery modules that may have been set via
* {@link CreateOptions.libp2p}.
*/
bootstrap?: BootstrapOptions;
decryptionKeys?: Array<Uint8Array | string>; decryptionKeys?: Array<Uint8Array | string>;
} }
export async function createWaku(options?: CreateOptions): Promise<Waku> {
const peerDiscovery = [];
if (options?.bootstrap) {
peerDiscovery.push(new Bootstrap(options?.bootstrap));
}
const libp2pOpts = Object.assign(
{
transports: [new WebSockets({ filter: filterAll })],
streamMuxers: [new Mplex()],
pubsub: new WakuRelay(options),
connectionEncryption: [new Noise()],
peerDiscovery: peerDiscovery,
},
options?.libp2p ?? {}
);
const libp2p = await createLibp2p(libp2pOpts);
const wakuStore = new WakuStore(libp2p, options);
const wakuLightPush = new WakuLightPush(libp2p, options);
const wakuFilter = new WakuFilter(libp2p, options);
return new Waku(options ?? {}, libp2p, wakuStore, wakuLightPush, wakuFilter);
}
export class Waku { export class Waku {
public libp2p: Libp2p; public libp2p: Libp2p;
public relay: WakuRelay; public relay: WakuRelay;
@ -125,7 +58,7 @@ export class Waku {
}; };
constructor( constructor(
options: CreateOptions, options: WakuOptions,
libp2p: Libp2p, libp2p: Libp2p,
store: WakuStore, store: WakuStore,
lightPush: WakuLightPush, lightPush: WakuLightPush,

View File

@ -3,8 +3,9 @@ import debug from "debug";
import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils"; import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils";
import { delay } from "../../test_utils/delay"; import { delay } from "../../test_utils/delay";
import { createWaku } from "../create_waku";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { WakuMessage } from "../waku_message"; import { WakuMessage } from "../waku_message";
const log = debug("waku:test"); const log = debug("waku:test");

View File

@ -3,8 +3,9 @@ import debug from "debug";
import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils"; import { makeLogFileName, NOISE_KEY_1, Nwaku } from "../../test_utils";
import { delay } from "../../test_utils/delay"; import { delay } from "../../test_utils/delay";
import { createWaku } from "../create_waku";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { WakuMessage } from "../waku_message"; import { WakuMessage } from "../waku_message";
const dbg = debug("waku:test:lightpush"); const dbg = debug("waku:test:lightpush");

View File

@ -8,6 +8,7 @@ import {
WakuRelayMessage, WakuRelayMessage,
} from "../../test_utils"; } from "../../test_utils";
import { delay } from "../../test_utils/delay"; import { delay } from "../../test_utils/delay";
import { createWaku } from "../create_waku";
import { import {
generatePrivateKey, generatePrivateKey,
generateSymmetricKey, generateSymmetricKey,
@ -15,7 +16,7 @@ import {
} from "../crypto"; } from "../crypto";
import { bytesToHex, bytesToUtf8, hexToBytes, utf8ToBytes } from "../utils"; import { bytesToHex, bytesToUtf8, hexToBytes, utf8ToBytes } from "../utils";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { DecryptionMethod, WakuMessage } from "./index"; import { DecryptionMethod, WakuMessage } from "./index";

View File

@ -11,13 +11,14 @@ import {
} from "../../test_utils"; } from "../../test_utils";
import { delay } from "../../test_utils/delay"; import { delay } from "../../test_utils/delay";
import { DefaultPubSubTopic } from "../constants"; import { DefaultPubSubTopic } from "../constants";
import { createWaku } from "../create_waku";
import { import {
generatePrivateKey, generatePrivateKey,
generateSymmetricKey, generateSymmetricKey,
getPublicKey, getPublicKey,
} from "../crypto"; } from "../crypto";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { DecryptionMethod, WakuMessage } from "../waku_message"; import { DecryptionMethod, WakuMessage } from "../waku_message";
const log = debug("waku:test"); const log = debug("waku:test");

View File

@ -12,13 +12,30 @@ import debug from "debug";
import { DefaultPubSubTopic } from "../constants"; import { DefaultPubSubTopic } from "../constants";
import { hexToBytes } from "../utils"; import { hexToBytes } from "../utils";
import { CreateOptions } from "../waku";
import { DecryptionMethod, WakuMessage } from "../waku_message"; import { DecryptionMethod, WakuMessage } from "../waku_message";
import * as constants from "./constants"; import * as constants from "./constants";
const dbg = debug("waku:relay"); const dbg = debug("waku:relay");
export interface CreateOptions {
/**
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
*
* One and only one pubsub topic is used by Waku. This is used by:
* - WakuRelay to receive, route and send messages,
* - WakuLightPush to send messages,
* - WakuStore to retrieve messages.
*
* The usage of the default pubsub topic is recommended.
* See [Waku v2 Topic Usage Recommendations](https://rfc.vac.dev/spec/23/) for details.
*
* @default {@link DefaultPubSubTopic}
*/
pubSubTopic?: string;
decryptionKeys?: Array<Uint8Array | string>;
}
/** /**
* Implements the [Waku v2 Relay protocol]{@link https://rfc.vac.dev/spec/11/}. * Implements the [Waku v2 Relay protocol]{@link https://rfc.vac.dev/spec/11/}.
* Must be passed as a `pubsub` module to a {Libp2p} instance. * Must be passed as a `pubsub` module to a {Libp2p} instance.

View File

@ -7,13 +7,14 @@ import {
NOISE_KEY_2, NOISE_KEY_2,
Nwaku, Nwaku,
} from "../../test_utils"; } from "../../test_utils";
import { createWaku } from "../create_waku";
import { import {
generatePrivateKey, generatePrivateKey,
generateSymmetricKey, generateSymmetricKey,
getPublicKey, getPublicKey,
} from "../crypto"; } from "../crypto";
import { waitForRemotePeer } from "../wait_for_remote_peer"; import { waitForRemotePeer } from "../wait_for_remote_peer";
import { createWaku, Protocols, Waku } from "../waku"; import { Protocols, Waku } from "../waku";
import { DecryptionMethod, WakuMessage } from "../waku_message"; import { DecryptionMethod, WakuMessage } from "../waku_message";
import { PageDirection } from "./history_rpc"; import { PageDirection } from "./history_rpc";

View File

@ -10,7 +10,7 @@
"sourceMap": true, "sourceMap": true,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"resolveJsonModule": true /* Include modules imported with .json extension. */, "resolveJsonModule": true /* Include modules imported with .json extension. */,
"tsBuildInfoFile": "dist/.tsbuildinfo",
"strict": true /* Enable all strict type-checking options. */, "strict": true /* Enable all strict type-checking options. */,
/* Strict Type-Checking Options */ /* Strict Type-Checking Options */

View File

@ -1,5 +1,5 @@
{ {
"entryPoints": ["./src/index.ts"], "entryPoints": ["./src/index.ts", "./src/lib/create_waku.ts"],
"out": "build/docs", "out": "build/docs",
"exclude": "**/*.spec.ts", "exclude": "**/*.spec.ts",
"excludeInternal": true, "excludeInternal": true,