Navigate

Earthstar

Create a chat app

In this tutorial you will build a browser chat application using Earthstar.

Table of contents

Overview

A basic knowledge of HTML, JavaScript, and using the terminal will be helpful in completing this tutorial.

Other tools you will need:

If you don't have a static file server yet, you can follow the instructions below.

Instructions for installing a static file server
  • Install Deno.
  • In your terminal, run deno install --allow-net --allow-read https://deno.land/std@0.167.0/http/file_server.ts

Proceed once you have all of the above.

Setting up

Writing the HTML

Open the index.html file you created in your text editor, and enter the following text:

<!DOCTYPE html>
<html lang="en">
	<head>
			<meta charset="utf-8">
			<title>My Chat App</title>	
	</head>
	<body>
		<ul id="messages"></ul>
		<form id="message-form">
			<input type="text" name="message-input">
			<button>Send</button>
		</form>
		<script src="./chat.js" type="module" async></script>
	</body>
</html>

Starting the JavaScript

Open the chat.js file created earlier in your text editor, and enter the following text:

import * as Earthstar from "https://cdn.earthstar-project.org/js/earthstar.web.v10.2.2.js";

alert("Everything is set up!");

Making sure it works

Now we will verify that we have set up everything correctly.

Writing chat messages to a Replica

We will now write some JavaScript to write the contents of the text input to an Earthstar Replica whenever the 'Send' button is pressed.

Listening for events

Firstly we will write some Javascript which listens for events on form submission, and logs a message to the console.

Modify chat.js with the following contents:

import * as Earthstar from "https://cdn.earthstar-project.org/js/earthstar.web.v10.2.2.js";

const form = document.getElementById("message-form");
const input = document.querySelector("input");
form.addEventListener("submit", (event) => {
// This stops the page from reloading.
event.preventDefault();
console.log(input.value);
});

Reload your chat app, type something in the input, and click the send button. You will see the message you typed in the console.

Writing to a replica

Now we will take messages typed into the form and write them to an Earthstar Replica.

Modify chat.js with the following contents:

import * as Earthstar from "https://cdn.earthstar-project.org/js/earthstar.web.v10.2.2.js";

const shareKeypair = await Earthstar.Crypto.generateShareKeypair("chatting");
const authorKeypair = await Earthstar.Crypto.generateAuthorKeypair("test");
if (Earthstar.notErr(shareKeypair) && Earthstar.notErr(authorKeypair)) {
console.group("Share keypair");
console.log(shareKeypair);
console.groupEnd();
console.group("Author keypair");
console.log(authorKeypair);
console.groupEnd();
} else if (Earthstar.isErr(shareKeypair)) {
console.error(shareKeypair);
} else if (Earthstar.isErr(authorKeypair)) {
console.error(authorKeypair);
}
const form = document.getElementById("message-form"); const input = document.querySelector("input"); form.addEventListener("submit", (event) => { // This stops the page from reloading. event.preventDefault(); console.log(input.value); });

Reload the page and copy the values from the browser. We want to keep reusing them even after the page has refreshed.

With these values we can instantiate an Earthstar Replica and write data to it. Modify chat.js again:

import * as Earthstar from "https://cdn.earthstar-project.org/js/earthstar.web.v10.2.2.js";

// Use the values for shareKeypair which were logged to your console.
const shareKeypair = {
shareAddress:
"+chatting.bffblffbnzrjeqmh3s3vnuvztfibnzuex3e5h4nthsq7dum4mnlra",
secret: "b4wghljrl4f4e7tedrggn72gyqvqyeqvlg6u5usi6nijwyrukbena",
};
// Use the values for authorKeypair which were logged to your console.
const authorKeypair = {
address: "@test.bozdi5jngr2yztz5ue6qnvqpeq5flm6gpuqajikngp3wjolabgmaa",
secret: "byrp2eqpjzdmaxllybrbrtblb54bmuwbl26n6hrfendg72zcxsduq",
};
const replica = new Earthstar.Replica({
driver: new Earthstar.ReplicaDriverWeb(shareKeypair.shareAddress),
shareSecret: shareKeypair.secret,
});
const form = document.getElementById("message-form"); const input = document.querySelector("input");
form.addEventListener("submit", async (event) => {
// This stops the page from reloading. event.preventDefault();
// Write the contents of the message to the replica.
const result = await replica.set(authorKeypair, {
text: input.value,
path: `/chat/~${authorKeypair.address}/${Date.now()}`,
});
if (Earthstar.isErr(result)) {
console.error(result);
}
input.value = "";
});

Reading messages from the replica

We will now read data back out of the replica so that we can display the messages we've entered.

Add the following to chat.js:

import * as Earthstar from "https://cdn.earthstar-project.org/js/earthstar.web.v10.2.2.js";

// Use the values for shareKeypair which were logged to your console.
const shareKeypair = {
	shareAddress:
		"+chatting.bffblffbnzrjeqmh3s3vnuvztfibnzuex3e5h4nthsq7dum4mnlra",
	secret: "b4wghljrl4f4e7tedrggn72gyqvqyeqvlg6u5usi6nijwyrukbena",
};

// Use the values for authorKeypair which were logged to your console.
const authorKeypair = {
	address: "@test.bozdi5jngr2yztz5ue6qnvqpeq5flm6gpuqajikngp3wjolabgmaa",
	secret: "byrp2eqpjzdmaxllybrbrtblb54bmuwbl26n6hrfendg72zcxsduq",
};

const replica = new Earthstar.Replica({
	driver: new Earthstar.ReplicaDriverWeb(shareKeypair.shareAddress),
	shareSecret: shareKeypair.secret,
});

const form = document.getElementById("message-form");
const input = document.querySelector("input");

form.addEventListener("submit", async (event) => {
	// This stops the page from reloading.
	event.preventDefault();

	// Write the contents of the message to the replica.
	const result = await replica.set(authorKeypair, {
		text: input.value,
		path: `/chat/~${authorKeypair.address}/${Date.now()}`,
	});

	if (Earthstar.isErr(result)) {
		console.error(result);
	}

	input.value = "";
});

// Read messages from chat.
const messages = document.getElementById("messages");
const cache = new Earthstar.ReplicaCache(replica);
function renderMessages() {
messages.innerHTML = "";
const chatDocs = cache.queryDocs({
filter: { pathStartsWith: "/chat" },
});
for (const doc of chatDocs) {
const message = document.createElement("li");
message.textContent = doc.text;
messages.append(message);
}
}
cache.onCacheUpdated(() => {
renderMessages();
});
renderMessages();

Now when you enter messages they will be rendered above the message input. The messages will also persist between browser sessions.

Going online

Our chat application works, but it only allows us to talk to ourselves. We can enable online communication by adding three lines to the end of chat.js:

const peer = new Earthstar.Peer();
peer.addReplica(replica);
peer.sync("https://my.server", true);

This won't work because there is no Earthstar server at https://my.server. Fortunately we have a tutorial for running an Earthstar server.

Make sure your browser allows Earthstar to save data

In your browser settings you may need to add an exception for your local Earthstar server, so that your application can access it and store data on it.

Firefox: go to "Settings -> Privacy & Security -> Cookies and Site Data -> Manage Exceptions..." and add the local Earthstar server address.

Summary

We've created a simple chat app which works in the browser, and uses Earthstar to persist and sync data.

Further exercises