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

@localfirst/auth-syncserver

v6.0.0

Published

Sync server for automerge-repo using localfirst/auth

Downloads

132

Readme

Authenticated sync server for Automerge Repo

This is a sync server that uses @localfirst/auth-provider-automerge-repo to authenticate connections with peers.

This sync server works much the same way as the automerge-repo sync server, in that is fundamentally just another peer running automerge-repo.

The sync server needs to be added to every team we want to sync with, and it needs to have a full copy of the team graph. Instead of going through the invitation process, the sync server exposes an REST API to obtain its public keys and to provide it with a team's graph.

Instantiating a sync server

The server's hostname (without the port) is used as its unique identifier. Here we use localhost; in production this would look like sync.my-organization.com.

const host = 'localhost'
const port = 3030
const url = `${host}:${port}`
const storageDir = 'localfirst-auth-syncserver-storage'
const syncServer = new LocalFirstAuthSyncServer(host)
await syncServer.listen({ port, storageDir })

Connecting to the sync server

A user creates an auth provider with a reference to the server's hostname, and instantiates a repo as described here.

// Instantiate a user's auth provider.
const user = Auth.createUser('alice')
const device = Auth.createDevice(user.userId, 'ALICE-MACBOOK-2023')
const storage = new SomeStorageAdapter()
const authProvider = new AuthProvider({
  user,
  device,
  storage,
  server: 'localhost:3030',
})

// Instantiate a repo.
const adapter = new SomeNetworkAdapter()
const network = [authProvider.wrap(adapter)]
const repo = new Repo({ network, storage })

// Create a team.
const team = await authProvider.createTeam(`Alice's team`)

A new team needs to be registered with the sync server using the API described below. The AuthProvider.createTeam() method automatically does this for you. If you create the team outside the auth provider, you can use the AuthProvider.registerTeam() method.

const team = Auth.createTeam('team A', aliceContext)
authProvider.addTeam(team)
await authProvider.registerTeam(team)

On the team, the server is treated more or less like a device with no user. The server can't make any changes to the team's membership etc.; it can only relay changes made by team members. But the server can verify invitations and admit new members and devices to the team.

Any number of servers can be registered with a team, and any number of teams can be registered with a server.

The repo will now connect with the server, the auth provider will authenticate with it, and the repo should get a peer event.

repo.networkSubsystem.on('peer', ({ peerId }) => {
  console.log(peerId) // `localhost` or `sync.my-organization.com`
})

From this point on, our communication with the sync server takes place over an encrypted channel. All subsequent changes to the team (inviting or removing members, etc.) will be automatically synced with the server.

Server API

The sync server exposes two endpoints that are used when adding a new team.

(You wouldn't normally access this API yourself; the AuthProvider.createTeam() and AuthProvider.registerTeam() methods call these endpoints for you.)

GET /keys

Obtains the server's public keys. We need these to add the server to the team.

const response = await fetch(`http://${url}/keys`)
const keys = await response.json()

// Use these keys to add the server to the team
team.addServer({ host, keys })

POST /teams

Registers the team with the sync server by giving it a complete copy of the team's data.

await fetch(`http://${url}/teams`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    serializedGraph: team.save(), // the serialized team is encrypted
    teamKeyring: team.teamKeyring(), // these are needed to decrypt the serialized team
  }),
})