Build a decentralized chat app using the GUN JavaScript library. Learn how to use web3 technology to create a peer-to-peer graph database without traditional cloud computing providers. https://gun-chat-dapp.web.app/

#js #web3 #tutorial

🔗 Resources

Live Demo: https://gun-chat-dapp.web.app/
View on Product Hunt: https://www.producthunt.com/posts/gun-2
Docs: https://gun.eco/
Source Code: https://github.com/fireship-io/gun-chat

📚 Chapters

00:00 Intro
00:56 How it Works
03:11 Setup
03:30 User Authentication
07:43 Chat Messages

 🤓 Install the quiz app

iOS https://itunes.apple.com/us/app/fireship/id1462592372?mt=8
Android https://play.google.com/store/apps/details?id=io.fireship.quizapp

🔥 Watch more with Fireship PRO

Upgrade to Fireship PRO at https://fireship.io/pro
Use code lORhwXd2 for 25% off your first payment. 

🎨 My Editor Settings

- Atom One Dark 
- vscode-icons
- Fira Code Font

Topics Covered 

- Pros and Cons of Web3 development
- How to develop decentralized apps
- WebRTC 
- End-to-End e2e encryption for chat
- Using Svelte to build a chat UI
2024-02-04T13:59:03.919Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
bea91a7f-f8ef-44c3-a4cf-e6cdf399ee0e
6298c300bd1d30a1dd6eef82ae0a4194e51ffc852e1d68b4b282dfe4592144e2
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
I recently built a chat app that can handle thousands of messages per second, scales around the world, and cost me nothing to run.
But the real weird thing about it is that the data and infrastructure is not controlled by a big tech company.
Instead, it's decentralized across the entire user base using web technologies.
In fact, you can chat with me right now on the live demo by going to gunchatdap.web.app.
Again, that's gunchatdap.web.app.
And I'm trusting you not to hack to pieces this time.
In today's video, we'll build a decentralized chat app or dApp if you prefer, similar to YouTube Super Chat using a a library called gun.
Js.
In the process, you'll learn about the benefits of building a decentralized app along with the weird trade offs and challenges.
For the front end UI, we'll use Svelte, a JavaScript library that's not sponsored by Big Tech.
If you're new here, like and subscribe, and you'll find the full source code on GitHub.
Then I want to give a shout out to Mark Nadal, the creator of gun.
Js, who donated a bunch of his time to answer all my questions and help make this video happen.
Before we jump into the code, let's first answer the question of how does this thing actually work?
I made a short video about gun.
Js a few weeks ago and you guys had a ton of questions about it.
At a high level.
Gun.
Js is a decentralized graph database.
A normal database would store all of your data in a hard disk somewhere in the cloud.
It may be sharded across multiple machines, but for all intents and purposes, you can imagine your entire dataset on a single disk.
Gun, on the other hand, stores a small subset of data on each user based on the actual data that they consume in the application.
When a user makes a query for some data, it will search across the network for other users that have that data and sync it up using technologies like WebRTC.
So you can think of the entire database as the union of all peers on the network.
Connected.
The idea is very similar to a blockchain ledger where no one individual has control of the entire network, but it's important to point out that this is not blockchain technology, which tends to be too slow and just unnecessary to build something like a super chat.
However, it does rely heavily on cryptography to implement things like user authentication.
When you create a new user account, a cryptographically secure key pair is generated.
The username is associated with the public key so past messages can found, and the password is a proof of work seed to prove and decrypt access to the account's private keys.
In addition, it's possible to implement end end encryption, which we'll do in this demo, but we'll talk more about that later in the video.
Another good question is how is data persisted good, and what happens if a user just clears out their browser cache?
By default, data is stored in the browser's local storage, which is limited to 5 megabytes.
And if the user clears out the data in local storage, it could potentially be lost if it's not somewhere else on the network.
That's probably not acceptable if you're building a production grade app.
But what you can do is deploy a relay server that uses a different storage mechanism called RADIX that can store a lot more data on the disk of an actual server.
And that makes the network more robust because a query can fall back to a relay if it's not available from another peer.
Now, another really important concept to understand is that when you create a node in the database, it'll be available to the entire decentralized network.
That means another developer can easily access your public data by simply knowing the name of the node where it's stored.
Now it is possible to encrypt data and things like that, but it just requires a completely different mental model than you might be used to.
Let's go ahead and jump into the source code.
I'm not going to cover every single line of code in this project and instead just focus on the important parts related to the database.
What we have here is a Svelte app with 2 main features, email password user authentication, and then a massive group chat room that anybody can join.
The only dependency in this project is gun, which can be installed with NPM.
The first thing we'll focus on is user authentication, and to do that, I'm creating a file called user dotjs.
At the top of the file, we'll import gun, and below that, import 2 supporting libraries.
The first one c, which stands for security the encryption and authorization, and is the module that enables user authentication.
Next, we have axe, which stands for advanced exchange equation, and is basically an alternative way to connect peers together and tends to be more performant for a chat app like this, and there's a whole doc on it if you wanna learn more.
From there, we'll create a variable called db to initialize the database, then we'll use it to make a reference to the currently authenticated user.
I'm also chaining the option of recall all to session storage here, so the user stays logged in between browser sessions.
Now to manage the user in the app, we need to know if the user is logged in, and we also want their username so we can show it in the UI.
We can get the username by making a reference to the user, then calling git alias, which will be the value of whatever username they choose when they sign up.
Now we're going to use this value frequently throughout the application, so I'm importing writable from Svelte store to make it reactive.
A store is like an observable value that will rerender the UI whenever it's changed, and it can be shared across multiple components.
So whenever the alias for the current user updates, we'll set the value of the store to that value.
But we also want to listen to changes to the auth state when the user signs in or signs out.
To handle that, we'll listen to the auth event on the database and basically do the same thing here where we fetch the alias and then set that as the value on the store.
Now I'm going to kinda do things in reverse here because I first want to show you how the store works in Svelte.
We have this header component here that will show the title of the app if you're not logged in, but if you are logged in, it'll show your username as well as your avatar.
Now implementing sign out is really easy.
All we have to do is import the username store and the gun user object, then we'll create a function called sign out that calls leave on the user and sets the username store to an empty string.
Then down in the HTML, we have a button that when clicked will call the sign out function.
But we only want to show that button if the user is signed in.
And the way we can tell if a user is signed in is if their username is present.
The cool thing about spelled is that we can easily do that with a store in any component by adding an if statement followed by a dollar sign and then the name of the store.
The dollar sign will subscribed to the store and react to any changes that happened to it.
If the username does exist, then we'll go ahead and show the username by subscribing to the store once again.
We can also do the same contained to show an avatar with the user's initials by using the awesome dice bear API.
I made a short video about this already, but dice bear will basically make a unique an avatar based on the username as the random seed.
Then after that, we have a button that fires the sign out function when clicked.
And finally, we'll add an else block here to show something else if the user is not logged in.
That takes care of the header component, and you'll notice that I'm declaring it here in the app component.
And now we can move on to the login component that will allow the user to sign in or sign up with their username and password.
In the component, we'll import the user object, then set up local state for the username and password.
In Svelte, we can implement 2 way data binding with a variable by creating a form input and then saying bind value to that variable.
Full.
That means anytime the user types into the form, the value of the variable will change.
We have separate form inputs for username and password, and we'll share them for both the login and sign up process, which itself just consists of 2 different buttons that will either call the login function or the sign up function.
To log a user in, we use the user auth method.
It takes the username and password as arguments, then the third argument allows you to define a callback.
In this case, the value of the store that we set up earlier will update automatically, but we can do other things here as well like error handling.
Now the process to sign up a new user is very similar, but instead of calling auth, we call that create method on the user.
And if the user creation is successful, then we will log that user in automatically.
Now at this point, we have a working user authentication system.
But one thing to keep in mind here is that we're not enforcing the uniqueness of the username, which is just a caveat you'll wanna keep combined.
I should mention that it is possible to enforce username uniqueness, but it's beyond the scope of this video.
Now we can move on to the chat component, which is where we will query items from the database and also give the user the ability to send a message.
The component has 2 pieces of state, a string for a new message that the user will type into a form input and an array of messages, which will contain the message text along with the user who sent it and a timestamp.
To query messages, as I'm going to set up the on mount life cycle hook that will run whenever that component is first initialized.
Inside of it, we'll use the database to make a reference to the chat node.
Coded.
In this demo, since we have one giant super chat, we can just give it a name of chat.
But if you have multiple chat rooms, you'd likely want to give each one a name.
After that, we'll call map to basically loop over every single message in the chat and then call once to only read each message once.
In this case, each message is immutable, so we don't need to listen to changes in real time, but you could do that if you wanted to using the on method.
We can then define a callback that will be called on each new message that will give us access to the data and the ID of that node.
Now if the data is defined, we're going to format a message that's more suitable for the UI with the properties of who, what, and when.
Who is the user that sent the message, and we can figure out who sent it by taking that data of the raw message and using it to get the alias.
Next, we have what, which is the actual text of the user's message.
But the interesting thing here is that we're actually implementing end to end encryption.
That means the value in the database is encrypted and the only way to decrypt it is to have the corresponding key.
In this demo, our data is encrypted, but it's not really secure because I'm just hard coding the encryption key right here in the source code so anybody could find it.
But if it was an actual secret between 2 users, you could use it to encrypt and decrypt messages.
And finally, we have the when property.
To get an accurate time stamp across all of our users, We're using gun state as the final source of truth with the raw data.
That'll give us all the data we need for the UI.
Then the final step is to take each message and add it to an array that we can then loop over in the UI with Svelte.
You can loop over an array of items in Svelte with each.
This will render the chat message component for each message in the array.
And also notice how I'm adding parenthesis with message when, which provides Svelte with a unique key to sort all of the messages sufficiently.
That gives us a way to read messages in the chat.
Now we just need a form to submit them.
In the UI, you'll notice that I have a form that on the submit event will call the send message function.
Inside the function, the first thing we'll wanna do is use c to encrypt the actual message text, and notice how the key is the same as the one we used earlier to decrypt the messages.
From there, we can associate the message to the current user using the encrypted message as the Kevalu.
Then we'll create a date to serve as the index for the message so it can be sorted properly, at which point we can reference the chat collection, create a new node based on that index, ex and store the message value.
Congratulations.
You just built a decentralized chat app.
It'll be interesting to see if this thing actually works when the video is released.
Let me know how things go for you in the comments.
Make sure to like and subscribe.
Thanks for watching, and I will see you in the next one.

