diff --git a/examples/dogfooding/index.html b/examples/dogfooding/index.html
index 4ca2627..3e9337a 100644
--- a/examples/dogfooding/index.html
+++ b/examples/dogfooding/index.html
@@ -1,51 +1,62 @@
-
+
-
-
+
+
+
+
+
+
+
+
+ Message Statistics
+
+
+ 0
+ Sent by Me
+
+
+ 0
+ Received (Mine)
+
+
+ 0
+ Received (Others)
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/examples/dogfooding/package-lock.json b/examples/dogfooding/package-lock.json
index 7024f66..66c2897 100644
--- a/examples/dogfooding/package-lock.json
+++ b/examples/dogfooding/package-lock.json
@@ -10,7 +10,7 @@
"dependencies": {
"@libp2p/crypto": "^5.0.5",
"@multiformats/multiaddr": "^12.3.1",
- "@waku/sdk": "0.0.30-0e49a1e.0",
+ "@waku/sdk": "0.0.32-16328a3.0",
"libp2p": "^2.1.10",
"protobufjs": "^7.3.0",
"uint8arrays": "^5.1.0"
@@ -35,9 +35,9 @@
"license": "Apache-2.0"
},
"node_modules/@chainsafe/as-sha256": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-1.0.1.tgz",
- "integrity": "sha512-4Y/kQm0LsJ6QRtGcMq6gOdQP+fZhWDfIV2eIqP6oFJZBWYGmdh3wm8YbrXDPLJO87X2Fu6koRLdUS00O3k14Hw==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.4.2.tgz",
+ "integrity": "sha512-HJ8GZBRjLeWtRsAXf3EbNsNzmTGpzTFjfpSf4yHkLYC+E52DhT6hwz+7qpj6I/EmFzSUm5tYYvT9K8GZokLQCQ==",
"license": "Apache-2.0"
},
"node_modules/@chainsafe/is-ip": {
@@ -47,20 +47,20 @@
"license": "MIT"
},
"node_modules/@chainsafe/libp2p-noise": {
- "version": "16.1.0",
- "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-16.1.0.tgz",
- "integrity": "sha512-GJA/i5pd6VmetxokvnPlEbVCeL7SfLHkSuUHwbJ4w0u7dZUbse4Hr8SA8RYGwNHbZr2TEKFC9WerhvMWbciIrQ==",
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-16.0.0.tgz",
+ "integrity": "sha512-8rqr8V1RD2/lVbfL0Bb//N8iPOFof11cUe8v8z8xJT7fUhCAbtCCSM4jbwI4HCnw0MvHLmcpmAfDCFRwcWzoeA==",
"license": "Apache-2.0 OR MIT",
"dependencies": {
"@chainsafe/as-chacha20poly1305": "^0.1.0",
- "@chainsafe/as-sha256": "^1.0.0",
+ "@chainsafe/as-sha256": "^0.4.1",
"@libp2p/crypto": "^5.0.0",
"@libp2p/interface": "^2.0.0",
"@libp2p/peer-id": "^5.0.0",
- "@noble/ciphers": "^1.1.3",
+ "@noble/ciphers": "^0.6.0",
"@noble/curves": "^1.1.0",
"@noble/hashes": "^1.3.1",
- "it-length-prefixed": "^10.0.1",
+ "it-length-prefixed": "^9.0.1",
"it-length-prefixed-stream": "^1.0.0",
"it-pair": "^2.0.6",
"it-pipe": "^3.0.1",
@@ -71,6 +71,23 @@
"wherearewe": "^2.0.1"
}
},
+ "node_modules/@chainsafe/libp2p-noise/node_modules/it-length-prefixed": {
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-9.1.1.tgz",
+ "integrity": "sha512-O88nBweT6M9ozsmok68/auKH7ik/slNM4pYbM9lrfy2z5QnpokW5SlrepHZDKtN71llhG2sZvd6uY4SAl+lAQg==",
+ "license": "Apache-2.0 OR MIT",
+ "dependencies": {
+ "it-reader": "^6.0.1",
+ "it-stream-types": "^2.0.1",
+ "uint8-varint": "^2.0.1",
+ "uint8arraylist": "^2.0.0",
+ "uint8arrays": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
"node_modules/@chainsafe/netmask": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz",
@@ -680,13 +697,10 @@
}
},
"node_modules/@noble/ciphers": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz",
- "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==",
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.6.0.tgz",
+ "integrity": "sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==",
"license": "MIT",
- "engines": {
- "node": "^14.21.3 || >=16"
- },
"funding": {
"url": "https://paulmillr.com/funding/"
}
@@ -719,9 +733,9 @@
}
},
"node_modules/@noble/secp256k1": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
- "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.2.tgz",
+ "integrity": "sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ==",
"funding": [
{
"type": "individual",
@@ -1513,16 +1527,16 @@
]
},
"node_modules/@waku/discovery": {
- "version": "0.0.7-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/discovery/-/discovery-0.0.7-0e49a1e.0.tgz",
- "integrity": "sha512-dHj/0w11V+Fkfl7T0MqJ9VEINAvuleU8vJ1hLifBbg7lbUWFe8b24qzPNzhqsxV93cLR+okhM7gj0N2yeVpaOQ==",
+ "version": "0.0.9-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/discovery/-/discovery-0.0.9-16328a3.0.tgz",
+ "integrity": "sha512-s3tQpF4t0G/Fa5BCwO+92vf9gPczaz3YIGhrctdU1SYoS5CHhQ0JZ44HKHv/nL+eIzRKwimiGAk3RjLW7Z9pIw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
- "@waku/core": "0.0.34-0e49a1e.0",
- "@waku/enr": "0.0.28-0e49a1e.0",
- "@waku/interfaces": "0.0.29-0e49a1e.0",
- "@waku/proto": "0.0.9-0e49a1e.0",
- "@waku/utils": "0.0.22-0e49a1e.0",
+ "@waku/core": "0.0.36-16328a3.0",
+ "@waku/enr": "0.0.30-16328a3.0",
+ "@waku/interfaces": "0.0.31-16328a3.0",
+ "@waku/proto": "0.0.11-16328a3.0",
+ "@waku/utils": "0.0.24-16328a3.0",
"debug": "^4.3.4",
"dns-over-http-resolver": "^3.0.8",
"hi-base32": "^0.5.1",
@@ -1533,16 +1547,16 @@
}
},
"node_modules/@waku/discovery/node_modules/@waku/core": {
- "version": "0.0.34-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.34-0e49a1e.0.tgz",
- "integrity": "sha512-kihMebnMzUnZXAwkAiya34jkcvogkRcszCzaIKO0m4StytKqLBmR1I5MmN9OcsFbygVeGMnax+8K+EHlemSOfg==",
+ "version": "0.0.36-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.36-16328a3.0.tgz",
+ "integrity": "sha512-+5GNNcy3FYnPKaL0RuJ01oo3+wMqkVhHPKdpRc3T0Rodi6IZsFCFdT1ob3A5rpFo5IURXqNjElUVBItIGrtupw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@libp2p/ping": "2.0.1",
- "@waku/enr": "0.0.28-0e49a1e.0",
- "@waku/interfaces": "0.0.29-0e49a1e.0",
- "@waku/proto": "0.0.9-0e49a1e.0",
- "@waku/utils": "0.0.22-0e49a1e.0",
+ "@waku/enr": "0.0.30-16328a3.0",
+ "@waku/interfaces": "0.0.31-16328a3.0",
+ "@waku/proto": "0.0.11-16328a3.0",
+ "@waku/utils": "0.0.24-16328a3.0",
"debug": "^4.3.4",
"it-all": "^3.0.4",
"it-length-prefixed": "^9.0.4",
@@ -1633,9 +1647,9 @@
}
},
"node_modules/@waku/enr": {
- "version": "0.0.28-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/enr/-/enr-0.0.28-0e49a1e.0.tgz",
- "integrity": "sha512-K9LcAf3c0pSfmVgx0I17V9wM7idAqu6VdlICrVcxL7ZVnIUPH+Skmk/S15LS9YigDwl283+hmwL8zO8P8inM+g==",
+ "version": "0.0.30-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/enr/-/enr-0.0.30-16328a3.0.tgz",
+ "integrity": "sha512-9D4WVJcuL/ncVsHb7KyeIkkDJia6UVdNK9Kf1u9BhvJBtzioPGgXrmp1O7CsXpIKVu4f8IVCu1Lc6hUVG84Chw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@ethersproject/rlp": "^5.7.0",
@@ -1643,7 +1657,7 @@
"@libp2p/peer-id": "^5.0.1",
"@multiformats/multiaddr": "^12.0.0",
"@noble/secp256k1": "^1.7.1",
- "@waku/utils": "0.0.22-0e49a1e.0",
+ "@waku/utils": "0.0.24-16328a3.0",
"debug": "^4.3.4",
"js-sha3": "^0.9.2"
},
@@ -1660,34 +1674,34 @@
}
},
"node_modules/@waku/interfaces": {
- "version": "0.0.29-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.29-0e49a1e.0.tgz",
- "integrity": "sha512-TaGr2cshZ2qmZsix+QNWwKFjefcOgXnBQk0P1RGE7lGo22KmxLqwwjeEMkmyud3El826Ukg6XprKliVGrceBzA==",
+ "version": "0.0.31-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.31-16328a3.0.tgz",
+ "integrity": "sha512-2jZCwBSBKd7PX12xJadMmxMpIKGR9SrQTnTqUfDD4aT72GQ9SpaqQDY5h+svMt/qjriZMBSUpITQQF04w0GIaw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
- "@waku/proto": "0.0.9-0e49a1e.0"
+ "@waku/proto": "0.0.11-16328a3.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@waku/message-hash": {
- "version": "0.1.18-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/message-hash/-/message-hash-0.1.18-0e49a1e.0.tgz",
- "integrity": "sha512-n3S8WOQhp8jj2hLUmRQ2LnJMpJb4E04ZrmknpJ6XIQru0pWq2LV2qqJe3+5RpvrM+JADc6HggmCjxYojW0EkZA==",
+ "version": "0.1.20-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/message-hash/-/message-hash-0.1.20-16328a3.0.tgz",
+ "integrity": "sha512-j1FHSgeJeKnc9Tet3/NcrNjOV1gKa6U3WXNe/uBRZsvn2P30Qg6a1Am2eMfxpmO3ggXz25ywe2WDNA/K4vk/RQ==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@noble/hashes": "^1.3.2",
- "@waku/utils": "0.0.22-0e49a1e.0"
+ "@waku/utils": "0.0.24-16328a3.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@waku/proto": {
- "version": "0.0.9-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/proto/-/proto-0.0.9-0e49a1e.0.tgz",
- "integrity": "sha512-rf82UD5KFobmGrsd/l5AFNACPcP9k0yEfq5eNgoOH5rGo/BFs9N5L7Wi9E+56b5hxPcA8b+2bpu1EGgQuDq2gw==",
+ "version": "0.0.11-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/proto/-/proto-0.0.11-16328a3.0.tgz",
+ "integrity": "sha512-yFGW6UaQC0MrffZV25uVDYC8sUxI6OpnizTfSyebLg84eihYHJyxTed7pD/EyjSl8vL9GFX8nDuksDbkIQ2OQw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"protons-runtime": "^5.4.0"
@@ -1697,24 +1711,24 @@
}
},
"node_modules/@waku/sdk": {
- "version": "0.0.30-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/sdk/-/sdk-0.0.30-0e49a1e.0.tgz",
- "integrity": "sha512-j6L+2idHmx0f5HUHtLW6uqc4F1/JSQKVsqL3Mqyh1OrwaYqKAfDqvOyJq8hb9auWRCOTHZs0Bs5g7iA99kti2Q==",
+ "version": "0.0.32-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/sdk/-/sdk-0.0.32-16328a3.0.tgz",
+ "integrity": "sha512-tHS2+lf7NMQekuxfrZOGsMWya35W8saxjMjPnIRE6FOq0Mlv1ADwso05W7iy9ExNJoFD3+4XVemDvc5RfIM75w==",
"license": "MIT OR Apache-2.0",
"dependencies": {
- "@chainsafe/libp2p-noise": "^16.0.0",
+ "@chainsafe/libp2p-noise": "16.0.0",
"@libp2p/bootstrap": "^11.0.1",
"@libp2p/identify": "^3.0.1",
"@libp2p/mplex": "^11.0.1",
"@libp2p/ping": "2.0.1",
"@libp2p/websockets": "^9.0.1",
"@noble/hashes": "^1.3.3",
- "@waku/core": "0.0.34-0e49a1e.0",
- "@waku/discovery": "0.0.7-0e49a1e.0",
- "@waku/interfaces": "0.0.29-0e49a1e.0",
- "@waku/message-hash": "0.1.18-0e49a1e.0",
- "@waku/proto": "0.0.9-0e49a1e.0",
- "@waku/utils": "0.0.22-0e49a1e.0",
+ "@waku/core": "0.0.36-16328a3.0",
+ "@waku/discovery": "0.0.9-16328a3.0",
+ "@waku/interfaces": "0.0.31-16328a3.0",
+ "@waku/message-hash": "0.1.20-16328a3.0",
+ "@waku/proto": "0.0.11-16328a3.0",
+ "@waku/utils": "0.0.24-16328a3.0",
"libp2p": "2.1.8"
},
"engines": {
@@ -1722,16 +1736,16 @@
}
},
"node_modules/@waku/sdk/node_modules/@waku/core": {
- "version": "0.0.34-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.34-0e49a1e.0.tgz",
- "integrity": "sha512-kihMebnMzUnZXAwkAiya34jkcvogkRcszCzaIKO0m4StytKqLBmR1I5MmN9OcsFbygVeGMnax+8K+EHlemSOfg==",
+ "version": "0.0.36-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.36-16328a3.0.tgz",
+ "integrity": "sha512-+5GNNcy3FYnPKaL0RuJ01oo3+wMqkVhHPKdpRc3T0Rodi6IZsFCFdT1ob3A5rpFo5IURXqNjElUVBItIGrtupw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@libp2p/ping": "2.0.1",
- "@waku/enr": "0.0.28-0e49a1e.0",
- "@waku/interfaces": "0.0.29-0e49a1e.0",
- "@waku/proto": "0.0.9-0e49a1e.0",
- "@waku/utils": "0.0.22-0e49a1e.0",
+ "@waku/enr": "0.0.30-16328a3.0",
+ "@waku/interfaces": "0.0.31-16328a3.0",
+ "@waku/proto": "0.0.11-16328a3.0",
+ "@waku/utils": "0.0.24-16328a3.0",
"debug": "^4.3.4",
"it-all": "^3.0.4",
"it-length-prefixed": "^9.0.4",
@@ -1820,13 +1834,13 @@
}
},
"node_modules/@waku/utils": {
- "version": "0.0.22-0e49a1e.0",
- "resolved": "https://registry.npmjs.org/@waku/utils/-/utils-0.0.22-0e49a1e.0.tgz",
- "integrity": "sha512-4aHZK5w4kGN1GgJMQOTwplwPIwiRefsDn2/bfcP87+EPGPw3toaDSWfOhWLvh2ZG1Zsk6k5eZmN4WF/oHx9NdA==",
+ "version": "0.0.24-16328a3.0",
+ "resolved": "https://registry.npmjs.org/@waku/utils/-/utils-0.0.24-16328a3.0.tgz",
+ "integrity": "sha512-zYNeWtRAYGJLVvE/8xnKmO5ctxuPD6/k9NAS/g3ES0o++kBrXNRFy3d1V1nKlnerwJuwYmB0RhfwFmz7ehtwWA==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@noble/hashes": "^1.3.2",
- "@waku/interfaces": "0.0.29-0e49a1e.0",
+ "@waku/interfaces": "0.0.31-16328a3.0",
"chai": "^4.3.10",
"debug": "^4.3.4",
"uint8arrays": "^5.0.1"
@@ -3283,9 +3297,9 @@
}
},
"node_modules/dns-over-http-resolver": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-3.0.10.tgz",
- "integrity": "sha512-l2kMOLxK6f9ll+5sf2Ndl8WS/2eXhOf9ZSXZMPnTVyHsv1ktN1WX3FwcyYklMq3ORv2N1nhf0TsGKWBjhgn0ug==",
+ "version": "3.0.15",
+ "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-3.0.15.tgz",
+ "integrity": "sha512-h2Ldu6b8LjW725Q5zjjv7T5s1K3dPjlU3DWvcEFqB3Ksb3QmqC4dHhPKlGlBS/1P47D4T5arZMiE4dD4OIfO6A==",
"license": "Apache-2.0 OR MIT",
"dependencies": {
"quick-lru": "^7.0.0",
@@ -5727,9 +5741,9 @@
}
},
"node_modules/it-first": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/it-first/-/it-first-3.0.7.tgz",
- "integrity": "sha512-e2dVSlOP+pAxPYPVJBF4fX7au8cvGfvLhIrGCMc5aWDnCvwgOo94xHbi3Da6eXQ2jPL5FGEM8sJMn5uE8Seu+g==",
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/it-first/-/it-first-3.0.8.tgz",
+ "integrity": "sha512-neaRRwOMCmMKkXJVZ4bvUDVlde+Xh0aTWr7hFaOZeDXzbctGVV/WHmPVqBqy3RjlsP7eRM0vcqNtlM8hivcmGw==",
"license": "Apache-2.0 OR MIT"
},
"node_modules/it-foreach": {
@@ -7185,9 +7199,9 @@
"license": "MIT"
},
"node_modules/quick-lru": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.0.tgz",
- "integrity": "sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.1.tgz",
+ "integrity": "sha512-kLjThirJMkWKutUKbZ8ViqFc09tDQhlbQo2MNuVeLWbRauqYP96Sm6nzlQ24F0HFjUNZ4i9+AgldJ9H6DZXi7g==",
"license": "MIT",
"engines": {
"node": ">=18"
diff --git a/examples/dogfooding/package.json b/examples/dogfooding/package.json
index df135bb..3605a4c 100644
--- a/examples/dogfooding/package.json
+++ b/examples/dogfooding/package.json
@@ -9,7 +9,7 @@
"dependencies": {
"@libp2p/crypto": "^5.0.5",
"@multiformats/multiaddr": "^12.3.1",
- "@waku/sdk": "0.0.30-0e49a1e.0",
+ "@waku/sdk": "0.0.32-16328a3.0",
"libp2p": "^2.1.10",
"protobufjs": "^7.3.0",
"uint8arrays": "^5.1.0"
diff --git a/examples/dogfooding/public/style.css b/examples/dogfooding/public/style.css
new file mode 100644
index 0000000..d10d7e8
--- /dev/null
+++ b/examples/dogfooding/public/style.css
@@ -0,0 +1,187 @@
+/* General Styles */
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+ margin: 0;
+ background-color: #f4f7f9;
+ color: #333;
+ line-height: 1.6;
+}
+
+.app-container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+header {
+ background-color: #2c3e50;
+ color: #ecf0f1;
+ padding: 20px;
+ border-radius: 8px;
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+header h1 {
+ margin: 0;
+ font-size: 1.8em;
+}
+
+.connection-status span {
+ font-size: 0.9em;
+}
+
+main {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 20px;
+}
+
+section {
+ background-color: #fff;
+ padding: 20px;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+h2 {
+ margin-top: 0;
+ color: #3498db;
+ border-bottom: 2px solid #ecf0f1;
+ padding-bottom: 10px;
+ margin-bottom: 15px;
+}
+
+/* Message Statistics */
+.stats-counters {
+ display: flex;
+ justify-content: space-around;
+ text-align: center;
+}
+
+.counter-value {
+ display: block;
+ font-size: 2em;
+ font-weight: bold;
+ color: #2980b9;
+}
+
+.counter-label {
+ font-size: 0.9em;
+ color: #555;
+}
+
+/* Message Controls */
+.btn {
+ padding: 10px 15px;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ font-size: 1em;
+ transition: background-color 0.3s ease;
+}
+
+.btn-primary {
+ background-color: #3498db;
+ color: white;
+}
+
+.btn-primary:hover {
+ background-color: #2980b9;
+}
+
+.search-container {
+ margin-top: 15px;
+ display: flex;
+ gap: 10px;
+}
+
+#searchInput {
+ flex-grow: 1;
+ padding: 10px;
+ border: 1px solid #ddd;
+ border-radius: 5px;
+ font-size: 0.9em;
+}
+
+/* Message Display */
+.message-list {
+ max-height: 400px;
+ overflow-y: auto;
+ border: 1px solid #ecf0f1;
+ border-radius: 5px;
+ padding: 10px;
+}
+
+.message-item {
+ padding: 10px;
+ margin-bottom: 8px;
+ border-radius: 4px;
+ background-color: #ecf0f1;
+ font-size: 0.9em;
+}
+
+.message-item.sent {
+ background-color: #eafaf1; /* Light green for sent */
+}
+
+.message-item.received-mine {
+ background-color: #e8f6fd; /* Light blue for received (mine) */
+}
+
+.message-item.received-other {
+ background-color: #fdf3e8; /* Light orange for received (other) */
+}
+
+.message-item p {
+ margin: 5px 0;
+}
+
+.message-item .timestamp {
+ font-size: 0.8em;
+ color: #7f8c8d;
+ text-align: right;
+}
+
+.message-item .content {
+ font-weight: 500;
+}
+
+.message-item .sender-info {
+ font-size: 0.8em;
+ color: #34495e;
+}
+
+/* Added style for Message ID */
+.message-item .message-id {
+ font-size: 0.75em;
+ color: #888;
+ margin-bottom: 3px;
+ word-break: break-all; /* Ensure long IDs don't break layout */
+}
+
+footer {
+ text-align: center;
+ margin-top: 30px;
+ padding-top: 15px;
+ border-top: 1px solid #ecf0f1;
+ font-size: 0.9em;
+ color: #7f8c8d;
+}
+
+/* Responsive Design */
+@media (min-width: 768px) {
+ main {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .message-stats, .message-controls {
+ grid-column: span 1;
+ }
+
+ .message-display {
+ grid-column: span 2;
+ }
+}
diff --git a/examples/dogfooding/src/index.ts b/examples/dogfooding/src/index.ts
index 4a2b773..e850495 100644
--- a/examples/dogfooding/src/index.ts
+++ b/examples/dogfooding/src/index.ts
@@ -1,176 +1,139 @@
import {
- createLightNode,
- createEncoder,
- createDecoder,
- DecodedMessage,
- LightNode,
- utils,
-} from "@waku/sdk";
-import { generateKeyPairFromSeed } from "@libp2p/crypto/keys";
-import { fromString } from "uint8arrays";
-
-import { Type, Field } from "protobufjs";
+ getWakuNode,
+ createWakuEncoder,
+ createWakuDecoder,
+ getPeerId
+} from "./waku-service";
+import { DecodedMessage } from "@waku/sdk";
import {
- generateRandomNumber,
- sha256,
-} from "./util";
+ encodeMessage,
+ decodeMessage,
+ ChatMessage,
+ ProtoChatMessage,
+} from "./message-service";
+import {
+ updatePeerIdDisplay,
+ incrementSentByMe,
+ incrementReceivedMine,
+ incrementReceivedOthers,
+ addMessageToLog,
+ renderMessages,
+ getSearchTerm,
+} from "./ui-manager";
-const DEFAULT_CONTENT_TOPIC = "/js-waku-examples/1/message-ratio/utf8";
+const NUM_MESSAGES_PER_BATCH = 5;
+let batchCounter = 0;
-const ProtoSequencedMessage = new Type("SequencedMessage")
- .add(new Field("hash", 1, "string"))
- .add(new Field("total", 2, "uint64"))
- .add(new Field("index", 3, "uint64"))
- .add(new Field("sender", 4, "string"));
+async function initializeApp() {
+ try {
+ console.log("Initializing Waku node...");
+ const node = await getWakuNode();
+ const currentPeerId = getPeerId();
+ console.log("Waku node initialized. Peer ID:", currentPeerId);
-const sequenceCompletedEvent = new CustomEvent("sequenceCompleted");
-
-async function wakuNode(): Promise
{
- let seed = localStorage.getItem("seed");
-
- if (!seed) {
- seed = (await sha256(generateRandomNumber())).slice(0, 32);
- localStorage.setItem("seed", seed);
- }
-
- const privateKey = await generateKeyPairFromSeed("Ed25519", fromString(seed));
-
- const node = await createLightNode({
- defaultBootstrap: false,
- networkConfig: {
- clusterId: 42,
- shards: [0]
- },
- numPeersToUse: 2,
- libp2p: {
- privateKey,
- },
- });
-
- (window as any).waku = node;
-
- await Promise.allSettled([
- node.dial("/dns4/waku-test.bloxy.one/tcp/8095/wss/p2p/16Uiu2HAmSZbDB7CusdRhgkD81VssRjQV5ZH13FbzCGcdnbbh6VwZ"),
- node.dial("/dns4/vps-aaa00d52.vps.ovh.ca/tcp/8000/wss/p2p/16Uiu2HAm9PftGgHZwWE3wzdMde4m3kT2eYJFXLZfGoSED3gysofk")
- ]);
-
- return node;
-}
-
-export async function app() {
- const node = await wakuNode();
-
- console.log("DEBUG: your peer ID is:", node.libp2p.peerId.toString());
-
- await node.start();
- await node.waitForPeers();
-
- const peerId = node.libp2p.peerId.toString();
- const encoder = createEncoder({
- contentTopic: DEFAULT_CONTENT_TOPIC,
- pubsubTopicShardInfo: {
- clusterId: 42,
- shard: 0,
+ if (currentPeerId) {
+ updatePeerIdDisplay(currentPeerId);
}
- });
- const startLightPushSequence = async (
- numMessages: number,
- period: number = 3000
- ) => {
- const sequenceHash = await sha256(generateRandomNumber());
- const sequenceTotal = numMessages;
- let sequenceIndex = 0;
+ const sendMessageBatch = async () => {
+ const encoder = createWakuEncoder();
+ batchCounter++;
+ console.log(`Sending batch C${batchCounter} of ${NUM_MESSAGES_PER_BATCH} messages...`);
+ for (let i = 0; i < NUM_MESSAGES_PER_BATCH; i++) {
+ const messageContent = `Batch ${batchCounter} - Msg ${i + 1} @ ${new Date().toLocaleTimeString()}`;
+ const payload = encodeMessage(messageContent);
- const sendMessage = async () => {
- try {
- const messageHash = await sha256(
- `${sequenceHash}-${sequenceIndex}-${sequenceTotal}`
- );
+ const tempDecodedMessage = ProtoChatMessage.decode(payload);
+ const messageId = (tempDecodedMessage as any).id || `temp-id-${Date.now()}`;
- const message = ProtoSequencedMessage.create({
- hash: messageHash,
- total: sequenceTotal,
- index: sequenceIndex,
- sender: peerId,
- });
- const payload = ProtoSequencedMessage.encode(message).finish();
+ const chatMessage: ChatMessage = {
+ id: messageId,
+ timestamp: Date.now(),
+ senderPeerId: currentPeerId || "unknown",
+ content: messageContent
+ };
- const result = await node.lightPush.send(
- encoder,
- {
+ try {
+ const result = await node.lightPush.send(encoder, {
payload,
- timestamp: new Date(),
- },
- { autoRetry: true }
- );
+ timestamp: new Date(chatMessage.timestamp),
+ }, { autoRetry: true });
- console.log("DEBUG: light push successes: ", result.successes.length);
- console.log(
- "DEBUG: light push failures: ",
- result.failures.length
- );
+ if (result.successes.length > 0) {
+ console.log(`Message ${i + 1} (ID: ${chatMessage.id}) sent successfully.`);
+ incrementSentByMe();
+ addMessageToLog(chatMessage, 'sent');
+ } else {
+ console.warn(`Failed to send message ${i + 1} (ID: ${chatMessage.id}):`, result.failures);
+ }
+ } catch (error) {
+ console.error(`Error sending message ${i + 1} (ID: ${chatMessage.id}):`, error);
+ }
+ await new Promise(resolve => setTimeout(resolve, 100));
+ }
+ console.log("Message batch sending complete.");
+ };
- // Increment sequence
- sequenceIndex++;
+ const subscribeToMessages = async () => {
+ const decoder = createWakuDecoder();
+ console.log("Subscribing to messages...");
+ await node.filter.subscribe(decoder, (wakuMessage: DecodedMessage) => {
+ console.log("Raw Waku message received, payload length:", wakuMessage.payload.length);
+ const chatMessage = decodeMessage(wakuMessage.payload);
- if (sequenceIndex < sequenceTotal) {
- setTimeout(sendMessage, period); // Schedule the next send
+ if (chatMessage) {
+ console.log("Decoded chat message:", chatMessage);
+ if (chatMessage.senderPeerId === currentPeerId) {
+ incrementReceivedMine();
+ console.log("Received own message (loopback):", chatMessage.id);
+ } else {
+ incrementReceivedOthers();
+ addMessageToLog(chatMessage, 'received-other');
+ console.log("Received message from other peer:", chatMessage.id);
+ }
} else {
- document.dispatchEvent(sequenceCompletedEvent);
+ console.warn("Could not decode received Waku message. Payload might be malformed or not a ChatMessage.");
}
-
- if ( result.successes.length > 0) {
- const messageElement = document.createElement("div");
- messageElement.textContent = messageHash;
-
- document.getElementById("messagesSent")?.appendChild(messageElement);
- }
- } catch (error) {
- console.error("DEBUG: Error sending message", error);
- }
+ });
+ console.log("Subscription active.");
};
- sendMessage(); // Start the recursive sending
- };
+ const sendMessageButton = document.getElementById("sendMessageButton");
+ if (sendMessageButton) {
+ sendMessageButton.addEventListener("click", () => {
+ console.log("Send Message Button clicked");
+ sendMessageBatch();
+ });
+ }
- const startFilterSubscription = async () => {
- const decoder = createDecoder(DEFAULT_CONTENT_TOPIC, { clusterId: 42, shard: 0 });
+ const searchButton = document.getElementById("searchButton");
+ if (searchButton) {
+ searchButton.addEventListener("click", () => {
+ console.log("Search button clicked");
+ renderMessages(getSearchTerm());
+ });
+ }
+
+ const searchInput = document.getElementById("searchInput");
+ if(searchInput) {
+ searchInput.addEventListener("input", () => {
+ console.log("Search input changed");
+ renderMessages(getSearchTerm());
+ });
+ }
- const subscriptionCallback = async (message: DecodedMessage) => {
- const decodedMessage: any = ProtoSequencedMessage.decode(
- message.payload
- );
+ await subscribeToMessages();
+
+ console.log("Application setup complete. Click 'Send New Message Batch' to send messages.");
- if (decodedMessage.sender === peerId) {
- return;
- }
-
- const messageElement = document.createElement("div");
- messageElement.textContent = decodedMessage.hash;
-
- document.getElementById("messagesReceived")?.appendChild(messageElement);
- };
-
- await node.nextFilter.subscribe(decoder, subscriptionCallback);
- await node.nextFilter.subscribe(decoder, subscriptionCallback);
- };
-
- return {
- node,
- startLightPushSequence,
- startFilterSubscription,
- };
+ } catch (error) {
+ console.error("Critical error during app initialization:", error);
+ const peerIdDisplayEl = document.getElementById("peerIdDisplay");
+ if(peerIdDisplayEl) peerIdDisplayEl.textContent = "Error connecting to Waku Network.";
+ }
}
-(async () => {
- const { startLightPushSequence, startFilterSubscription } = await app();
-
- startFilterSubscription();
-
- document.addEventListener(sequenceCompletedEvent.type, () =>
- startLightPushSequence(10, 3000)
- );
-
- startLightPushSequence(10, 3000);
-})();
+document.addEventListener("DOMContentLoaded", () => {
+ console.log("DOM fully loaded and parsed. Starting app initialization.");
+ initializeApp();
+});
diff --git a/examples/dogfooding/src/message-service.ts b/examples/dogfooding/src/message-service.ts
new file mode 100644
index 0000000..bc1539e
--- /dev/null
+++ b/examples/dogfooding/src/message-service.ts
@@ -0,0 +1,42 @@
+import { Type, Field } from "protobufjs";
+import { getPeerId } from "./waku-service";
+
+// New message structure with a unique ID and content for searchability
+export const ProtoChatMessage = new Type("ChatMessage")
+ .add(new Field("id", 1, "string")) // Unique message ID (e.g., UUID or timestamp-based)
+ .add(new Field("timestamp", 2, "uint64"))
+ .add(new Field("senderPeerId", 3, "string"))
+ .add(new Field("content", 4, "string")); // Actual message content
+
+export interface ChatMessage {
+ id: string;
+ timestamp: number;
+ senderPeerId: string;
+ content: string;
+}
+
+export function encodeMessage(content: string): Uint8Array {
+ const id = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
+ const message = ProtoChatMessage.create({
+ id,
+ timestamp: Date.now(),
+ senderPeerId: getPeerId() || "unknown",
+ content,
+ });
+ return ProtoChatMessage.encode(message).finish();
+}
+
+export function decodeMessage(payload: Uint8Array): ChatMessage | null {
+ try {
+ const decoded = ProtoChatMessage.decode(payload) as any;
+ return {
+ id: decoded.id,
+ timestamp: Number(decoded.timestamp),
+ senderPeerId: decoded.senderPeerId,
+ content: decoded.content,
+ };
+ } catch (error) {
+ console.error("Failed to decode message:", error);
+ return null;
+ }
+}
diff --git a/examples/dogfooding/src/ui-manager.ts b/examples/dogfooding/src/ui-manager.ts
new file mode 100644
index 0000000..4c0dcc0
--- /dev/null
+++ b/examples/dogfooding/src/ui-manager.ts
@@ -0,0 +1,105 @@
+import { ChatMessage } from "./message-service";
+
+const sentByMeCountEl = document.getElementById("sentByMeCount") as HTMLSpanElement;
+const receivedMineCountEl = document.getElementById("receivedMineCount") as HTMLSpanElement;
+const receivedOthersCountEl = document.getElementById("receivedOthersCount") as HTMLSpanElement;
+const peerIdDisplayEl = document.getElementById("peerIdDisplay") as HTMLSpanElement;
+const messageListEl = document.getElementById("messageList") as HTMLDivElement;
+const searchInputEl = document.getElementById("searchInput") as HTMLInputElement;
+
+let sentByMe = 0;
+let receivedMine = 0;
+let receivedOthers = 0;
+
+let currentMessages: ChatMessage[] = [];
+let currentPeerId: string | undefined;
+
+export function updatePeerIdDisplay(peerId: string) {
+ currentPeerId = peerId;
+ if (peerIdDisplayEl) {
+ peerIdDisplayEl.textContent = peerId;
+ }
+}
+
+export function incrementSentByMe() {
+ sentByMe++;
+ if (sentByMeCountEl) sentByMeCountEl.textContent = sentByMe.toString();
+}
+
+export function incrementReceivedMine() {
+ receivedMine++;
+ if (receivedMineCountEl) receivedMineCountEl.textContent = receivedMine.toString();
+}
+
+export function incrementReceivedOthers() {
+ receivedOthers++;
+ if (receivedOthersCountEl) receivedOthersCountEl.textContent = receivedOthers.toString();
+}
+
+export function addMessageToLog(message: ChatMessage, type: 'sent' | 'received-mine' | 'received-other') {
+ currentMessages.push(message);
+ renderMessages();
+}
+
+export function renderMessages(filterText?: string) {
+ if (!messageListEl) return;
+
+ messageListEl.innerHTML = "";
+
+ const messagesToRender = filterText
+ ? currentMessages.filter(msg => {
+ const searchTerm = filterText.toLowerCase();
+ return (
+ msg.content.toLowerCase().includes(searchTerm) ||
+ msg.id.toLowerCase().includes(searchTerm) ||
+ msg.senderPeerId.toLowerCase().includes(searchTerm)
+ );
+ })
+ : currentMessages;
+
+ messagesToRender.sort((a, b) => a.timestamp - b.timestamp);
+
+ messagesToRender.forEach(message => {
+ const item = document.createElement("div");
+ item.classList.add("message-item");
+
+ let typeClass = '';
+ let senderPrefix = '';
+
+ if (message.senderPeerId === currentPeerId) {
+ typeClass = 'sent';
+ senderPrefix = 'Me';
+ } else {
+ typeClass = 'received-other';
+ senderPrefix = `Other (${message.senderPeerId.substring(0, 6)}...)`;
+ }
+
+ item.classList.add(typeClass);
+
+ const idText = document.createElement("p");
+ idText.classList.add("message-id");
+ idText.textContent = `ID: ${message.id}`;
+
+ const contentP = document.createElement("p");
+ contentP.classList.add("content");
+ contentP.textContent = message.content;
+
+ const senderInfoP = document.createElement("p");
+ senderInfoP.classList.add("sender-info");
+ senderInfoP.textContent = `From: ${senderPrefix}`;
+
+ const timestampP = document.createElement("p");
+ timestampP.classList.add("timestamp");
+ timestampP.textContent = new Date(message.timestamp).toLocaleTimeString();
+
+ item.appendChild(idText);
+ item.appendChild(senderInfoP);
+ item.appendChild(contentP);
+ item.appendChild(timestampP);
+ messageListEl.appendChild(item);
+ });
+}
+
+export function getSearchTerm(): string {
+ return searchInputEl ? searchInputEl.value : "";
+}
diff --git a/examples/dogfooding/src/utils.ts b/examples/dogfooding/src/utils.ts
new file mode 100644
index 0000000..58c3e91
--- /dev/null
+++ b/examples/dogfooding/src/utils.ts
@@ -0,0 +1,12 @@
+export async function sha256(text: string): Promise {
+ const encoder = new TextEncoder();
+ const data = encoder.encode(text);
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
+ return hashHex;
+}
+
+export function generateRandomNumber(): string {
+ return Math.random().toString();
+}
diff --git a/examples/dogfooding/src/waku-service.ts b/examples/dogfooding/src/waku-service.ts
new file mode 100644
index 0000000..f2bf83a
--- /dev/null
+++ b/examples/dogfooding/src/waku-service.ts
@@ -0,0 +1,64 @@
+import { LightNode, createLightNode, createEncoder, createDecoder } from "@waku/sdk";
+import { generateKeyPairFromSeed } from "@libp2p/crypto/keys";
+import { fromString } from "uint8arrays";
+import { sha256, generateRandomNumber } from "./utils";
+
+export const DEFAULT_CONTENT_TOPIC = "/js-waku-examples/1/message-ratio/utf8";
+
+let wakuNodeInstance: LightNode | null = null;
+
+export async function getWakuNode(): Promise {
+ if (wakuNodeInstance) {
+ return wakuNodeInstance;
+ }
+
+ let seed = localStorage.getItem("seed");
+ if (!seed) {
+ seed = (await sha256(generateRandomNumber())).slice(0, 32);
+ localStorage.setItem("seed", seed);
+ }
+
+ const privateKey = await generateKeyPairFromSeed("Ed25519", fromString(seed));
+
+ const node = await createLightNode({
+ defaultBootstrap: false,
+ networkConfig: {
+ clusterId: 42,
+ shards: [0]
+ },
+ numPeersToUse: 2,
+ libp2p: {
+ privateKey,
+ },
+ });
+
+ await Promise.allSettled([
+ node.dial("/dns4/waku-test.bloxy.one/tcp/8095/wss/p2p/16Uiu2HAmSZbDB7CusdRhgkD81VssRjQV5ZH13FbzCGcdnbbh6VwZ"),
+ node.dial("/dns4/vps-aaa00d52.vps.ovh.ca/tcp/8000/wss/p2p/16Uiu2HAm9PftGgHZwWE3wzdMde4m3kT2eYJFXLZfGoSED3gysofk")
+ ]);
+
+ await node.start();
+ await node.waitForPeers();
+
+ wakuNodeInstance = node;
+ (window as any).waku = node;
+ return node;
+}
+
+export function getPeerId(): string | undefined {
+ return wakuNodeInstance?.libp2p.peerId.toString();
+}
+
+export function createWakuEncoder() {
+ return createEncoder({
+ contentTopic: DEFAULT_CONTENT_TOPIC,
+ pubsubTopicShardInfo: {
+ clusterId: 42,
+ shard: 0,
+ }
+ });
+}
+
+export function createWakuDecoder() {
+ return createDecoder(DEFAULT_CONTENT_TOPIC, { clusterId: 42, shard: 0 });
+}
diff --git a/examples/dogfooding/webpack.config.js b/examples/dogfooding/webpack.config.js
index 56eef45..bf4f56f 100644
--- a/examples/dogfooding/webpack.config.js
+++ b/examples/dogfooding/webpack.config.js
@@ -2,7 +2,7 @@ const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
module.exports = {
- entry: "./src/index.ts", // Changed from index.js to index.ts
+ entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "build"),
filename: "index.js",
@@ -11,12 +11,12 @@ module.exports = {
asyncWebAssembly: true,
},
resolve: {
- extensions: ['.ts', '.js'], // Add .ts to the extensions
+ extensions: ['.ts', '.js'],
},
module: {
rules: [
{
- test: /\.ts$/, // Add a rule for TypeScript files
+ test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/,
},
@@ -29,7 +29,13 @@ module.exports = {
},
plugins: [
new CopyWebpackPlugin({
- patterns: ["index.html", "favicon.ico", "favicon.png", "manifest.json"],
+ patterns: [
+ { from: "index.html", to: "index.html" },
+ { from: "public/style.css", to: "style.css" },
+ { from: "manifest.json", to: "manifest.json" },
+ { from: "favicon.ico", to: "favicon.ico" },
+ { from: "favicon.png", to: "favicon.png" },
+ ],
}),
],
};