react-earthstar icon indicating copy to clipboard operation
react-earthstar copied to clipboard

A UI toolkit for making collaborative, offline-first applets for small groups.

react-earthstar

What is this?

A library for using React with Earthstar, a library for building syncing, decentralised online tools.

Featuring:

  • Don't-have-to-think-about-it realtime collaborative data
  • No-servers-involved authentication
  • No-distinction-between-the-two offline and online support

Earthstar

Earthstar models collaborative online tools using the concepts of Shares, Replicas, Documents, and Identities. To learn more about what that all means, check out our how it works page.

Getting started

First, install react-earthstar and earthstar as dependencies to your project:

yarn add earthstar react-earthstar
npm install earthstar react-earthstar

Start by placing the Peer component somewhere near the root of your app:

import { Peer } from 'react-earthstar';
import { FormatValidatorEs4 } from 'earthstar';
import { ReplicaDriverIndexedDB } from 'earthstar/browser';

function App() {
  return (
    <Peer
      onCreateShare={(address) => {
        // Here we're teaching Peer how to persist data for shares.
        const driver = new ReplicaDriverIndexedDB(address);
        return new Replica(address, FormatValidatorEs4, driver);
      }}
    >
      <h1>{'The beginnings of my app!'}</h1>
      <SomeCoolFeature />
    </Peer>
  );
}

<Peer> coordinates the state of your Earthstar app: things like share replicas, the current identity in use, or

With you app wrapped in <Peer>, you now use all of react-earthstar's hooks!

Hooks

useReplica

This is the workhorse of the library, used for querying documents from replicas.

const replica = useReplica();

const txtDocs = replica.queryDocs({ filter: { pathEndsWith: '.txt' } });

This hook returns an instance of Earthstar's ReplicaCache class, with the exact same API.

When you query docs the replica keeps track of what was queried for, and only updates React when the results of those queries are updated. This results in a best-of-both-worlds API where we can have the same API as the vanilla Earthstar library, and components which only re-render when they need to. Nice!

useCurrentShare

A hook to get and set the active share.

const [currentShare, setCurrentShare] = useCurrentShare();

return <div>{`You are currently browsing the docs of ${currentShare}!`}</div>;

useIdentity

A convenience hook for getting and setting an Earthstar identity keypair.

const replica = useReplica();
const [identity, setIdentity] = useIdentity();

const set = () => {
  replica.set(identity, { content: 'Hi!', 'path': '/greetings.txt', format: 'es.4' });
};

usePeer

const peer = usePeer();

const allShares = peer.shares();

Returns an instance of Earthstar's Peer class. Useful for getting the list of all shares, adding or removing replicas, etc.

useIsLive

Get and set whether synchronisation with remote peers is active or not.

const [isLive, setIsLive] = useIsLive();

return <label><input checked={isLive} onChange={(e) => { setIsLive(e.target.checked )}} /> Syncing?</label>

useInvitation

Earthstar has a specification for URL-style invitations. This hook parses such URLs and adds any shares or replica servers derived from them.

const redeem = useInvitation("earthstar:///?workspace=+gardening.abc&pub=http://pub1.org& v=1");

return <button onClick={() => redeem()}>Join!</button>

useMakeInvitation

You can also create invitations to be used by others:

const invitation = useInvitation(['wss://my.server'], '+gardening.a123');

useAddShare

Adds a share using the onCreateShare passed to <Peer>:

consnt add = useAddShare();

add('+archery.k456');

useLocalStorageEarthstarSettings

<Peer>`` holds state which you probably want to persist between sessions. You can use this hook to access this state (written by the <LocalStorageSettingsWriter/>` component).

const settings = useLocalStorageEarthstarSettings('my-app');

return <Peer {...settings} {...etc} />;

Components

There are a few components needed to make things work, as well as a few convenience ones.

<Peer>

You'll need this somewhere in your app to use react-earthstar.

<Peer
  onCreateShare={(address) => {
    // Here we're teaching Peer how to persist data for shares.
    const driver = new ReplicaDriverIndexedDB(address);
    return new Replica(address, FormatValidatorEs4, driver);
  }}
>
  <MyGreatAppUsingEarthstar/>
</Peer>

<Peer> also has a bunch of props for setting its initial state, e.g. initShares, initReplicaServers, initIdentity, etc. These can be hydrated and persisted to local storage using useEarthstarLocalStorageSettings and <LocalStorageSettingsWriter>.

This component will also automatically start synchronising with any replica servers it knows of.

<LocalStorageSettingsWriter>

Stick this somewhere within <Peer> and it'll automatically persist many settings to local storage, namespaced by a key of your choice.

<Peer>
  <LocalStorageSettingsWriter storageKey="my-app"/>
</Peer>

<ShareLabel>

Renders the human readable portion of a share address, and omits the obscuring portion: e.g. '+gardening.b34ue9ug' becomes '+gardening'. Good for making sure you don't disclose share addresses to people looking over your users' shoulders.

<ShareLabel address="+potatoes.b34ou9e8">

<IdentityLabel>

Renders the shortname portion of an identity's address, omitting the public key, e.g. @cinn.euu8euheuigoe... just becomes @cinn.

<IdentityLabel address="@devy.a234gue9Juhxo9eu...">

<CurrentIdentityLabel>

Does the same as <IdentityLabel> but doesn't take an address prop and just uses the current identity provided by <Peer>.

What about Earthbar?

Earthbar was an out-of-the-box UI for managing many Earthstar related tasks. It attempted to pack a lot of functionality and flexibility into this repo, and it was huge. It's been removed from react-earthstar for maintainability reasons, and we will be bringing back something similar in a separate package somewhere down the road.