Speaker 0: I recently built a chat app that can handle thousands of messages per second, scales around the world, and cost me nothing to run. But the real weird thing about it is that the data and infrastructure is not controlled by a big tech company. Instead, it's decentralized across the entire user base using web technologies. In fact, you can chat with me right now on the live demo by going to gunchatdap.web.app. Again, that's gunchatdap.web.app.

And I'm trusting you not to hack to pieces this time. In today's video, we'll build a decentralized chat app or dApp if you prefer, similar to YouTube Super Chat using a a library called gun. Js. In the process, you'll learn about the benefits of building a decentralized app along with the weird trade offs and challenges. For the front end UI, we'll use Svelte, a JavaScript library that's not sponsored by Big Tech.

If you're new here, like and subscribe, and you'll find the full source code on GitHub. Then I want to give a shout out to Mark Nadal, the creator of gun. Js, who donated a bunch of his time to answer all my questions and help make this video happen. Before we jump into the code, let's first answer the question of how does this thing actually work? I made a short video about gun.

Js a few weeks ago and you guys had a ton of questions about it. At a high level. Gun. Js is a decentralized graph database. A normal database would store all of your data in a hard disk somewhere in the cloud.

It may be sharded across multiple machines, but for all intents and purposes, you can imagine your entire dataset on a single disk. Gun, on the other hand, stores a small subset of data on each user based on the actual data that they consume in the application. When a user makes a query for some data, it will search across the network for other users that have that data and sync it up using technologies like WebRTC. So you can think of the entire database as the union of all peers on the network. Connected.

The idea is very similar to a blockchain ledger where no one individual has control of the entire network, but it's important to point out that this is not blockchain technology, which tends to be too slow and just unnecessary to build something like a super chat. However, it does rely heavily on cryptography to implement things like user authentication. When you create a new user account, a cryptographically secure key pair is generated. The username is associated with the public key so past messages can found, and the password is a proof of work seed to prove and decrypt access to the account's private keys. In addition, it's possible to implement end end encryption, which we'll do in this demo, but we'll talk more about that later in the video.

Another good question is how is data persisted good, and what happens if a user just clears out their browser cache? By default, data is stored in the browser's local storage, which is limited to 5 megabytes. And if the user clears out the data in local storage, it could potentially be lost if it's not somewhere else on the network. That's probably not acceptable if you're building a production grade app. But what you can do is deploy a relay server that uses a different storage mechanism called RADIX that can store a lot more data on the disk of an actual server.

And that makes the network more robust because a query can fall back to a relay if it's not available from another peer. Now, another really important concept to understand is that when you create a node in the database, it'll be available to the entire decentralized network. That means another developer can easily access your public data by simply knowing the name of the node where it's stored. Now it is possible to encrypt data and things like that, but it just requires a completely different mental model than you might be used to. Let's go ahead and jump into the source code.

I'm not going to cover every single line of code in this project and instead just focus on the important parts related to the database. What we have here is a Svelte app with 2 main features, email password user authentication, and then a massive group chat room that anybody can join. The only dependency in this project is gun, which can be installed with NPM. The first thing we'll focus on is user authentication, and to do that, I'm creating a file called user dotjs. At the top of the file, we'll import gun, and below that, import 2 supporting libraries.

The first one c, which stands for security the encryption and authorization, and is the module that enables user authentication. Next, we have axe, which stands for advanced exchange equation, and is basically an alternative way to connect peers together and tends to be more performant for a chat app like this, and there's a whole doc on it if you wanna learn more. From there, we'll create a variable called db to initialize the database, then we'll use it to make a reference to the currently authenticated user. I'm also chaining the option of recall all to session storage here, so the user stays logged in between browser sessions. Now to manage the user in the app, we need to know if the user is logged in, and we also want their username so we can show it in the UI.

We can get the username by making a reference to the user, then calling git alias, which will be the value of whatever username they choose when they sign up. Now we're going to use this value frequently throughout the application, so I'm importing writable from Svelte store to make it reactive. A store is like an observable value that will rerender the UI whenever it's changed, and it can be shared across multiple components. So whenever the alias for the current user updates, we'll set the value of the store to that value. But we also want to listen to changes to the auth state when the user signs in or signs out.

To handle that, we'll listen to the auth event on the database and basically do the same thing here where we fetch the alias and then set that as the value on the store. Now I'm going to kinda do things in reverse here because I first want to show you how the store works in Svelte. We have this header component here that will show the title of the app if you're not logged in, but if you are logged in, it'll show your username as well as your avatar. Now implementing sign out is really easy. All we have to do is import the username store and the gun user object, then we'll create a function called sign out that calls leave on the user and sets the username store to an empty string.

Then down in the HTML, we have a button that when clicked will call the sign out function. But we only want to show that button if the user is signed in. And the way we can tell if a user is signed in is if their username is present. The cool thing about spelled is that we can easily do that with a store in any component by adding an if statement followed by a dollar sign and then the name of the store. The dollar sign will subscribed to the store and react to any changes that happened to it.

If the username does exist, then we'll go ahead and show the username by subscribing to the store once again. We can also do the same contained to show an avatar with the user's initials by using the awesome dice bear API. I made a short video about this already, but dice bear will basically make a unique an avatar based on the username as the random seed. Then after that, we have a button that fires the sign out function when clicked. And finally, we'll add an else block here to show something else if the user is not logged in.

That takes care of the header component, and you'll notice that I'm declaring it here in the app component. And now we can move on to the login component that will allow the user to sign in or sign up with their username and password. In the component, we'll import the user object, then set up local state for the username and password. In Svelte, we can implement 2 way data binding with a variable by creating a form input and then saying bind value to that variable. Full.

That means anytime the user types into the form, the value of the variable will change. We have separate form inputs for username and password, and we'll share them for both the login and sign up process, which itself just consists of 2 different buttons that will either call the login function or the sign up function. To log a user in, we use the user auth method. It takes the username and password as arguments, then the third argument allows you to define a callback. In this case, the value of the store that we set up earlier will update automatically, but we can do other things here as well like error handling.

Now the process to sign up a new user is very similar, but instead of calling auth, we call that create method on the user. And if the user creation is successful, then we will log that user in automatically. Now at this point, we have a working user authentication system. But one thing to keep in mind here is that we're not enforcing the uniqueness of the username, which is just a caveat you'll wanna keep combined. I should mention that it is possible to enforce username uniqueness, but it's beyond the scope of this video.

Now we can move on to the chat component, which is where we will query items from the database and also give the user the ability to send a message. The component has 2 pieces of state, a string for a new message that the user will type into a form input and an array of messages, which will contain the message text along with the user who sent it and a timestamp. To query messages, as I'm going to set up the on mount life cycle hook that will run whenever that component is first initialized. Inside of it, we'll use the database to make a reference to the chat node. Coded.

In this demo, since we have one giant super chat, we can just give it a name of chat. But if you have multiple chat rooms, you'd likely want to give each one a name. After that, we'll call map to basically loop over every single message in the chat and then call once to only read each message once. In this case, each message is immutable, so we don't need to listen to changes in real time, but you could do that if you wanted to using the on method. We can then define a callback that will be called on each new message that will give us access to the data and the ID of that node.

Now if the data is defined, we're going to format a message that's more suitable for the UI with the properties of who, what, and when. Who is the user that sent the message, and we can figure out who sent it by taking that data of the raw message and using it to get the alias. Next, we have what, which is the actual text of the user's message. But the interesting thing here is that we're actually implementing end to end encryption. That means the value in the database is encrypted and the only way to decrypt it is to have the corresponding key.

In this demo, our data is encrypted, but it's not really secure because I'm just hard coding the encryption key right here in the source code so anybody could find it. But if it was an actual secret between 2 users, you could use it to encrypt and decrypt messages. And finally, we have the when property. To get an accurate time stamp across all of our users, We're using gun state as the final source of truth with the raw data. That'll give us all the data we need for the UI.

Then the final step is to take each message and add it to an array that we can then loop over in the UI with Svelte. You can loop over an array of items in Svelte with each. This will render the chat message component for each message in the array. And also notice how I'm adding parenthesis with message when, which provides Svelte with a unique key to sort all of the messages sufficiently. That gives us a way to read messages in the chat.

