npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-earthstar

v4.0.0

Published

A React toolkit for making collaborative, decentralised, offline-first tools you can truly call your own.

Downloads

109

Readme

react-earthstar

What is this?

A library of React hooks and components for usage with Earthstar, storage for private, distributed, offline-first application.

This library is just a few small hooks for subscribing to some events in Earthstar, with the same API for querying and writing data.

It's recommended that you check out Earthstar's README before reading on if you haven't already.

Getting started

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

npm install earthstar react-earthstar

Here's a basic applet which creates a IndexedDB replica for a +gardening share, and renders a list of notes using useReplica.

import * as Earthstar from "earthstar";
import { useReplica } from 'react-earthstar';

// You get the share address and secret from someone else,
// Or using Earthstar.Crypto.generateShareKeypair()

const MY_SHARE_ADDRESS =
  "+gardening.bhyux4opeug2ieqcy36exrf4qymc56adwll4zeazm42oamxtr7heq";

const MY_SHARE_SECRET = "buaqth6jr5wkksnhdlpfi64cqcnjzfx3r6cssnfqdvitjmfygsk3q";

const replica = new Earthstar.Replica({
  driver: new ReplicaDriverWeb(MY_SHARE_ADDRESS),
  shareSecret: MY_SHARE_SECRET,
});

function App() {
  const cache = useReplica(replica);

  // This will update whenever a document with a path starting with '/notes' updates.
  const notes = cache.queryDocs({
    filter: {
      pathStartsWith: "/notes",
      author: 
    },
  });

  return (
    <div>
      <h1>My notes</h1>
      { notes.map((noteDoc) => 
        <li>noteDoc.text</li>
      )}
      
    </div>
  );
}

Hooks

useReplica

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

const replica = useReplica(myReplica);

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

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

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!

usePeerReplicas

Returns an updating array of Replica for a given Peer.

function ReplicaList() {
  const replicas = usePeerReplicas(myPeer);

  return (
    <div>
      <h1>My replicas</h1>
      <ul>
        {replicas.map((replica) => <li>{replica.share}</li>)}
      </ul>
    </div>
  );
}

useAuthorSettings

Returns a getter and setter for the SharedSettings' current author setting. Uses the SharedSettingsContext.

function CurrentAuthorAddress() {
  const [author, setAuthor] = useAuthorSettings();

  return <div>{author.address}</div>;
}

useShareSettings

Returns the shares + a callback to add a share + a callback to remove a share from SharedSettings' shares setting. Uses the SharedSettingsContext.

function KnownShares() {
  const [shares, addShare, removeShare] = useAuthorSettings();

  return (
    <div>
      <h1>My shares</h1>
      <ul>
        {shares.map((share) => <li>{share}</li>)}
      </ul>
    </div>
  );
}

useShareSecretSettings

Returns the secrets + a callback to add a secret + a callback to remove a secret from SharedSettings' share secrets setting. Uses the SharedSettingsContext.

function KnownSecrets() {
  const [secrets, addSecret, removeSecret] = useAuthorSettings();

  return (
    <div>
      <h1>Known secrets...p</h1>
      <ul>
        {Object.keys(secrets).map((share) => (
          <li>{share} {secrets["share"] ? "✓" : "???"}</li>
        ))}
      </ul>
    </div>
  );
}

useServerSettings

Returns the server + a callback to add a server + a callback to remove a server from SharedSettings' servers setting. Uses the SharedSettingsContext.

function KnownShares() {
  const [servers, addServer, removeServer] = useAuthorSettings();

  return (
    <div>
      <h1>My servers</h1>
      <ul>
        {servers.map((share) => <li>{server}</li>)}
      </ul>
    </div>
  );
}

Components

<SharedSettingsContext.Provider>

If you're going to use any of the settings hooks, you should provide a single instance of SharedSettings as a context for them:

const settings = new Earthstar.SharedSettings();

function App() {
  return (
    <SharedSettings.Provider value={settings}>
      // Components which use useAuthorSettings, useShareSettings etc.
      <TheRestOfTheApp />
    </SharedSettings.Provider>
  );
}

<ShareLabel>

Renders the human readable portion of a share address, and omits the public key: e.g. '+gardening.bhyux4opeug2ieqcy36exrf4qymc56adwll4zeazm42oamxtr7heq' becomes '+gardening'. Also renders an identicon next to the address to make it harder for shares to be mistaken for one another. Good for making sure you don't disclose share addresses to people looking over your users' shoulders.

<ShareLabel address="+potatoes.b34ou9e8">

Also takes an iconSize prop (side size in px), and a viewingAuthorSecret prop. The latter prop is used as a salt for generating the identicon, making it so that each user has their own identicon for each share, making them harder for an attacker to imitate. If available, pass the current user's keypair secret to this prop.

<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...">

Also takes an iconSize prop (side size in px), and a viewingAuthorSecret prop. The latter prop is used as a salt for generating the identicon, making it so that each user has their own identicon for each share, making them harder for an attacker to imitate. If available, pass the current user's keypair secret to this prop.