mirror of
https://github.com/logos-messaging/examples.waku.org.git
synced 2026-01-04 05:43:07 +00:00
commit
fcad46760c
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -17,7 +17,8 @@ jobs:
|
|||||||
relay-angular-chat,
|
relay-angular-chat,
|
||||||
relay-reactjs-chat,
|
relay-reactjs-chat,
|
||||||
store-reactjs-chat,
|
store-reactjs-chat,
|
||||||
web-chat
|
web-chat,
|
||||||
|
noise-js
|
||||||
]
|
]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
1
ci/Jenkinsfile
vendored
1
ci/Jenkinsfile
vendored
@ -39,6 +39,7 @@ pipeline {
|
|||||||
stage('relay-reactjs-chat') { steps { script { buildExample() } } }
|
stage('relay-reactjs-chat') { steps { script { buildExample() } } }
|
||||||
stage('store-reactjs-chat') { steps { script { buildExample() } } }
|
stage('store-reactjs-chat') { steps { script { buildExample() } } }
|
||||||
stage('web-chat') { steps { script { buildExample() } } }
|
stage('web-chat') { steps { script { buildExample() } } }
|
||||||
|
stage('noise-js') { steps { script { buildExample() } } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
examples/noise-js/README.md
Normal file
7
examples/noise-js/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Waku Noise Pairing Example App
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
Browse to http://localhost:8080
|
||||||
BIN
examples/noise-js/favicon.ico
Normal file
BIN
examples/noise-js/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
examples/noise-js/favicon.png
Normal file
BIN
examples/noise-js/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
191
examples/noise-js/index.html
Normal file
191
examples/noise-js/index.html
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
|
<title>Waku Noise</title>
|
||||||
|
<link rel="apple-touch-icon" href="./favicon.png" />
|
||||||
|
<link rel="manifest" href="./manifest.json" />
|
||||||
|
<link rel="icon" href="./favicon.ico" />
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
word-wrap: break-word;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 800px;
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 800px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3:last-of-type {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 span,
|
||||||
|
h3 span {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
color: #9ea13b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
color: #3ba183;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #c84740;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.progress {
|
||||||
|
color: white;
|
||||||
|
background-color: #9ea13b;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.success {
|
||||||
|
color: white;
|
||||||
|
background-color: #3ba183;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.error {
|
||||||
|
color: white;
|
||||||
|
background-color: #c84740;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pairingInfo {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pairingInfo input {
|
||||||
|
display: block;
|
||||||
|
min-width: 250px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
padding: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pairingInfo button {
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pairingInfo button + button {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatArea {
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatArea ul {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatArea ul li + li {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatArea div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatArea div > * {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
padding: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="status">
|
||||||
|
<h3>
|
||||||
|
<b>Waku Node Status:</b> <span id="waku-status">connecting...</span>
|
||||||
|
</h3>
|
||||||
|
<h3 id="handshake-span">
|
||||||
|
<b>Handshake Status:</b>
|
||||||
|
<span id="handshake-status" class="progress">waiting for waku</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pairingInfo" id="qr-url-container" style="display: none">
|
||||||
|
<h2>Pairing information</h2>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="qr-url"
|
||||||
|
readonly
|
||||||
|
placeholder="generating URL..."
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<button id="copy-url" style="width: 100px">Copy URL</button>
|
||||||
|
<button id="open-tab" style="width: 150px">Open in new tab</button>
|
||||||
|
</div>
|
||||||
|
<canvas id="qr-canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chatArea" id="chat-area" style="display: none">
|
||||||
|
<h2>Chat</h2>
|
||||||
|
<ul id="messages"></ul>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input id="nick-input" placeholder="Choose a nickname" type="text" />
|
||||||
|
<textarea
|
||||||
|
id="text-input"
|
||||||
|
placeholder="Type your message here"
|
||||||
|
type="text"
|
||||||
|
></textarea>
|
||||||
|
<button id="send-btn" type="button" disabled>Send message</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
341
examples/noise-js/index.js
Normal file
341
examples/noise-js/index.js
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
import { createLightNode } from "js-waku/lib/create_waku";
|
||||||
|
import { utils } from "js-waku";
|
||||||
|
import { waitForRemotePeer } from "js-waku/lib/wait_for_remote_peer";
|
||||||
|
import {
|
||||||
|
Fleet,
|
||||||
|
getPredefinedBootstrapNodes,
|
||||||
|
} from "js-waku/lib/predefined_bootstrap_nodes";
|
||||||
|
import { PeerDiscoveryStaticPeers } from "js-waku/lib/peer_discovery_static_list";
|
||||||
|
import { Protocols } from "js-waku";
|
||||||
|
import * as noise from "@waku/noise";
|
||||||
|
import protobuf from "protobufjs";
|
||||||
|
import QRCode from "qrcode";
|
||||||
|
|
||||||
|
// Protobuf
|
||||||
|
const ProtoChatMessage = new protobuf.Type("ChatMessage")
|
||||||
|
.add(new protobuf.Field("timestamp", 1, "uint64"))
|
||||||
|
.add(new protobuf.Field("nick", 2, "string"))
|
||||||
|
.add(new protobuf.Field("text", 3, "bytes"));
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const ui = initUI();
|
||||||
|
ui.waku.connecting();
|
||||||
|
|
||||||
|
// Starting the node
|
||||||
|
const node = await createLightNode({
|
||||||
|
defaultBootstrap: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await node.start();
|
||||||
|
await waitForRemotePeer(node, [Protocols.Filter, Protocols.LightPush]);
|
||||||
|
|
||||||
|
ui.waku.connected();
|
||||||
|
|
||||||
|
const [sender, responder] = getSenderAndResponder(node);
|
||||||
|
const myStaticKey = noise.generateX25519KeyPair();
|
||||||
|
const urlPairingInfo = getPairingInfoFromURL();
|
||||||
|
|
||||||
|
const pairingObj = new noise.WakuPairing(
|
||||||
|
sender,
|
||||||
|
responder,
|
||||||
|
myStaticKey,
|
||||||
|
urlPairingInfo || new noise.ResponderParameters()
|
||||||
|
);
|
||||||
|
const pExecute = pairingObj.execute(120000); // timeout after 2m
|
||||||
|
|
||||||
|
scheduleHandshakeAuthConfirmation(pairingObj, ui);
|
||||||
|
|
||||||
|
let encoder;
|
||||||
|
let decoder;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ui.handshake.waiting();
|
||||||
|
|
||||||
|
if (!urlPairingInfo) {
|
||||||
|
const pairingURL = buildPairingURLFromObj(pairingObj);
|
||||||
|
ui.shareInfo.setURL(pairingURL);
|
||||||
|
ui.shareInfo.renderQR(pairingURL);
|
||||||
|
ui.shareInfo.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
[encoder, decoder] = await pExecute;
|
||||||
|
|
||||||
|
ui.handshake.connected();
|
||||||
|
ui.shareInfo.hide();
|
||||||
|
} catch (err) {
|
||||||
|
ui.handshake.error(err.message);
|
||||||
|
ui.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.message.display();
|
||||||
|
|
||||||
|
await node.filter.subscribe(
|
||||||
|
[decoder],
|
||||||
|
ui.message.onReceive.bind(ui.message)
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.message.onSend(async (text, nick) => {
|
||||||
|
const timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
const message = ProtoChatMessage.create({
|
||||||
|
nick,
|
||||||
|
timestamp,
|
||||||
|
text: utils.utf8ToBytes(text),
|
||||||
|
});
|
||||||
|
const payload = ProtoChatMessage.encode(message).finish();
|
||||||
|
|
||||||
|
await node.lightPush.push(encoder, { payload, timestamp });
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
ui.waku.error(err.message);
|
||||||
|
ui.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPairingURLFromObj(pairingObj) {
|
||||||
|
const pInfo = pairingObj.getPairingInfo();
|
||||||
|
|
||||||
|
// Data to encode in the QR code. The qrMessageNametag too to the QR string (separated by )
|
||||||
|
const messageNameTagParam = `messageNameTag=${utils.bytesToHex(
|
||||||
|
pInfo.qrMessageNameTag
|
||||||
|
)}`;
|
||||||
|
const qrCodeParam = `qrCode=${encodeURIComponent(pInfo.qrCode)}`;
|
||||||
|
|
||||||
|
return `${window.location.href}?${messageNameTagParam}&${qrCodeParam}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPairingInfoFromURL() {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
const messageNameTag = urlParams.get("messageNameTag");
|
||||||
|
const qrCodeString = urlParams.get("qrCode");
|
||||||
|
|
||||||
|
if (!(messageNameTag && qrCodeString)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new noise.InitiatorParameters(
|
||||||
|
decodeURIComponent(qrCodeString),
|
||||||
|
utils.hexToBytes(messageNameTag)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSenderAndResponder(node) {
|
||||||
|
const sender = {
|
||||||
|
async publish(encoder, msg) {
|
||||||
|
await node.lightPush.push(encoder, msg);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const msgQueue = new Array();
|
||||||
|
const subscriptions = new Map();
|
||||||
|
const intervals = new Map();
|
||||||
|
|
||||||
|
const responder = {
|
||||||
|
async subscribe(decoder) {
|
||||||
|
const subscription = await node.filter.subscribe(
|
||||||
|
[decoder],
|
||||||
|
(wakuMessage) => {
|
||||||
|
msgQueue.push(wakuMessage);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
subscriptions.set(decoder.contentTopic, subscription);
|
||||||
|
},
|
||||||
|
async nextMessage(contentTopic) {
|
||||||
|
if (msgQueue.length != 0) {
|
||||||
|
const oldestMsg = msgQueue.shift();
|
||||||
|
if (oldestMsg.contentTopic === contentTopic) {
|
||||||
|
return oldestMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (msgQueue.length != 0) {
|
||||||
|
clearInterval(interval);
|
||||||
|
const oldestMsg = msgQueue.shift();
|
||||||
|
if (oldestMsg.contentTopic === contentTopic) {
|
||||||
|
resolve(oldestMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
intervals.set(contentTopic, interval);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async stop(contentTopic) {
|
||||||
|
if (intervals.has(contentTopic)) {
|
||||||
|
clearInterval(intervals.get(contentTopic));
|
||||||
|
intervals.delete(contentTopic);
|
||||||
|
}
|
||||||
|
if (subscriptions.has(contentTopic)) {
|
||||||
|
await subscriptions.get(contentTopic)();
|
||||||
|
subscriptions.delete(contentTopic);
|
||||||
|
} else {
|
||||||
|
console.log("Subscriptipon doesnt exist");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return [sender, responder];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function scheduleHandshakeAuthConfirmation(pairingObj, ui) {
|
||||||
|
const authCode = await pairingObj.getAuthCode();
|
||||||
|
ui.handshake.connecting();
|
||||||
|
pairingObj.validateAuthCode(confirm("Confirm that authcode is: " + authCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
function initUI() {
|
||||||
|
const messagesList = document.getElementById("messages");
|
||||||
|
const nicknameInput = document.getElementById("nick-input");
|
||||||
|
const textInput = document.getElementById("text-input");
|
||||||
|
const sendButton = document.getElementById("send-btn");
|
||||||
|
const chatArea = document.getElementById("chat-area");
|
||||||
|
const wakuStatusSpan = document.getElementById("waku-status");
|
||||||
|
const handshakeStatusSpan = document.getElementById("handshake-status");
|
||||||
|
|
||||||
|
const qrCanvas = document.getElementById("qr-canvas");
|
||||||
|
const qrUrlContainer = document.getElementById("qr-url-container");
|
||||||
|
const qrUrl = document.getElementById("qr-url");
|
||||||
|
const copyURLButton = document.getElementById("copy-url");
|
||||||
|
const openTabButton = document.getElementById("open-tab");
|
||||||
|
|
||||||
|
copyURLButton.onclick = () => {
|
||||||
|
const copyText = document.getElementById("qr-url"); // need to get it each time otherwise copying does not work
|
||||||
|
copyText.select();
|
||||||
|
copyText.setSelectionRange(0, 99999);
|
||||||
|
navigator.clipboard.writeText(copyText.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
openTabButton.onclick = () => {
|
||||||
|
window.open(qrUrl.value, "_blank");
|
||||||
|
};
|
||||||
|
|
||||||
|
const disableChatUIStateIfNeeded = () => {
|
||||||
|
const readyToSend = nicknameInput.value !== "";
|
||||||
|
textInput.disabled = !readyToSend;
|
||||||
|
sendButton.disabled = !readyToSend;
|
||||||
|
};
|
||||||
|
nicknameInput.onchange = disableChatUIStateIfNeeded;
|
||||||
|
nicknameInput.onblur = disableChatUIStateIfNeeded;
|
||||||
|
|
||||||
|
return {
|
||||||
|
shareInfo: {
|
||||||
|
setURL(url) {
|
||||||
|
qrUrl.value = url;
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
qrUrlContainer.style.display = "none";
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
qrUrlContainer.style.display = "flex";
|
||||||
|
},
|
||||||
|
renderQR(url) {
|
||||||
|
QRCode.toCanvas(qrCanvas, url, (err) => {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
waku: {
|
||||||
|
_val(msg) {
|
||||||
|
wakuStatusSpan.innerText = msg;
|
||||||
|
},
|
||||||
|
_class(name) {
|
||||||
|
wakuStatusSpan.className = name;
|
||||||
|
},
|
||||||
|
connecting() {
|
||||||
|
this._val("connecting...");
|
||||||
|
this._class("progress");
|
||||||
|
},
|
||||||
|
connected() {
|
||||||
|
this._val("connected");
|
||||||
|
this._class("success");
|
||||||
|
},
|
||||||
|
error(msg) {
|
||||||
|
this._val(msg);
|
||||||
|
this._class("error");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handshake: {
|
||||||
|
_val(val) {
|
||||||
|
handshakeStatusSpan.innerText = val;
|
||||||
|
},
|
||||||
|
_class(name) {
|
||||||
|
handshakeStatusSpan.className = name;
|
||||||
|
},
|
||||||
|
error(msg) {
|
||||||
|
this._val(msg);
|
||||||
|
this._class("error");
|
||||||
|
},
|
||||||
|
waiting() {
|
||||||
|
this._val("waiting for handshake...");
|
||||||
|
this._class("progress");
|
||||||
|
},
|
||||||
|
generating() {
|
||||||
|
this._val("generating QR code...");
|
||||||
|
this._class("progress");
|
||||||
|
},
|
||||||
|
connecting() {
|
||||||
|
this._val("executing handshake...");
|
||||||
|
this._class("progress");
|
||||||
|
},
|
||||||
|
connected() {
|
||||||
|
this._val("handshake completed!");
|
||||||
|
this._class("success");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
_render({ time, text, nick }) {
|
||||||
|
messagesList.innerHTML += `
|
||||||
|
<li>
|
||||||
|
(${nick})
|
||||||
|
<strong>${text}</strong>
|
||||||
|
<i>[${new Date(time).toISOString()}]</i>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
_status(text, className) {
|
||||||
|
sendButton.className = className;
|
||||||
|
},
|
||||||
|
onReceive({ payload }) {
|
||||||
|
const { timestamp, nick, text } = ProtoChatMessage.decode(payload);
|
||||||
|
|
||||||
|
this._render({
|
||||||
|
nick,
|
||||||
|
time: timestamp * 1000,
|
||||||
|
text: utils.bytesToUtf8(text),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onSend(cb) {
|
||||||
|
sendButton.addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
this._status("sending...", "progress");
|
||||||
|
await cb(textInput.value, nicknameInput.value);
|
||||||
|
this._status("sent", "success");
|
||||||
|
|
||||||
|
this._render({
|
||||||
|
time: Date.now(), // a bit different from what receiver will see but for the matter of example is good enough
|
||||||
|
text: textInput.value,
|
||||||
|
nick: nicknameInput.value,
|
||||||
|
});
|
||||||
|
textInput.value = "";
|
||||||
|
} catch (e) {
|
||||||
|
this._status(`error: ${e.message}`, "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
display() {
|
||||||
|
chatArea.style.display = "block";
|
||||||
|
this._status("waiting for input", "progress");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.shareInfo.hide();
|
||||||
|
chatArea.style.display = "none";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
19
examples/noise-js/manifest.json
Normal file
19
examples/noise-js/manifest.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Waku Noise",
|
||||||
|
"description": "Example showing Waku noise capabilities.",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "favicon.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
12121
examples/noise-js/package-lock.json
generated
Normal file
12121
examples/noise-js/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
examples/noise-js/package.json
Normal file
23
examples/noise-js/package.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "@waku/noise-example",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --config webpack.config.js",
|
||||||
|
"start": "webpack-dev-server"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@waku/noise": "https://github.com/waku-org/js-noise.git",
|
||||||
|
"js-waku": "^0.29.0-29436ea",
|
||||||
|
"protobufjs": "^7.1.2",
|
||||||
|
"qrcode": "^1.5.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
|
"webpack": "^5.74.0",
|
||||||
|
"webpack-cli": "^4.10.0",
|
||||||
|
"webpack-dev-server": "^4.11.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
19
examples/noise-js/webpack.config.js
Normal file
19
examples/noise-js/webpack.config.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: "./index.js",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
filename: "index.js",
|
||||||
|
},
|
||||||
|
experiments: {
|
||||||
|
asyncWebAssembly: true,
|
||||||
|
},
|
||||||
|
mode: "development",
|
||||||
|
plugins: [
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: ["index.html", "favicon.ico", "favicon.png", "manifest.json"],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user