Making an Earthstar App
Let's make a Todo list app! It will use the same data format as the Earthstar Foyer App, so you can view your todos in that app also.
#
Read the tutorial codeStart by reading tutorial.js -- most of the tutorial is in the comments there.
The rest of this document is extra details.
#
Run the tutorial code#
Also try the command-line toolearthstar-cli is a little command line utility for working with Earthstar databases -- adding documents, syncing, etc.
#
Review: Earthstar in 30 secondsIt's a p2p document database. Each person has a copy of all the data on their own machine. They sync with each other.
Users are called "authors" and are identified with short names and public keys, like @suzy.bjzee56v2hd6mv5r5a...
.
"Pub servers" in the cloud help keep data online, but they have no authority over users. They are just peers like everyone else.
Users sign their documents; nobody can tamper with them as they travel through the network.
Earthstar doesn't encrypt your data but since everyone has a public and private key, you can encrypt and decrypt data yourself.
A "workspace" is like a shared folder; it's the way we divide up the world into small groups of users and their data. Workspace names look like +gardening.bja0q349ja
. Knowing a workspace name lets you access the data, so only share it with your friends.
There is not a huge global space of data and users. There are lots of small workspaces which are separate and independent.
#
In detail: how to plan your data storage in EarthstarWe'll evolve our plan as we work through these steps:
#
How data works in EarthstarImagine if your app's data was stored as a bunch of small files in a folder, and you were using Dropbox to sync it with other users. How would you divide up your data into files? We'll use a similar strategy in Earthstar.
Earthstar data is stored in Documents. Each document has a Path and some Content.
Imagine it like this:
This is almost like a filesystem except there's no entries for folders, only for files. For example there's no entry for the folder /todos/
-- it's existence is implied by the deeper items.
So this is actually a key-value store, like leveldb, and the entire path is the key.
Documents can be modified. You can "delete" them by just overwriting them with an empty string as the content.
An actual document has more fields like
author
andtimestamp
that we can ignore for now:
#
Choose a unique name for your appYour app will coexist with other apps inside the same Earthstar workspace. Maybe there are other Todo apps that work differently. Let's choose a unique name so our documents don't collide with another app.
The app name should be the first component of the path:
#
Divide your data into small piecesTwo people might edit the same document at the same time. Earthstar doesn't merge those conflicts, it just chooses the most recent one as the winner.
In our Todo app, each todo has a checkbox state and a text label. If I check a box and you edit the text label, we want both of those changes to survive. That means we need 2 documents for each Todo:
#
Plan for chaosWhen Earthstar syncs, documents can arrive in any order, and some might not arrive for a long time.
There are no transactions or batch writes.
Your app should continue working if any documents are randomly missing or haven't been updated for a while.
To make this easier to think about, let's say that the text.txt
document is the "primary" one -- we only consider a Todo to exist if the "primary" document exists.
#
Plan for efficient queryingThe most efficient way to query your documents is by path prefix -- fetching all the documents with paths starting with a certain string.
The kind of path we're using works well because we can get all the documents related to a Todo with this query:
#
Avoid sequential id numbersBut this is a distributed system and we need to make sure new Todos are created with unique IDs. There's no central place to give out unique sequential integers.
Instead, choose one strategy:
- Use randomly generated UUIDs
- Use timestamps combined with some randomness to avoid rare accidental collisions.
Let's choose #2, because the paths will be conveniently sorted by creation time.
Microseconds, not milliseconds, are used for timestamps throughout Earthstar, so let's follow that convention here and multiply Date.now()
by 1000 to get microseconds.
Now our paths are like:
If you need to put strings into your paths, such as Wiki page titles, check the specification: write permissions for details on character limits, how to encode unicode characters, etc.
#
Decide who can edit documentsBy default, anyone can edit any document.
If a document path contains "~"
+ the name of an author, only that author can edit it. For example:
In our Todo example we'll leave all documents editable by anyone.
#
Storing binary dataDocument content is stored as UTF-8 strings.
Use a "file extension" on the end of your path to suggest how it should be interpreted: .txt
? .json
? .html
?
Earthstar doesn't directly support storing raw binary data. You can base64-encode your data, save it to Earthstar, and then base64-decode it when you load it back.
There's no way to tell if a document contains base64 data or not, so use the file extension to guess. If it ends in .jpg
, it's probably base64-encoded binary.
#
Size limitsBrowser localStorage is limited to 5 MB total. If you're using that kind of storage, all of your documents across all your workspaces need to fit within 5 MB.
Browser IndexedDB can hold more data but it's not yet supported by Earthstar.
In node, SQLite can hold very large amounts of data.
Also, each document's content should be < 6 MB. (And note that a binary file of 4.5 MB will grow to 6MB when base64-encoded.) Larger documents should be broken into smaller pieces.
#
Saving spaceDeleted documents still take up about 300 bytes each. If your app will generate and delete a lot of documents it can add up to a lot of clutter.
Example: a chat app where we don't need to keep very old history.
Here's 2 ways avoid clutter:
#
1. Re-use old pathsWhen writing a new message, look for an old one that's been deleted (from the same author), re-use that path and overwrite the old message.
#
2. Use ephemeral messagesEarthstar messages can have expiration dates. They are deleted after that timestamp passes. You can keep extending the expiration date to keep the document alive.
Read more in the specification: ephemeral documents.
#
Our final plan for data storage#
Put all that Todo code into a LayerA set of code for handling a data format, such as Todos, is called a "Layer" in Earthstar. Typically this is a single class that's treated like a React store, but there are no specific rules.
Here's the full Todo Layer from the Foyer app:
https://github.com/earthstar-project/earthstar-foyer/blob/master/src/layers/todoLayer.ts
#
Making apps#
Kinds of appsHere's 4 ways to make apps, from easy to hard:
- A node command-line app, using the main
earthstar
package directly - A React app that uses the hooks from react-earthstar
- A React app that builds on top of earthstar-foyer
- A frontend-based web app of any kind, using the main
earthstar
package directly - Native mobile or desktop apps
This tutorial uses #1, the node command-line app, because it's the simplest.
react-earthstar
and earthstar-foyer
have helpful UIs already built for adding and removing workspaces, logging in as a user, setting pubs, etc.
#
Web appsThe usual structure of an Earthstar web app is:
- The backend is a simple static HTTP server. It does no computation or storage of data.
- The frontend is a single-page application
- The frontend stores Earthstar data in localStorage or in memory
- The frontend syncs the data with pub server(s) over HTTP
- The frontend provides a UI for adding workspaces, changing pubs, making new user identities, etc.
- Sometimes the frontend contains multiple "apps" and you can switch between them from the same UI
- The user's keys never leave the browser
- Ideally the page is a Progressive Web App that can be used offline, then sync'd later when the user comes back online.
You could also store the data in a more traditional backend and query it from the frontend. This would be like a hybrid pub and app server. We don't have an example of this style yet. Make sure to keep the user's keys in the browser, have them sign documents there, and then upload the signed documents to the server. The server should never have the user's keys.
#
ReactUse the react-earthstar library which provides:
- A UI called the "EarthBar" which lets users add pub servers and workspaces, create identities, etc.
- Hooks for using Earthstar more easily from React
#
VueHere's a very minimal demo of a Todo list built with Vue.
https://codesandbox.io/s/earthstar-vue-todo-list-demo-2-udv6o?file=/src/App.vue