diff --git a/.cspell.json b/.cspell.json index 6fc3342..ecfd0c8 100644 --- a/.cspell.json +++ b/.cspell.json @@ -74,6 +74,7 @@ "instanceof", "sepolia", "faucet", + "concat", ], "flagWords": [], "ignorePaths": [ diff --git a/docs/guides/js-waku/configure-discovery.md b/docs/guides/js-waku/configure-discovery.md index a5f102f..8d6c7e0 100644 --- a/docs/guides/js-waku/configure-discovery.md +++ b/docs/guides/js-waku/configure-discovery.md @@ -29,7 +29,7 @@ import TabItem from '@theme/TabItem'; ``` - + ```shell npm install @libp2p/bootstrap @@ -89,7 +89,7 @@ For local development using a `nwaku` node, use a `ws` address instead of `wss`. To bootstrap a node using [DNS Discovery](/overview/concepts/dns-discovery), first install the `@waku/dns-discovery` package: - + ```shell npm install @waku/dns-discovery diff --git a/docs/guides/js-waku/index.md b/docs/guides/js-waku/index.md index 71ccece..0f316c9 100644 --- a/docs/guides/js-waku/index.md +++ b/docs/guides/js-waku/index.md @@ -14,7 +14,7 @@ import TabItem from '@theme/TabItem'; ``` - + ```shell npm install @waku/sdk @@ -48,7 +48,7 @@ We recommend creating a message structure for your application using [Protocol B To get started, install the `protobufjs` package using your preferred package manager: - + ```shell npm install protobufjs @@ -84,7 +84,8 @@ Have a look at the quick start guide and comprehensive tutorials to learn how to | - | - | | [Send and Receive Messages Using Light Push and Filter](/guides/js-waku/light-send-receive) | Learn how to send and receive messages on light nodes using the [Light Push](/overview/concepts/protocols#light-push) and [Filter](/overview/concepts/protocols#filter) protocols | | [Retrieve Messages Using Store Protocol](/guides/js-waku/store-retrieve-messages) | Learn how to retrieve and filter historical messages on light nodes using the [Store protocol](/overview/concepts/protocols#store) | -| [Bootstrap DApps Using @waku/create-app](/guides/js-waku/use-waku-create-app) | Learn how to use the [@waku/create-app](https://www.npmjs.com/package/@waku/create-app) package to bootstrap your next `@waku/sdk` project from various example templates | +| [Build React DApps Using @waku/react](/guides/js-waku/use-waku-react) | Learn how to use the [@waku/react](https://www.npmjs.com/package/@waku/react) package seamlessly integrate `@waku/sdk` into a React application | +| [Scaffold DApps Using @waku/create-app](/guides/js-waku/use-waku-create-app) | Learn how to use the [@waku/create-app](https://www.npmjs.com/package/@waku/create-app) package to bootstrap your next `@waku/sdk` project from various example templates | | [Bootstrap Nodes and Discover Peers](/guides/js-waku/configure-discovery) | Learn how to bootstrap your node using [Static Peers](/overview/concepts/static-peers) and discover peers using [DNS Discovery](/overview/concepts/dns-discovery) | | [Run @waku/sdk in a NodeJS Application](/guides/js-waku/run-waku-nodejs) | Learn our suggested approach for using the `@waku/sdk` package within a NodeJS application | | [Debug Your Waku DApp and WebSocket](/guides/js-waku/debug-waku-dapp) | Learn how to troubleshoot your Waku DApp using debug logs and check [WebSocket](/overview/concepts/transports) connections in [nwaku](/guides/run-nwaku-node) | @@ -94,8 +95,6 @@ Have a look at the quick start guide and comprehensive tutorials to learn how to Until [node incentivisation](/overview/reference/research-in-progress#prevention-of-denial-of-service-dos-and-node-incentivisation) is in place, you should [operate extra nodes](/guides/nodes-and-sdks#run-a-waku-node) alongside the ones provided by the Waku Network. When running a node, we recommend using the [DNS Discovery and Static Peers](/guides/js-waku/configure-discovery#configure-dns-discovery-and-static-peers) configuration to connect to both the Waku Network and your node. ::: - - ## Get Help and Report Issues To engage in general discussions, seek assistance, or stay updated with the latest news, visit the `#support` and `#js-waku-contribute` channels on the [Waku Discord](https://discord.waku.org). diff --git a/docs/guides/js-waku/light-send-receive.md b/docs/guides/js-waku/light-send-receive.md index ce94d96..ec2ed51 100644 --- a/docs/guides/js-waku/light-send-receive.md +++ b/docs/guides/js-waku/light-send-receive.md @@ -6,7 +6,7 @@ This guide provides detailed steps to start using the `@waku/sdk` package by set ## Create a Light Node -Use the `createLightNode()` function to create a `Light Node` and interact with the Waku Network: +Use the `createLightNode()` function to create a [Light Node](/overview/reference/glossary#light-node) and interact with the Waku Network: ```js import { createLightNode } from "@waku/sdk"; @@ -61,12 +61,12 @@ const encoder = createEncoder({ contentTopic }); const decoder = createDecoder(contentTopic); ``` -The `ephemeral` option allows you to specify whether your messages should be persisted by [Store peers](/guides/js-waku/store-retrieve-messages): +The `ephemeral` option allows you to specify whether messages should not be stored by [Store peers](/guides/js-waku/store-retrieve-messages): ```js const encoder = createEncoder({ contentTopic: contentTopic, // message content topic - ephemeral: true, // allows messages to be persisted or not + ephemeral: true, // allows messages not be stored on the network }); ``` diff --git a/docs/guides/js-waku/use-waku-create-app.md b/docs/guides/js-waku/use-waku-create-app.md index d076081..4d46191 100644 --- a/docs/guides/js-waku/use-waku-create-app.md +++ b/docs/guides/js-waku/use-waku-create-app.md @@ -1,5 +1,5 @@ --- -title: "Bootstrap DApps Using @waku/create-app" +title: "Scaffold DApps Using @waku/create-app" --- This guide provides detailed steps to bootstrap your next `@waku/sdk` project from [various example templates](https://github.com/waku-org/js-waku-examples/tree/master/examples) using the [@waku/create-app](https://www.npmjs.com/package/@waku/create-app) package. @@ -14,7 +14,7 @@ import TabItem from '@theme/TabItem'; ``` - + ```shell npx @waku/create-app [PROJECT DIRECTORY] diff --git a/docs/guides/js-waku/use-waku-react.md b/docs/guides/js-waku/use-waku-react.md index 16ead41..94a48ee 100644 --- a/docs/guides/js-waku/use-waku-react.md +++ b/docs/guides/js-waku/use-waku-react.md @@ -6,7 +6,7 @@ The [@waku/react](https://www.npmjs.com/package/@waku/react) package provides co ## Install the Dependencies -First, set up a project using any [production-grade React framework](https://react.dev/learn/start-a-new-react-project) or use an existing React application. For this guide, we will create a boilerplate using [Create React App (CRA)](https://create-react-app.dev/docs/getting-started): +First, set up a project using any [production-grade React framework](https://react.dev/learn/start-a-new-react-project) or an existing React application. For this guide, we will create a boilerplate using [ViteJS](https://vitejs.dev/guide/): ```mdx-code-block import Tabs from '@theme/Tabs'; @@ -14,53 +14,69 @@ import TabItem from '@theme/TabItem'; ``` - + ```shell -npx create-react-app [PROJECT DIRECTORY] +npm create vite@latest [PROJECT DIRECTORY] -- --template react ``` ```shell -yarn create react-app [PROJECT DIRECTORY] +yarn create vite [PROJECT DIRECTORY] --template react ``` -Next, install the `@waku/react` package using your preferred package manager: +Next, install the required libraries for integrating `@waku/sdk` using your preferred package manager: - + ```shell -npm install @waku/react @waku/sdk +npm install @waku/react @waku/sdk protobufjs ``` ```shell -yarn add @waku/react @waku/sdk +yarn add @waku/react @waku/sdk protobufjs ``` -## Create a Light Node +## Initialise the Waku Provider -Use the `useCreateLightNode()` hook to create a [Light Node](/guides/js-waku/light-send-receive): +In the `main.jsx` file, which serves as the entry point for a React app, we will set up the `LightNodeProvider` [context provider](https://react.dev/reference/react/createContext#provider) to wrap the entire application within the Waku provider. Import the following on top of your file: -```js title="App.js" -import { useCreateLightNode } from "@waku/react"; +```js title="src/main.jsx" +import { LightNodeProvider } from "@waku/react"; + +// Set the Light Node options +const NODE_OPTIONS = { defaultBootstrap: true }; + +ReactDOM.createRoot(document.getElementById('root')).render( + // Use the Light Node context provider + + + + + , +) +``` + +Next, create and start a [Light Node](/overview/reference/glossary#light-node) using the `useWaku()` function within the `App.jsx` file: + +```js title="src/App.jsx" +import { useWaku } from "@waku/react"; function App() { - // Create and start a Light Node and wait for remote peers - const { node, error, isLoading } = useCreateLightNode({ - options: { defaultBootstrap: true }, - }); + // Create and start a Light Node + const { node, error, isLoading } = useWaku(); // "node" is the created Light Node // "error" captures any error that occurs during node creation @@ -68,163 +84,208 @@ function App() { } ``` -You can also use the `LightNodeProvider` [context provider](https://react.dev/reference/react/createContext#provider) to pass configuration options for creating a `Light Node`: +## Build the Application Interface -```js title="index.js" -import { LightNodeProvider } from "@waku/react"; +Let's build a user interface for sending messages and viewing past messages, modify the `App.jsx` file with the following code block: -// Set the Light Node options -const NODE_OPTIONS = { defaultBootstrap: true }; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - // Use the Light Node context provider - - - - -); -``` - -```js title="App.js" +```js title="src/App.jsx" +import { useState, useEffect } from 'react'; import { useWaku } from "@waku/react"; +import { createEncoder, createDecoder } from "@waku/sdk"; +import protobuf from 'protobufjs'; +import './App.css' function App() { + const [inputMessage, setInputMessage] = useState(""); + const [messages, setMessages] = useState([]); + + // Update the inputMessage state as the user input changes + const handleInputChange = (e) => { + setInputMessage(e.target.value); + }; + // Create and start a Light Node const { node, error, isLoading } = useWaku(); + + // Create a message encoder and decoder + const contentTopic = "/waku-react-guide/1/chat/proto"; + const encoder = createEncoder({ contentTopic }); + const decoder = createDecoder(contentTopic); + + // Create a message structure using Protobuf + const ChatMessage = new protobuf.Type("ChatMessage") + .add(new protobuf.Field("timestamp", 1, "uint64")) + .add(new protobuf.Field("message", 2, "string")); + + // Send the message using Light Push + const sendMessage = async () => {} + + return ( + <> +
+

Waku React Demo

+
+ {messages.map((message, index) => ( +
+ {new Date(message.timestamp).toUTCString()} +
{message.message}
+
+ ))} +
+
+ + +
+
+ + ) +} + +export default App +``` + +:::info +In the code above, we also created a message `encoder` and `decoder` using the `createEncoder()` and `createDecoder()` functions, along with the application [message structure](/guides/js-waku/#message-structure) with Protobuf. +::: + +Next, modify the `App.css` file with the following code block: + +```css title="src/App.css" +#root { + margin: 0 auto; +} + +.chat-interface { + display: flex; + flex-direction: column; + height: 100vh; + border: 1px solid #ccc; +} + +.chat-body { + flex-grow: 1; + overflow-y: auto; + padding: 10px; +} + +.message-text { + background-color: #f1f1f1; + color: #000; + padding: 10px; + margin-bottom: 10px; +} + +.chat-footer { + display: flex; + padding: 10px; + background-color: #f1f1f1; + align-items: center; +} + +#message-input { + flex-grow: 1; + border-radius: 4px; + padding: 10px; + margin-right: 10px; +} + +.send-button { + background-color: #007bff; + border-radius: 4px; } ``` ## Send Messages Using Light Push -Use the `useLightPush()` hook to bind [Light Push methods](/guides/js-waku/light-send-receive/#send-messages-using-light-push) to a node and `encoder`: +To send messages in our application, we need to modify the `sendMessage()` function to serialize user input into our Protobuf structure and [push it to the network](/guides/js-waku/light-send-receive#send-messages-using-light-push) using the `useLightPush()` function: -```js title="App.js" -import { - useCreateLightNode, - useLightPush, -} from "@waku/react"; -import { - utf8ToBytes, - createEncoder, -} from "@waku/sdk"; +```js title="src/App.jsx" +import { useLightPush } from "@waku/react"; function App() { - // Create and start a Light Node and wait for remote peers - const { node, error, isLoading } = useCreateLightNode({ - options: { defaultBootstrap: true }, - }); - - // Choose a content topic and create an encoder - const contentTopic = "/waku-react-guide/1/message/utf8"; - const encoder = createEncoder({ contentTopic }); - // Bind push method to a node and encoder const { push } = useLightPush({ node, encoder }); // Send the message using Light Push - const sendMessage = async (text) => { - if (!push || !text) { - return; - } - const payload = utf8ToBytes(text); - await push({ payload }); - }; + const sendMessage = async () => { + if (!push || inputMessage.length === 0) return; - // Wait for the node to finish loading before sending messages - if (!isLoading) { - sendMessage("Hello, World!"); - } + // Create a new message object + const timestamp = Date.now(); + const protoMessage = ChatMessage.create({ + timestamp: timestamp, + message: inputMessage + }); + + // Serialise the message and push to the network + const payload = ChatMessage.encode(protoMessage).finish(); + const { recipients, errors } = await push({ payload, timestamp }); + + // Check for errors + if (errors.length === 0) { + setInputMessage(""); + console.log("MESSAGE PUSHED"); + } else { + console.log(errors); + } + }; } ``` ## Receive Messages Using Filter -Use the `useFilterMessages()` hook to receive messages from a [Filter subscription](/guides/js-waku/light-send-receive/#receive-messages-using-filter) and keep it updated: +To display messages in our application, we need to use the `useFilterMessages()` function to create a [Filter subscription](/guides/js-waku/light-send-receive/#receive-messages-using-filter), receive incoming messages, and render them in our interface: -```js title="App.js" -import { - useCreateLightNode, - useFilterMessages, -} from "@waku/react"; -import { - bytesToUtf8, - createDecoder, -} from "@waku/sdk"; +```js title="src/App.jsx" +import { useFilterMessages } from "@waku/react"; function App() { - // Create and start a Light Node and wait for remote peers - const { node } = useCreateLightNode({ - options: { defaultBootstrap: true }, - }); - - // Choose a content topic and create a decoder - const contentTopic = "/waku-react-guide/1/message/utf8"; - const decoder = createDecoder(contentTopic); - // Receive messages from Filter subscription - const { error, messages, isLoading } = useFilterMessages({ node, decoder }); + const { messages: filterMessages } = useFilterMessages({ node, decoder }); - // "error" captures any error that occurs while receiving messages - // "messages" contains a list of messages the subscription received - // "isLoading" indicates whether the node is still subscribing to Filter - - // Wait for the messages to finish loading before processing them - if (!isLoading) { - messages.forEach((message) => { - console.log(bytesToUtf8(message.payload)); - }); - } + // Render the list of messages + useEffect(() => { + setMessages(filterMessages.map((wakuMessage) => { + if (!wakuMessage.payload) return; + return ChatMessage.decode(wakuMessage.payload); + })); + }, [filterMessages]); } ``` -:::info -Wait for the messages to finish loading before processing them (`isLoading` === `false`). -::: - ## Retrieve Messages Using Store -Use the `useStoreMessages()` hook to retrieve messages from the [Store protocol](/guides/js-waku/store-retrieve-messages): +To display messages from the past, we need to retrieve them from the [Store protocol](/guides/js-waku/store-retrieve-messages) using the `useStoreMessages()` function when our application initialises and then render them alongside newly received messages: -```js title="App.js" -import { - useCreateLightNode, - useStoreMessages, -} from "@waku/react"; -import { - bytesToUtf8, - createDecoder, -} from "@waku/sdk"; +```js title="src/App.jsx" +import { useFilterMessages, useStoreMessages } from "@waku/react"; function App() { - // Create and start a Light Node and wait for remote peers - const { node } = useCreateLightNode({ - options: { defaultBootstrap: true }, - }); + // Query Store peers for past messages + const { messages: storeMessages } = useStoreMessages({ node, decoder }); - // Choose a content topic and create a decoder - const contentTopic = "/waku-react-guide/1/message/utf8"; - const decoder = createDecoder(contentTopic); + // Receive messages from Filter subscription + const { messages: filterMessages } = useFilterMessages({ node, decoder }); - // Query the Store peer - const { error, messages, isLoading } = useStoreMessages({ node, decoder }); - - // "error" captures any error that occurs during message retrieval - // "messages" contains a list of messages retrieved from the Store peer - // "isLoading" indicates whether the node is still retrieving messages - - // Wait for the messages to finish retrieving before processing them - if (!isLoading) { - messages.forEach((message) => { - console.log(bytesToUtf8(message.payload)); - }); - } + // Render both past and new messages + useEffect(() => { + const allMessages = storeMessages.concat(filterMessages); + setMessages(allMessages.map((wakuMessage) => { + if (!wakuMessage.payload) return; + return ChatMessage.decode(wakuMessage.payload); + })); + }, [filterMessages, storeMessages]); } ``` :::info -To explore the available query options, have a look at the [Store Query Options](/guides/js-waku/store-retrieve-messages#store-query-options) guide. +To explore the available Store query options, have a look at the [Retrieve Messages Using Store Protocol](/guides/js-waku/store-retrieve-messages#store-query-options) guide. ::: :::tip diff --git a/docs/guides/nodes-and-sdks.md b/docs/guides/nodes-and-sdks.md index a04e522..edc10d2 100644 --- a/docs/guides/nodes-and-sdks.md +++ b/docs/guides/nodes-and-sdks.md @@ -43,6 +43,6 @@ Waku provides integrations tailored for mobile applications, enabling Waku to ru | | Description | Documentation | | - | - | - | | [REST API](https://waku-org.github.io/waku-rest-api/) | REST API interface provided by `nwaku` and `go-waku` to interact with the Waku Network | [Waku Node REST API Spec](https://waku-org.github.io/waku-rest-api/) | -| [@waku/react](https://www.npmjs.com/package/@waku/react) | React components and UI adapters designed for seamless integration with `@waku/sdk` | COMING SOON | -| [@waku/create-app](https://www.npmjs.com/package/@waku/create-app) | Starter kit to bootstrap your next `@waku/sdk` project from various example templates | [Bootstrap DApps Using @waku/create-app](/guides/js-waku/use-waku-create-app) | +| [@waku/react](https://www.npmjs.com/package/@waku/react) | React components and UI adapters designed for seamless integration with `@waku/sdk` | [Build React DApps Using @waku/react](/guides/js-waku/use-waku-react) | +| [@waku/create-app](https://www.npmjs.com/package/@waku/create-app) | Starter kit to bootstrap your next `@waku/sdk` project from various example templates | [Scaffold DApps Using @waku/create-app](/guides/js-waku/use-waku-create-app) | | [nwaku-compose](https://github.com/waku-org/nwaku-compose) | Pre-configured Docker Compose setup for running and monitoring a `nwaku` node using Prometheus and Grafana | [Run Nwaku with Docker Compose](/guides/nwaku/run-docker-compose) | \ No newline at end of file diff --git a/docs/guides/nwaku/configure-discovery.md b/docs/guides/nwaku/configure-discovery.md index 15aa456..9789cbb 100644 --- a/docs/guides/nwaku/configure-discovery.md +++ b/docs/guides/nwaku/configure-discovery.md @@ -50,7 +50,7 @@ For example, consider a `nwaku` node that enables `DNS Discovery`, connects to a ```bash ./build/wakunode2 \ --dns-discovery=true \ - --dns-discovery-url=enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im \ + --dns-discovery-url=enrtree://ANEDLO25QVUGJOUTQFRYKWX6P4Z4GKVESBMHML7DZ6YK4LGS5FC5O@prod.wakuv2.nodes.status.im \ --dns-discovery-name-server=8.8.8.8 \ --dns-discovery-name-server=8.8.4.4 ``` diff --git a/sidebars.js b/sidebars.js index 1f390ed..d966285 100644 --- a/sidebars.js +++ b/sidebars.js @@ -75,6 +75,7 @@ const sidebars = { items: [ "guides/js-waku/light-send-receive", "guides/js-waku/store-retrieve-messages", + "guides/js-waku/use-waku-react", "guides/js-waku/use-waku-create-app", "guides/js-waku/configure-discovery", "guides/js-waku/run-waku-nodejs",