Now we just need a form to submit them. In the UI, you'll notice that I have a form that on the submit event will call the send message function. Inside the function, the first thing we'll wanna do is use c to encrypt the actual message text, and notice how the key is the same as the one we used earlier to decrypt the messages. From there, we can associate the message to the current user using the encrypted message as the Kevalu. Then we'll create a date to serve as the index for the message so it can be sorted properly, at which point we can reference the chat collection, create a new node based on that index, ex and store the message value.

Congratulations. You just built a decentralized chat app. It'll be interesting to see if this thing actually works when the video is released. Let me know how things go for you in the comments. Make sure to like and subscribe.

Thanks for watching, and I will see you in the next one.
I recently built a chat app that can handle thousands of messages per second, scales around the world, and cost me nothing to run. But the real weird thing about it is that the data and infrastructure is not controlled by a big tech company. Instead, it's decentralized across the entire user base using web technologies. In fact, you can chat with me right now on the live demo by going to gunchatdap.web.app. Again, that's gunchatdap.web.app. And I'm trusting you not to hack to pieces this time. In today's video, we'll build a decentralized chat app or dApp if you prefer, similar to YouTube Super Chat using a a library called gun. Js. In the process, you'll learn about the benefits of building a decentralized app along with the weird trade offs and challenges. For the front end UI, we'll use Svelte, a JavaScript library that's not sponsored by Big Tech. If you're new here, like and subscribe, and you'll find the full source code on GitHub.
telecommunications
internet
software
networking
software development
infrastructure
technology
video gaming
Then I want to give a shout out to Mark Nadal, the creator of gun. Js, who donated a bunch of his time to answer all my questions and help make this video happen. Before we jump into the code, let's first answer the question of how does this thing actually work?
I made a short video about gun. Js a few weeks ago and you guys had a ton of questions about it. At a high level. Gun. Js is a decentralized graph database. A normal database would store all of your data in a hard disk somewhere in the cloud. It may be sharded across multiple machines, but for all intents and purposes, you can imagine your entire dataset on a single disk. Gun, on the other hand, stores a small subset of data on each user based on the actual data that they consume in the application. When a user makes a query for some data, it will search across the network for other users that have that data and sync it up using technologies like WebRTC. So you can think of the entire database as the union of all peers on the network. Connected. The idea is very similar to a blockchain ledger where no one individual has control of the entire network, but it's important to point out that this is not blockchain technology, which tends to be too slow and just unnecessary to build something like a super chat. However, it does rely heavily on cryptography to implement things like user authentication. When you create a new user account, a cryptographically secure key pair is generated. The username is associated with the public key so past messages can found, and the password is a proof of work seed to prove and decrypt access to the account's private keys. In addition, it's possible to implement end end encryption, which we'll do in this demo, but we'll talk more about that later in the video.
networking
firearms
data
databases
cryptocurrency
security
data management
weapons
internet
data analysis
Another good question is how is data persisted good, and what happens if a user just clears out their browser cache? By default, data is stored in the browser's local storage, which is limited to 5 megabytes. And if the user clears out the data in local storage, it could potentially be lost if it's not somewhere else on the network. That's probably not acceptable if you're building a production grade app.
But what you can do is deploy a relay server that uses a different storage mechanism called RADIX that can store a lot more data on the disk of an actual server. And that makes the network more robust because a query can fall back to a relay if it's not available from another peer. Now, another really important concept to understand is that when you create a node in the database, it'll be available to the entire decentralized network. That means another developer can easily access your public data by simply knowing the name of the node where it's stored.
databases
networking
internet
Now it is possible to encrypt data and things like that, but it just requires a completely different mental model than you might be used to.
Let's go ahead and jump into the source code. I'm not going to cover every single line of code in this project and instead just focus on the important parts related to the database. What we have here is a Svelte app with 2 main features, email password user authentication, and then a massive group chat room that anybody can join.
databases
programming
The only dependency in this project is gun, which can be installed with NPM. The first thing we'll focus on is user authentication, and to do that, I'm creating a file called user dotjs. At the top of the file, we'll import gun, and below that, import 2 supporting libraries. The first one c, which stands for security the encryption and authorization, and is the module that enables user authentication. Next, we have axe, which stands for advanced exchange equation, and is basically an alternative way to connect peers together and tends to be more performant for a chat app like this, and there's a whole doc on it if you wanna learn more. From there, we'll create a variable called db to initialize the database, then we'll use it to make a reference to the currently authenticated user. I'm also chaining the option of recall all to session storage here, so the user stays logged in between browser sessions. Now to manage the user in the app, we need to know if the user is logged in, and we also want their username so we can show it in the UI.
databases
firearms
software
weapons
data management
nuclear weapons
We can get the username by making a reference to the user, then calling git alias, which will be the value of whatever username they choose when they sign up. Now we're going to use this value frequently throughout the application, so I'm importing writable from Svelte store to make it reactive. A store is like an observable value that will rerender the UI whenever it's changed, and it can be shared across multiple components. So whenever the alias for the current user updates, we'll set the value of the store to that value.
software development
programming
But we also want to listen to changes to the auth state when the user signs in or signs out. To handle that, we'll listen to the auth event on the database and basically do the same thing here where we fetch the alias and then set that as the value on the store. Now I'm going to kinda do things in reverse here because I first want to show you how the store works in Svelte. We have this header component here that will show the title of the app if you're not logged in, but if you are logged in, it'll show your username as well as your avatar. Now implementing sign out is really easy. All we have to do is import the username store and the gun user object, then we'll create a function called sign out that calls leave on the user and sets the username store to an empty string. Then down in the HTML, we have a button that when clicked will call the sign out function. But we only want to show that button if the user is signed in.
And the way we can tell if a user is signed in is if their username is present. The cool thing about spelled is that we can easily do that with a store in any component by adding an if statement followed by a dollar sign and then the name of the store. The dollar sign will subscribed to the store and react to any changes that happened to it. If the username does exist, then we'll go ahead and show the username by subscribing to the store once again. We can also do the same contained to show an avatar with the user's initials by using the awesome dice bear API.
customers
advertising
I made a short video about this already, but dice bear will basically make a unique an avatar based on the username as the random seed. Then after that, we have a button that fires the sign out function when clicked. And finally, we'll add an else block here to show something else if the user is not logged in. That takes care of the header component, and you'll notice that I'm declaring it here in the app component. And now we can move on to the login component that will allow the user to sign in or sign up with their username and password. In the component, we'll import the user object, then set up local state for the username and password. In Svelte, we can implement 2 way data binding with a variable by creating a form input and then saying bind value to that variable. Full. That means anytime the user types into the form, the value of the variable will change. We have separate form inputs for username and password, and we'll share them for both the login and sign up process, which itself just consists of 2 different buttons that will either call the login function or the sign up function. To log a user in, we use the user auth method. It takes the username and password as arguments, then the third argument allows you to define a callback. In this case, the value of the store that we set up earlier will update automatically, but we can do other things here as well like error handling. Now the process to sign up a new user is very similar, but instead of calling auth, we call that create method on the user. And if the user creation is successful, then we will log that user in automatically. Now at this point, we have a working user authentication system. But one thing to keep in mind here is that we're not enforcing the uniqueness of the username, which is just a caveat you'll wanna keep combined. I should mention that it is possible to enforce username uniqueness, but it's beyond the scope of this video. Now we can move on to the chat component, which is where we will query items from the database and also give the user the ability to send a message. The component has 2 pieces of state, a string for a new message that the user will type into a form input and an array of messages, which will contain the message text along with the user who sent it and a timestamp. To query messages, as I'm going to set up the on mount life cycle hook that will run whenever that component is first initialized. Inside of it, we'll use the database to make a reference to the chat node. Coded. In this demo, since we have one giant super chat, we can just give it a name of chat. But if you have multiple chat rooms, you'd likely want to give each one a name. After that, we'll call map to basically loop over every single message in the chat and then call once to only read each message once. In this case, each message is immutable, so we don't need to listen to changes in real time, but you could do that if you wanted to using the on method.
We can then define a callback that will be called on each new message that will give us access to the data and the ID of that node. Now if the data is defined, we're going to format a message that's more suitable for the UI with the properties of who, what, and when. Who is the user that sent the message, and we can figure out who sent it by taking that data of the raw message and using it to get the alias.
data
programming
data management
Next, we have what, which is the actual text of the user's message. But the interesting thing here is that we're actually implementing end to end encryption. That means the value in the database is encrypted and the only way to decrypt it is to have the corresponding key. In this demo, our data is encrypted, but it's not really secure because I'm just hard coding the encryption key right here in the source code so anybody could find it.
cryptocurrency
security
But if it was an actual secret between 2 users, you could use it to encrypt and decrypt messages. And finally, we have the when property. To get an accurate time stamp across all of our users, We're using gun state as the final source of truth with the raw data. That'll give us all the data we need for the UI. Then the final step is to take each message and add it to an array that we can then loop over in the UI with Svelte. You can loop over an array of items in Svelte with each. This will render the chat message component for each message in the array.
security
data
programming
And also notice how I'm adding parenthesis with message when, which provides Svelte with a unique key to sort all of the messages sufficiently. That gives us a way to read messages in the chat. Now we just need a form to submit them. In the UI, you'll notice that I have a form that on the submit event will call the send message function. Inside the function, the first thing we'll wanna do is use c to encrypt the actual message text, and notice how the key is the same as the one we used earlier to decrypt the messages. From there, we can associate the message to the current user using the encrypted message as the Kevalu. Then we'll create a date to serve as the index for the message so it can be sorted properly, at which point we can reference the chat collection, create a new node based on that index, ex and store the message value.
Congratulations. You just built a decentralized chat app. It'll be interesting to see if this thing actually works when the video is released. Let me know how things go for you in the comments. Make sure to like and subscribe. Thanks for watching, and I will see you in the next one.
podcasts
youtube
entertainment
television
streaming
media
I recently built a chat app that can handle thousands of messages per second, scales around the world, and cost me nothing to run. But the real weird thing about it is that the data and infrastructure is not controlled by a big tech company. Instead, it's decentralized across the entire user base using web technologies. In fact, you can chat with me right now on the live demo by going to gunchatdap.web.app. Again, that's gunchatdap.web.app. And I'm trusting you not to hack to pieces this time. In today's video, we'll build a decentralized chat app or dApp if you prefer, similar to YouTube Super Chat using a a library called gun. Js. In the process, you'll learn about the benefits of building a decentralized app along with the weird trade offs and challenges. For the front end UI, we'll use Svelte, a JavaScript library that's not sponsored by Big Tech. If you're new here, like and subscribe, and you'll find the full source code on GitHub. Then I want to give a shout out to Mark Nadal, the creator of gun. Js, who donated a bunch of his time to answer all my questions and help make this video happen. Before we jump into the code, let's first answer the question of how does this thing actually work? I made a short video about gun. Js a few weeks ago and you guys had a ton of questions about it. At a high level. Gun. Js is a decentralized graph database. A normal database would store all of your data in a hard disk somewhere in the cloud. It may be sharded across multiple machines, but for all intents and purposes, you can imagine your entire dataset on a single disk. Gun, on the other hand, stores a small subset of data on each user based on the actual data that they consume in the application. When a user makes a query for some data, it will search across the network for other users that have that data and sync it up using technologies like WebRTC. So you can think of the entire database as the union of all peers on the network. Connected. The idea is very similar to a blockchain ledger where no one individual has control of the entire network, but it's important to point out that this is not blockchain technology, which tends to be too slow and just unnecessary to build something like a super chat. However, it does rely heavily on cryptography to implement things like user authentication. When you create a new user account, a cryptographically secure key pair is generated. The username is associated with the public key so past messages can found, and the password is a proof of work seed to prove and decrypt access to the account's private keys. In addition, it's possible to implement end end encryption, which we'll do in this demo, but we'll talk more about that later in the video. Another good question is how is data persisted good, and what happens if a user just clears out their browser cache? By default, data is stored in the browser's local storage, which is limited to 5 megabytes. And if the user clears out the data in local storage, it could potentially be lost if it's not somewhere else on the network. That's probably not acceptable if you're building a production grade app. But what you can do is deploy a relay server that uses a different storage mechanism called RADIX that can store a lot more data on the disk of an actual server. And that makes the network more robust because a query can fall back to a relay if it's not available from another peer. Now, another really important concept to understand is that when you create a node in the database, it'll be available to the entire decentralized network. That means another developer can easily access your public data by simply knowing the name of the node where it's stored. Now it is possible to encrypt data and things like that, but it just requires a completely different mental model than you might be used to. Let's go ahead and jump into the source code. I'm not going to cover every single line of code in this project and instead just focus on the important parts related to the database. What we have here is a Svelte app with 2 main features, email password user authentication, and then a massive group chat room that anybody can join. The only dependency in this project is gun, which can be installed with NPM. The first thing we'll focus on is user authentication, and to do that, I'm creating a file called user dotjs. At the top of the file, we'll import gun, and below that, import 2 supporting libraries. The first one c, which stands for security the encryption and authorization, and is the module that enables user authentication. Next, we have axe, which stands for advanced exchange equation, and is basically an alternative way to connect peers together and tends to be more performant for a chat app like this, and there's a whole doc on it if you wanna learn more. From there, we'll create a variable called db to initialize the database, then we'll use it to make a reference to the currently authenticated user. I'm also chaining the option of recall all to session storage here, so the user stays logged in between browser sessions. Now to manage the user in the app, we need to know if the user is logged in, and we also want their username so we can show it in the UI. We can get the username by making a reference to the user, then calling git alias, which will be the value of whatever username they choose when they sign up. Now we're going to use this value frequently throughout the application, so I'm importing writable from Svelte store to make it reactive. A store is like an observable value that will rerender the UI whenever it's changed, and it can be shared across multiple components. So whenever the alias for the current user updates, we'll set the value of the store to that value. But we also want to listen to changes to the auth state when the user signs in or signs out. To handle that, we'll listen to the auth event on the database and basically do the same thing here where we fetch the alias and then set that as the value on the store. Now I'm going to kinda do things in reverse here because I first want to show you how the store works in Svelte. We have this header component here that will show the title of the app if you're not logged in, but if you are logged in, it'll show your username as well as your avatar. Now implementing sign out is really easy. All we have to do is import the username store and the gun user object, then we'll create a function called sign out that calls leave on the user and sets the username store to an empty string. Then down in the HTML, we have a button that when clicked will call the sign out function. But we only want to show that button if the user is signed in. And the way we can tell if a user is signed in is if their username is present. The cool thing about spelled is that we can easily do that with a store in any component by adding an if statement followed by a dollar sign and then the name of the store. The dollar sign will subscribed to the store and react to any changes that happened to it. If the username does exist, then we'll go ahead and show the username by subscribing to the store once again. We can also do the same contained to show an avatar with the user's initials by using the awesome dice bear API. I made a short video about this already, but dice bear will basically make a unique an avatar based on the username as the random seed. Then after that, we have a button that fires the sign out function when clicked. And finally, we'll add an else block here to show something else if the user is not logged in. That takes care of the header component, and you'll notice that I'm declaring it here in the app component. And now we can move on to the login component that will allow the user to sign in or sign up with their username and password. In the component, we'll import the user object, then set up local state for the username and password. In Svelte, we can implement 2 way data binding with a variable by creating a form input and then saying bind value to that variable. Full. That means anytime the user types into the form, the value of the variable will change. We have separate form inputs for username and password, and we'll share them for both the login and sign up process, which itself just consists of 2 different buttons that will either call the login function or the sign up function. To log a user in, we use the user auth method. It takes the username and password as arguments, then the third argument allows you to define a callback. In this case, the value of the store that we set up earlier will update automatically, but we can do other things here as well like error handling. Now the process to sign up a new user is very similar, but instead of calling auth, we call that create method on the user. And if the user creation is successful, then we will log that user in automatically. Now at this point, we have a working user authentication system. But one thing to keep in mind here is that we're not enforcing the uniqueness of the username, which is just a caveat you'll wanna keep combined. I should mention that it is possible to enforce username uniqueness, but it's beyond the scope of this video. Now we can move on to the chat component, which is where we will query items from the database and also give the user the ability to send a message. The component has 2 pieces of state, a string for a new message that the user will type into a form input and an array of messages, which will contain the message text along with the user who sent it and a timestamp. To query messages, as I'm going to set up the on mount life cycle hook that will run whenever that component is first initialized. Inside of it, we'll use the database to make a reference to the chat node. Coded. In this demo, since we have one giant super chat, we can just give it a name of chat. But if you have multiple chat rooms, you'd likely want to give each one a name. After that, we'll call map to basically loop over every single message in the chat and then call once to only read each message once. In this case, each message is immutable, so we don't need to listen to changes in real time, but you could do that if you wanted to using the on method. We can then define a callback that will be called on each new message that will give us access to the data and the ID of that node. Now if the data is defined, we're going to format a message that's more suitable for the UI with the properties of who, what, and when. Who is the user that sent the message, and we can figure out who sent it by taking that data of the raw message and using it to get the alias. Next, we have what, which is the actual text of the user's message. But the interesting thing here is that we're actually implementing end to end encryption. That means the value in the database is encrypted and the only way to decrypt it is to have the corresponding key. In this demo, our data is encrypted, but it's not really secure because I'm just hard coding the encryption key right here in the source code so anybody could find it. But if it was an actual secret between 2 users, you could use it to encrypt and decrypt messages. And finally, we have the when property. To get an accurate time stamp across all of our users, We're using gun state as the final source of truth with the raw data. That'll give us all the data we need for the UI. Then the final step is to take each message and add it to an array that we can then loop over in the UI with Svelte. You can loop over an array of items in Svelte with each. This will render the chat message component for each message in the array. And also notice how I'm adding parenthesis with message when, which provides Svelte with a unique key to sort all of the messages sufficiently. That gives us a way to read messages in the chat. Now we just need a form to submit them. In the UI, you'll notice that I have a form that on the submit event will call the send message function. Inside the function, the first thing we'll wanna do is use c to encrypt the actual message text, and notice how the key is the same as the one we used earlier to decrypt the messages. From there, we can associate the message to the current user using the encrypted message as the Kevalu. Then we'll create a date to serve as the index for the message so it can be sorted properly, at which point we can reference the chat collection, create a new node based on that index, ex and store the message value. Congratulations. You just built a decentralized chat app. It'll be interesting to see if this thing actually works when the video is released. Let me know how things go for you in the comments. Make sure to like and subscribe. Thanks for watching, and I will see you in the next one.
I
i
recently
recently
built
built
a
a
chat
chat
app
app
that
that
can
can
handle
handle
thousands
thousands
of
of
messages
messages
per
per
second,
second
scales
scales
around
around
the
the
world,
world
and
and
cost
cost
me
me
nothing
nothing
to
to
run.
run
But
but
the
the
real
real
weird
weird
thing
thing
about
about
it
it
is
is
that
that
the
the
data
data
and
and
infrastructure
infrastructure
is
is
not
not
controlled
controlled
by
by
a
a
big
big
tech
tech
company.
company
Instead,
instead
it's
it's
decentralized
decentralized
across
across
the
the
entire
entire
user
user
base
base
using
using
web
web
technologies.
technologies
In
in
fact,
fact
you
you
can
can
chat
chat
with
with
me
me
right
right
now
now
on
on
the
the
live
live
demo
demo
by
by
going
going
to
to
gunchatdap.web.app.
gunchatdap.web.app
Again,
again
that's
that's
gunchatdap.web.app.
gunchatdap.web.app
And
and
I'm
i'm
trusting
trusting
you
you
not
not
to
to
hack
hack
to
to
pieces
pieces
this
this
time.
time
In
in
today's
today's
video,
video
we'll
we'll
build
build
a
a
decentralized
decentralized
chat
chat
app
app
or
or
dApp
dapp
if
if
you
you
prefer,
prefer
similar
similar
to
to
YouTube
youtube
Super
super
Chat
chat
using
using
a
a
a
a
library
library
called
called
gun.
gun
Js.
js
In
in
the
the
process,
process
you'll
you'll
learn
learn
about
about
the
the
benefits
benefits
of
of
building
building
a
a
decentralized
decentralized
app
app
along
along
with
with
the
the
weird
weird
trade
trade
offs
offs
and
and
challenges.
challenges
For
for
the
the
front
front
end
end
UI,
ui
we'll
we'll
use
use
Svelte,
svelte
a
a
JavaScript
javascript
library
library
that's
that's
not
not
sponsored
sponsored
by
by
Big
big
Tech.
tech
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe,
subscribe
and
and
you'll
you'll
find
find
the
the
full
full
source
source
code
code
on
on
GitHub.
github
Then
then
I
i
want
want
to
to
give
give
a
a
shout
shout
out
out
to
to
Mark
mark
Nadal,
nadal
the
the
creator
creator
of
of
gun.
gun
Js,
js
who
who
donated
donated
a
a
bunch
bunch
of
of
his
his
time
time
to
to
answer
answer
all
all
my
my
questions
questions
and
and
help
help
make
make
this
this
video
video
happen.
happen
Before
before
we
we
jump
jump
into
into
the
the
code,
code
let's
let's
first
first
answer
answer
the
the
question
question
of
of
how
how
does
does
this
this
thing
thing
actually
actually
work?
work
I
i
made
made
a
a
short
short
video
video
about
about
gun.
gun
Js
js
a
a
few
few
weeks
weeks
ago
ago
and
and
you
you
guys
guys
had
had
a
a
ton
ton
of
of
questions
questions
about
about
it.
it
At
at
a
a
high
high
level.
level
Gun.
gun
Js
js
is
is
a
a
decentralized
decentralized
graph
graph
database.
database
A
a
normal
normal
database
database
would
would
store
store
all
all
of
of
your
your
data
data
in
in
a
a
hard
hard
disk
disk
somewhere
somewhere
in
in
the
the
cloud.
cloud
It
it
may
may
be
be
sharded
sharded
across
across
multiple
multiple
machines,
machines
but
but
for
for
all
all
intents
intents
and
and
purposes,
purposes
you
you
can
can
imagine
imagine
your
your
entire
entire
dataset
dataset
on
on
a
a
single
single
disk.
disk
Gun,
gun
on
on
the
the
other
other
hand,
hand
stores
stores
a
a
small
small
subset
subset
of
of
data
data
on
on
each
each
user
user
based
based
on
on
the
the
actual
actual
data
data
that
that
they
they
consume
consume
in
in
the
the
application.
application
When
when
a
a
user
user
makes
makes
a
a
query
query
for
for
some
some
data,
data
it
it
will
will
search
search
across
across
the
the
network
network
for
for
other
other
users
users
that
that
have
have
that
that
data
data
and
and
sync
sync
it
it
up
up
using
using
technologies
technologies
like
like
WebRTC.
webrtc
So
so
you
you
can
can
think
think
of
of
the
the
entire
entire
database
database
as
as
the
the
union
union
of
of
all
all
peers
peers
on
on
the
the
network.
network
Connected.
connected
The
the
idea
idea
is
is
very
very
similar
similar
to
to
a
a
blockchain
blockchain
ledger
ledger
where
where
no
no
one
one
individual
individual
has
has
control
control
of
of
the
the
entire
entire
network,
network
but
but
it's
it's
important
important
to
to
point
point
out
out
that
that
this
this
is
is
not
not
blockchain
blockchain
technology,
technology
which
which
tends
tends
to
to
be
be
too
too
slow
slow
and
and
just
just
unnecessary
unnecessary
to
to
build
build
something
something
like
like
a
a
super
super
chat.
chat
However,
however
it
it
does
does
rely
rely
heavily
heavily
on
on
cryptography
cryptography
to
to
implement
implement
things
things
like
like
user
user
authentication.
authentication
When
when
you
you
create
create
a
a
new
new
user
user
account,
account
a
a
cryptographically
cryptographically
secure
secure
key
key
pair
pair
is
is
generated.
generated
The
the
username
username
is
is
associated
associated
with
with
the
the
public
public
key
key
so
so
past
past
messages
messages
can
can
found,
found
and
and
the
the
password
password
is
is
a
a
proof
proof
of
of
work
work
seed
seed
to
to
prove
prove
and
and
decrypt
decrypt
access
access
to
to
the
the
account's
account's
private
private
keys.
keys
In
in
addition,
addition
it's
it's
possible
possible
to
to
implement
implement
end
end
end
end
encryption,
encryption
which
which
we'll
we'll
do
do
in
in
this
this
demo,
demo
but
but
we'll
we'll
talk
talk
more
more
about
about
that
that
later
later
in
in
the
the
video.
video
Another
another
good
good
question
question
is
is
how
how
is
is
data
data
persisted
persisted
good,
good
and
and
what
what
happens
happens
if
if
a
a
user
user
just
just
clears
clears
out
out
their
their
browser
browser
cache?
cache
By
by
default,
default
data
data
is
is
stored
stored
in
in
the
the
browser's
browser's
local
local
storage,
storage
which
which
is
is
limited
limited
to
to
5
5
megabytes.
megabytes
And
and
if
if
the
the
user
user
clears
clears
out
out
the
the
data
data
in
in
local
local
storage,
storage
it
it
could
could
potentially
potentially
be
be
lost
lost
if
if
it's
it's
not
not
somewhere
somewhere
else
else
on
on
the
the
network.
network
That's
that's
probably
probably
not
not
acceptable
acceptable
if
if
you're
you're
building
building
a
a
production
production
grade
grade
app.
app
But
but
what
what
you
you
can
can
do
do
is
is
deploy
deploy
a
a
relay
relay
server
server
that
that
uses
uses
a
a
different
different
storage
storage
mechanism
mechanism
called
called
RADIX
radix
that
that
can
can
store
store
a
a
lot
lot
more
more
data
data
on
on
the
the
disk
disk
of
of
an
an
actual
actual
server.
server
And
and
that
that
makes
makes
the
the
network
network
more
more
robust
robust
because
because
a
a
query
query
can
can
fall
fall
back
back
to
to
a
a
relay
relay
if
if
it's
it's
not
not
available
available
from
from
another
another
peer.
peer
Now,
now
another
another
really
really
important
important
concept
concept
to
to
understand
understand
is
is
that
that
when
when
you
you
create
create
a
a
node
node
in
in
the
the
database,
database
it'll
it'll
be
be
available
available
to
to
the
the
entire
entire
decentralized
decentralized
network.
network
That
that
means
means
another
another
developer
developer
can
can
easily
easily
access
access
your
your
public
public
data
data
by
by
simply
simply
knowing
knowing
the
the
name
name
of
of
the
the
node
node
where
where
it's
it's
stored.
stored
Now
now
it
it
is
is
possible
possible
to
to
encrypt
encrypt
data
data
and
and
things
things
like
like
that,
that
but
but
it
it
just
just
requires
requires
a
a
completely
completely
different
different
mental
mental
model
model
than
than
you
you
might
might
be
be
used
used
to.
to
Let's
let's
go
go
ahead
ahead
and
and
jump
jump
into
into
the
the
source
source
code.
code
I'm
i'm
not
not
going
going
to
to
cover
cover
every
every
single
single
line
line
of
of
code
code
in
in
this
this
project
project
and
and
instead
instead
just
just
focus
focus
on
on
the
the
important
important
parts
parts
related
related
to
to
the
the
database.
database
What
what
we
we
have
have
here
here
is
is
a
a
Svelte
svelte
app
app
with
with
2
2
main
main
features,
features
email
email
password
password
user
user
authentication,
authentication
and
and
then
then
a
a
massive
massive
group
group
chat
chat
room
room
that
that
anybody
anybody
can
can
join.
join
The
the
only
only
dependency
dependency
in
in
this
this
project
project
is
is
gun,
gun
which
which
can
can
be
be
installed
installed
with
with
NPM.
npm
The
the
first
first
thing
thing
we'll
we'll
focus
focus
on
on
is
is
user
user
authentication,
authentication
and
and
to
to
do
do
that,
that
I'm
i'm
creating
creating
a
a
file
file
called
called
user
user
dotjs.
dotjs
At
at
the
the
top
top
of
of
the
the
file,
file
we'll
we'll
import
import
gun,
gun
and
and
below
below
that,
that
import
import
2
2
supporting
supporting
libraries.
libraries
The
the
first
first
one
one
c,
c
which
which
stands
stands
for
for
security
security
the
the
encryption
encryption
and
and
authorization,
authorization
and
and
is
is
the
the
module
module
that
that
enables
enables
user
user
authentication.
authentication
Next,
next
we
we
have
have
axe,
axe
which
which
stands
stands
for
for
advanced
advanced
exchange
exchange
equation,
equation
and
and
is
is
basically
basically
an
an
alternative
alternative
way
way
to
to
connect
connect
peers
peers
together
together
and
and
tends
tends
to
to
be
be
more
more
performant
performant
for
for
a
a
chat
chat
app
app
like
like
this,
this
and
and
there's
there's
a
a
whole
whole
doc
doc
on
on
it
it
if
if
you
you
wanna
wanna
learn
learn
more.
more
From
from
there,
there
we'll
we'll
create
create
a
a
variable
variable
called
called
db
db
to
to
initialize
initialize
the
the
database,
database
then
then
we'll
we'll
use
use
it
it
to
to
make
make
a
a
reference
reference
to
to
the
the
currently
currently
authenticated
authenticated
user.
user
I'm
i'm
also
also
chaining
chaining
the
the
option
option
of
of
recall
recall
all
all
to
to
session
session
storage
storage
here,
here
so
so
the
the
user
user
stays
stays
logged
logged
in
in
between
between
browser
browser
sessions.
sessions
Now
now
to
to
manage
manage
the
the
user
user
in
in
the
the
app,
app
we
we
need
need
to
to
know
know
if
if
the
the
user
user
is
is
logged
logged
in,
in
and
and
we
we
also
also
want
want
their
their
username
username
so
so
we
we
can
can
show
show
it
it
in
in
the
the
UI.
ui
We
we
can
can
get
get
the
the
username
username
by
by
making
making
a
a
reference
reference
to
to
the
the
user,
user
then
then
calling
calling
git
git
alias,
alias
which
which
will
will
be
be
the
the
value
value
of
of
whatever
whatever
username
username
they
they
choose
choose
when
when
they
they
sign
sign
up.
up
Now
now
we're
we're
going
going
to
to
use
use
this
this
value
value
frequently
frequently
throughout
throughout
the
the
application,
application
so
so
I'm
i'm
importing
importing
writable
writable
from
from
Svelte
svelte
store
store
to
to
make
make
it
it
reactive.
reactive
A
a
store
store
is
is
like
like
an
an
observable
observable
value
value
that
that
will
will
rerender
rerender
the
the
UI
ui
whenever
whenever
it's
it's
changed,
changed
and
and
it
it
can
can
be
be
shared
shared
across
across
multiple
multiple
components.
components
So
so
whenever
whenever
the
the
alias
alias
for
for
the
the
current
current
user
user
updates,
updates
we'll
we'll
set
set
the
the
value
value
of
of
the
the
store
store
to
to
that
that
value.
value
But
but
we
we
also
also
want
want
to
to
listen
listen
to
to
changes
changes
to
to
the
the
auth
auth
state
state
when
when
the
the
user
user
signs
signs
in
in
or
or
signs
signs
out.
out
To
to
handle
handle
that,
that
we'll
we'll
listen
listen
to
to
the
the
auth
auth
event
event
on
on
the
the
database
database
and
and
basically
basically
do
do
the
the
same
same
thing
thing
here
here
where
where
we
we
fetch
fetch
the
the
alias
alias
and
and
then
then
set
set
that
that
as
as
the
the
value
value
on
on
the
the
store.
store
Now
now
I'm
i'm
going
going
to
to
kinda
kinda
do
do
things
things
in
in
reverse
reverse
here
here
because
because
I
i
first
first
want
want
to
to
show
show
you
you
how
how
the
the
store
store
works
works
in
in
Svelte.
svelte
We
we
have
have
this
this
header
header
component
component
here
here
that
that
will
will
show
show
the
the
title
title
of
of
the
the
app
app
if
if
you're
you're
not
not
logged
logged
in,
in
but
but
if
if
you
you
are
are
logged
logged
in,
in
it'll
it'll
show
show
your
your
username
username
as
as
well
well
as
as
your
your
avatar.
avatar
Now
now
implementing
implementing
sign
sign
out
out
is
is
really
really
easy.
easy
All
all
we
we
have
have
to
to
do
do
is
is
import
import
the
the
username
username
store
store
and
and
the
the
gun
gun
user
user
object,
object
then
then
we'll
we'll
create
create
a
a
function
function
called
called
sign
sign
out
out
that
that
calls
calls
leave
leave
on
on
the
the
user
user
and
and
sets
sets
the
the
username
username
store
store
to
to
an
an
empty
empty
string.
string
Then
then
down
down
in
in
the
the
HTML,
html
we
we
have
have
a
a
button
button
that
that
when
when
clicked
clicked
will
will
call
call
the
the
sign
sign
out
out
function.
function
But
but
we
we
only
only
want
want
to
to
show
show
that
that
button
button
if
if
the
the
user
user
is
is
signed
signed
in.
in
And
and
the
the
way
way
we
we
can
can
tell
tell
if
if
a
a
user
user
is
is
signed
signed
in
in
is
is
if
if
their
their
username
username
is
is
present.
present
The
the
cool
cool
thing
thing
about
about
spelled
spelled
is
is
that
that
we
we
can
can
easily
easily
do
do
that
that
with
with
a
a
store
store
in
in
any
any
component
component
by
by
adding
adding
an
an
if
if
statement
statement
followed
followed
by
by
a
a
dollar
dollar
sign
sign
and
and
then
then
the
the
name
name
of
of
the
the
store.
store
The
the
dollar
dollar
sign
sign
will
will
subscribed
subscribed
to
to
the
the
store
store
and
and
react
react
to
to
any
any
changes
changes
that
that
happened
happened
to
to
it.
it
If
if
the
the
username
username
does
does
exist,
exist
then
then
we'll
we'll
go
go
ahead
ahead
and
and
show
show
the
the
username
username
by
by
subscribing
subscribing
to
to
the
the
store
store
once
once
again.
again
We
we
can
can
also
also
do
do
the
the
same
same
contained
contained
to
to
show
show
an
an
avatar
avatar
with
with
the
the
user's
user's
initials
initials
by
by
using
using
the
the
awesome
awesome
dice
dice
bear
bear
API.
api
I
i
made
made
a
a
short
short
video
video
about
about
this
this
already,
already
but
but
dice
dice
bear
bear
will
will
basically
basically
make
make
a
a
unique
unique
an
an
avatar
avatar
based
based
on
on
the
the
username
username
as
as
the
the
random
random
seed.
seed
Then
then
after
after
that,
that
we
we
have
have
a
a
button
button
that
that
fires
fires
the
the
sign
sign
out
out
function
function
when
when
clicked.
clicked
And
and
finally,
finally
we'll
we'll
add
add
an
an
else
else
block
block
here
here
to
to
show
show
something
something
else
else
if
if
the
the
user
user
is
is
not
not
logged
logged
in.
in
That
that
takes
takes
care
care
of
of
the
the
header
header
component,
component
and
and
you'll
you'll
notice
notice
that
that
I'm
i'm
declaring
declaring
it
it
here
here
in
in
the
the
app
app
component.
component
And
and
now
now
we
we
can
can
move
move
on
on
to
to
the
the
login
login
component
component
that
that
will
will
allow
allow
the
the
user
user
to
to
sign
sign
in
in
or
or
sign
sign
up
up
with
with
their
their
username
username
and
and
password.
password
In
in
the
the
component,
component
we'll
we'll
import
import
the
the
user
user
object,
object
then
then
set
set
up
up
local
local
state
state
for
for
the
the
username
username
and
and
password.
password
In
in
Svelte,
svelte
we
we
can
can
implement
implement
2
2
way
way
data
data
binding
binding
with
with
a
a
variable
variable
by
by
creating
creating
a
a
form
form
input
input
and
and
then
then
saying
saying
bind
bind
value
value
to
to
that
that
variable.
variable
Full.
full
That
that
means
means
anytime
anytime
the
the
user
user
types
types
into
into
the
the
form,
form
the
the
value
value
of
of
the
the
variable
variable
will
will
change.
change
We
we
have
have
separate
separate
form
form
inputs
inputs
for
for
username
username
and
and
password,
password
and
and
we'll
we'll
share
share
them
them
for
for
both
both
the
the
login
login
and
and
sign
sign
up
up
process,
process
which
which
itself
itself
just
just
consists
consists
of
of
2
2
different
different
buttons
buttons
that
that
will
will
either
either
call
call
the
the
login
login
function
function
or
or
the
the
sign
sign
up
up
function.
function
To
to
log
log
a
a
user
user
in,
in
we
we
use
use
the
the
user
user
auth
auth
method.
method
It
it
takes
takes
the
the
username
username
and
and
password
password
as
as
arguments,
arguments
then
then
the
the
third
third
argument
argument
allows
allows
you
you
to
to
define
define
a
a
callback.
callback
In
in
this
this
case,
case
the
the
value
value
of
of
the
the
store
store
that
that
we
we
set
set
up
up
earlier
earlier
will
will
update
update
automatically,
automatically
but
but
we
we
can
can
do
do
other
other
things
things
here
here
as
as
well
well
like
like
error
error
handling.
handling
Now
now
the
the
process
process
to
to
sign
sign
up
up
a
a
new
new
user
user
is
is
very
very
similar,
similar
but
but
instead
instead
of
of
calling
calling
auth,
auth
we
we
call
call
that
that
create
create
method
method
on
on
the
the
user.
user
And
and
if
if
the
the
user
user
creation
creation
is
is
successful,
successful
then
then
we
we
will
will
log
log
that
that
user
user
in
in
automatically.
automatically
Now
now
at
at
this
this
point,
point
we
we
have
have
a
a
working
working
user
user
authentication
authentication
system.
system
But
but
one
one
thing
thing
to
to
keep
keep
in
in
mind
mind
here
here
is
is
that
that
we're
we're
not
not
enforcing
enforcing
the
the
uniqueness
uniqueness
of
of
the
the
username,
username
which
which
is
is
just
just
a
a
caveat
caveat
you'll
you'll
wanna
wanna
keep
keep
combined.
combined
I
i
should
should
mention
mention
that
that
it
it
is
is
possible
possible
to
to
enforce
enforce
username
username
uniqueness,
uniqueness
but
but
it's
it's
beyond
beyond
the
the
scope
scope
of
of
this
this
video.
video
Now
now
we
we
can
can
move
move
on
on
to
to
the
the
chat
chat
component,
component
which
which
is
is
where
where
we
we
will
will
query
query
items
items
from
from
the
the
database
database
and
and
also
also
give
give
the
the
user
user
the
the
ability
ability
to
to
send
send
a
a
message.
message
The
the
component
component
has
has
2
2
pieces
pieces
of
of
state,
state
a
a
string
string
for
for
a
a
new
new
message
message
that
that
the
the
user
user
will
will
type
type
into
into
a
a
form
form
input
input
and
and
an
an
array
array
of
of
messages,
messages
which
which
will
will
contain
contain
the
the
message
message
text
text
along
along
with
with
the
the
user
user
who
who
sent
sent
it
it
and
and
a
a
timestamp.
timestamp
To
to
query
query
messages,
messages
as
as
I'm
i'm
going
going
to
to
set
set
up
up
the
the
on
on
mount
mount
life
life
cycle
cycle
hook
hook
that
that
will
will
run
run
whenever
whenever
that
that
component
component
is
is
first
first
initialized.
initialized
Inside
inside
of
of
it,
it
we'll
we'll
use
use
the
the
database
database
to
to
make
make
a
a
reference
reference
to
to
the
the
chat
chat
node.
node
Coded.
coded
In
in
this
this
demo,
demo
since
since
we
we
have
have
one
one
giant
giant
super
super
chat,
chat
we
we
can
can
just
just
give
give
it
it
a
a
name
name
of
of
chat.
chat
But
but
if
if
you
you
have
have
multiple
multiple
chat
chat
rooms,
rooms
you'd
you'd
likely
likely
want
want
to
to
give
give
each
each
one
one
a
a
name.
name
After
after
that,
that
we'll
we'll
call
call
map
map
to
to
basically
basically
loop
loop
over
over
every
every
single
single
message
message
in
in
the
the
chat
chat
and
and
then
then
call
call
once
once
to
to
only
only
read
read
each
each
message
message
once.
once
In
in
this
this
case,
case
each
each
message
message
is
is
immutable,
immutable
so
so
we
we
don't
don't
need
need
to
to
listen
listen
to
to
changes
changes
in
in
real
real
time,
time
but
but
you
you
could
could
do
do
that
that
if
if
you
you
wanted
wanted
to
to
using
using
the
the
on
on
method.
method
We
we
can
can
then
then
define
define
a
a
callback
callback
that
that
will
will
be
be
called
called
on
on
each
each
new
new
message
message
that
that
will
will
give
give
us
us
access
access
to
to
the
the
data
data
and
and
the
the
ID
id
of
of
that
that
node.
node
Now
now
if
if
the
the
data
data
is
is
defined,
defined
we're
we're
going
going
to
to
format
format
a
a
message
message
that's
that's
more
more
suitable
suitable
for
for
the
the
UI
ui
with
with
the
the
properties
properties
of
of
who,
who
what,
what
and
and
when.
when
Who
who
is
is
the
the
user
user
that
that
sent
sent
the
the
message,
message
and
and
we
we
can
can
figure
figure
out
out
who
who
sent
sent
it
it
by
by
taking
taking
that
that
data
data
of
of
the
the
raw
raw
message
message
and
and
using
using
it
it
to
to
get
get
the
the
alias.
alias
Next,
next
we
we
have
have
what,
what
which
which
is
is
the
the
actual
actual
text
text
of
of
the
the
user's
user's
message.
message
But
but
the
the
interesting
interesting
thing
thing
here
here
is
is
that
that
we're
we're
actually
actually
implementing
implementing
end
end
to
to
end
end
encryption.
encryption
That
that
means
means
the
the
value
value
in
in
the
the
database
database
is
is
encrypted
encrypted
and
and
the
the
only
only
way
way
to
to
decrypt
decrypt
it
it
is
is
to
to
have
have
the
the
corresponding
corresponding
key.
key
In
in
this
this
demo,
demo
our
our
data
data
is
is
encrypted,
encrypted
but
but
it's
it's
not
not
really
really
secure
secure
because
because
I'm
i'm
just
just
hard
hard
coding
coding
the
the
encryption
encryption
key
key
right
right
here
here
in
in
the
the
source
source
code
code
so
so
anybody
anybody
could
could
find
find
it.
it
But
but
if
if
it
it
was
was
an
an
actual
actual
secret
secret
between
between
2
2
users,
users
you
you
could
could
use
use
it
it
to
to
encrypt
encrypt
and
and
decrypt
decrypt
messages.
messages
And
and
finally,
finally
we
we
have
have
the
the
when
when
property.
property
To
to
get
get
an
an
accurate
accurate
time
time
stamp
stamp
across
across
all
all
of
of
our
our
users,
users
We're
we're
using
using
gun
gun
state
state
as
as
the
the
final
final
source
source
of
of
truth
truth
with
with
the
the
raw
raw
data.
data
That'll
that'll
give
give
us
us
all
all
the
the
data
data
we
we
need
need
for
for
the
the
UI.
ui
Then
then
the
the
final
final
step
step
is
is
to
to
take
take
each
each
message
message
and
and
add
add
it
it
to
to
an
an
array
array
that
that
we
we
can
can
then
then
loop
loop
over
over
in
in
the
the
UI
ui
with
with
Svelte.
svelte
You
you
can
can
loop
loop
over
over
an
an
array
array
of
of
items
items
in
in
Svelte
svelte
with
with
each.
each
This
this
will
will
render
render
the
the
chat
chat
message
message
component
component
for
for
each
each
message
message
in
in
the
the
array.
array
And
and
also
also
notice
notice
how
how
I'm
i'm
adding
adding
parenthesis
parenthesis
with
with
message
message
when,
when
which
which
provides
provides
Svelte
svelte
with
with
a
a
unique
unique
key
key
to
to
sort
sort
all
all
of
of
the
the
messages
messages
sufficiently.
sufficiently
That
that
gives
gives
us
us
a
a
way
way
to
to
read
read
messages
messages
in
in
the
the
chat.
chat
Now
now
we
we
just
just
need
need
a
a
form
form
to
to
submit
submit
them.
them
In
in
the
the
UI,
ui
you'll
you'll
notice
notice
that
that
I
i
have
have
a
a
form
form
that
that
on
on
the
the
submit
submit
event
event
will
will
call
call
the
the
send
send
message
message
function.
function
Inside
inside
the
the
function,
function
the
the
first
first
thing
thing
we'll
we'll
wanna
wanna
do
do
is
is
use
use
c
c
to
to
encrypt
encrypt
the
the
actual
actual
message
message
text,
text
and
and
notice
notice
how
how
the
the
key
key
is
is
the
the
same
same
as
as
the
the
one
one
we
we
used
used
earlier
earlier
to
to
decrypt
decrypt
the
the
messages.
messages
From
from
there,
there
we
we
can
can
associate
associate
the
the
message
message
to
to
the
the
current
current
user
user
using
using
the
the
encrypted
encrypted
message
message
as
as
the
the
Kevalu.
kevalu
Then
then
we'll
we'll
create
create
a
a
date
date
to
to
serve
serve
as
as
the
the
index
index
for
for
the
the
message
message
so
so
it
it
can
can
be
be
sorted
sorted
properly,
properly
at
at
which
which
point
point
we
we
can
can
reference
reference
the
the
chat
chat
collection,
collection
create
create
a
a
new
new
node
node
based
based
on
on
that
that
index,
index
ex
ex
and
and
store
store
the
the
message
message
value.
value
Congratulations.
congratulations
You
you
just
just
built
built
a
a
decentralized
decentralized
chat
chat
app.
app
It'll
it'll
be
be
interesting
interesting
to
to
see
see
if
if
this
this
thing
thing
actually
actually
works
works
when
when
the
the
video
video
is
is
released.
released
Let
let
me
me
know
know
how
how
things
things
go
go
for
for
you
you
in
in
the
the
comments.
comments
Make
make
sure
sure
to
to
like
like
and
and
subscribe.
subscribe
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
see
see
you
you
in
in
the
the
next
next
one.
one
success
The decentralized chat app (Gant) uses a library called gun to store a small subset of data on each user based on the actual data they consume. The app is decentralized across the entire user base and the front end UI will use Svelte, a JavaScript library. Different features, including email password user authentication, and a massive group chat room, are explained. The process of creating a login component for a decentralized chat app is also discussed, including setting up state, input and send messages, and the use of a form to submit messages. The app is designed to ensure security and promotes viewers to like and subscribe to the video.
I built a decentralized chat dapp // GUN web3 Tutorial
I recently built a chat app that can handle thousands of messages per second, scales around the world, and cost me nothing to run. But the real weird thing about it is that the data and infrastructure is not controlled by a big tech company. Instead, it's decentralized across the entire user base using web technologies. In fact, you can chat with me right now on the live demo by going to gunchatdap.web.app. Again, that's gunchatdap.web.app. And I'm trusting you not to hack to pieces this time. In today's video, we'll build a decentralized chat app or dApp if you prefer, similar to YouTube Super Chat using a a library called gun. Js. In the process, you'll learn about the benefits of building a decentralized app along with the weird trade offs and challenges. For the front end UI, we'll use Svelte, a JavaScript library that's not sponsored by Big Tech. If you're new here, like and subscribe, and you'll find the full source code on GitHub. Then I want to give a shout out to Mark Nadal, the creator of gun. Js, who donated a bunch of his time to answer all my questions and help make this video happen. Before we jump into the code, let's first answer the question of how does this thing actually work? I made a short video about gun. Js a few weeks ago and you guys had a ton of questions about it. At a high level. Gun. Js is a decentralized graph database. A normal database would store all of your data in a hard disk somewhere in the cloud. It may be sharded across multiple machines, but for all intents and purposes, you can imagine your entire dataset on a single disk. Gun, on the other hand, stores a small subset of data on each user based on the actual data that they consume in the application. When a user makes a query for some data, it will search across the network for other users that have that data and sync it up using technologies like WebRTC. So you can think of the entire database as the union of all peers on the network. Connected. The idea is very similar to a blockchain ledger where no one individual has control of the entire network, but it's important to point out that this is not blockchain technology, which tends to be too slow and just unnecessary to build something like a super chat. However, it does rely heavily on cryptography to implement things like user authentication. When you create a new user account, a cryptographically secure key pair is generated. The username is associated with the public key so past messages can found, and the password is a proof of work seed to prove and decrypt access to the account's private keys. In addition, it's possible to implement end end encryption, which we'll do in this demo, but we'll talk more about that later in the video. Another good question is how is data persisted good, and what happens if a user just clears out their browser cache? By default, data is stored in the browser's local storage, which is limited to 5 megabytes. And if the user clears out the data in local storage, it could potentially be lost if it's not somewhere else on the network. That's probably not acceptable if you're building a production grade app. But what you can do is deploy a relay server that uses a different storage mechanism called RADIX that can store a lot more data on the disk of an actual server. And that makes the network more robust because a query can fall back to a relay if it's not available from another peer. Now, another really important concept to understand is that when you create a node in the database, it'll be available to the entire decentralized network. That means another developer can easily access your public data by simply knowing the name of the node where it's stored. Now it is possible to encrypt data and things like that, but it just requires a completely different mental model than you might be used to. Let's go ahead and jump into the source code. I'm not going to cover every single line of code in this project and instead just focus on the important parts related to the database. What we have here is a Svelte app with 2 main features, email password user authentication, and then a massive group chat room that anybody can join. The only dependency in this project is gun, which can be installed with NPM. The first thing we'll focus on is user authentication, and to do that, I'm creating a file called user dotjs. At the top of the file, we'll import gun, and below that, import 2 supporting libraries. The first one c, which stands for security the encryption and authorization, and is the module that enables user authentication. Next, we have axe, which stands for advanced exchange equation, and is basically an alternative way to connect peers together and tends to be more performant for a chat app like this, and there's a whole doc on it if you wanna learn more. From there, we'll create a variable called db to initialize the database, then we'll use it to make a reference to the currently authenticated user. I'm also chaining the option of recall all to session storage here, so the user stays logged in between browser sessions. Now to manage the user in the app, we need to know if the user is logged in, and we also want their username so we can show it in the UI. We can get the username by making a reference to the user, then calling git alias, which will be the value of whatever username they choose when they sign up. Now we're going to use this value frequently throughout the application, so I'm importing writable from Svelte store to make it reactive. A store is like an observable value that will rerender the UI whenever it's changed, and it can be shared across multiple components. So whenever the alias for the current user updates, we'll set the value of the store to that value. But we also want to listen to changes to the auth state when the user signs in or signs out. To handle that, we'll listen to the auth event on the database and basically do the same thing here where we fetch the alias and then set that as the value on the store. Now I'm going to kinda do things in reverse here because I first want to show you how the store works in Svelte. We have this header component here that will show the title of the app if you're not logged in, but if you are logged in, it'll show your username as well as your avatar. Now implementing sign out is really easy. All we have to do is import the username store and the gun user object, then we'll create a function called sign out that calls leave on the user and sets the username store to an empty string. Then down in the HTML, we have a button that when clicked will call the sign out function. But we only want to show that button if the user is signed in. And the way we can tell if a user is signed in is if their username is present. The cool thing about spelled is that we can easily do that with a store in any component by adding an if statement followed by a dollar sign and then the name of the store. The dollar sign will subscribed to the store and react to any changes that happened to it. If the username does exist, then we'll go ahead and show the username by subscribing to the store once again. We can also do the same contained to show an avatar with the user's initials by using the awesome dice bear API. I made a short video about this already, but dice bear will basically make a unique an avatar based on the username as the random seed. Then after that, we have a button that fires the sign out function when clicked. And finally, we'll add an else block here to show something else if the user is not logged in. That takes care of the header component, and you'll notice that I'm declaring it here in the app component. And now we can move on to the login component that will allow the user to sign in or sign up with their username and password. In the component, we'll import the user object, then set up local state for the username and password. In Svelte, we can implement 2 way data binding with a variable by creating a form input and then saying bind value to that variable. Full. That means anytime the user types into the form, the value of the variable will change. We have separate form inputs for username and password, and we'll share them for both the login and sign up process, which itself just consists of 2 different buttons that will either call the login function or the sign up function. To log a user in, we use the user auth method. It takes the username and password as arguments, then the third argument allows you to define a callback. In this case, the value of the store that we set up earlier will update automatically, but we can do other things here as well like error handling. Now the process to sign up a new user is very similar, but instead of calling auth, we call that create method on the user. And if the user creation is successful, then we will log that user in automatically. Now at this point, we have a working user authentication system. But one thing to keep in mind here is that we're not enforcing the uniqueness of the username, which is just a caveat you'll wanna keep combined. I should mention that it is possible to enforce username uniqueness, but it's beyond the scope of this video. Now we can move on to the chat component, which is where we will query items from the database and also give the user the ability to send a message. The component has 2 pieces of state, a string for a new message that the user will type into a form input and an array of messages, which will contain the message text along with the user who sent it and a timestamp. To query messages, as I'm going to set up the on mount life cycle hook that will run whenever that component is first initialized. Inside of it, we'll use the database to make a reference to the chat node. Coded. In this demo, since we have one giant super chat, we can just give it a name of chat. But if you have multiple chat rooms, you'd likely want to give each one a name. After that, we'll call map to basically loop over every single message in the chat and then call once to only read each message once. In this case, each message is immutable, so we don't need to listen to changes in real time, but you could do that if you wanted to using the on method. We can then define a callback that will be called on each new message that will give us access to the data and the ID of that node. Now if the data is defined, we're going to format a message that's more suitable for the UI with the properties of who, what, and when. Who is the user that sent the message, and we can figure out who sent it by taking that data of the raw message and using it to get the alias. Next, we have what, which is the actual text of the user's message. But the interesting thing here is that we're actually implementing end to end encryption. That means the value in the database is encrypted and the only way to decrypt it is to have the corresponding key. In this demo, our data is encrypted, but it's not really secure because I'm just hard coding the encryption key right here in the source code so anybody could find it. But if it was an actual secret between 2 users, you could use it to encrypt and decrypt messages. And finally, we have the when property. To get an accurate time stamp across all of our users, We're using gun state as the final source of truth with the raw data. That'll give us all the data we need for the UI. Then the final step is to take each message and add it to an array that we can then loop over in the UI with Svelte. You can loop over an array of items in Svelte with each. This will render the chat message component for each message in the array. And also notice how I'm adding parenthesis with message when, which provides Svelte with a unique key to sort all of the messages sufficiently. That gives us a way to read messages in the chat. Now we just need a form to submit them. In the UI, you'll notice that I have a form that on the submit event will call the send message function. Inside the function, the first thing we'll wanna do is use c to encrypt the actual message text, and notice how the key is the same as the one we used earlier to decrypt the messages. From there, we can associate the message to the current user using the encrypted message as the Kevalu. Then we'll create a date to serve as the index for the message so it can be sorted properly, at which point we can reference the chat collection, create a new node based on that index, ex and store the message value. Congratulations. You just built a decentralized chat app. It'll be interesting to see if this thing actually works when the video is released. Let me know how things go for you in the comments. Make sure to like and subscribe. Thanks for watching, and I will see you in the next one.
The decentralized chat app (Gant) uses a library called gun to store a small subset of data on each user based on the actual data they consume. The app is decentralized across the entire user base and the front end UI will use Svelte, a JavaScript library. Different features, including email password user authentication, and a massive group chat room, are explained. The process of creating a login component for a decentralized chat app is also discussed, including setting up state, input and send messages, and the use of a form to submit messages. The app is designed to ensure security and promotes viewers to like and subscribe to the video.