Giter Club home page Giter Club logo

rushlight's Introduction

🕯️ Rushlight

Make collaborative code editors that run on your own infrastructure: just Redis and a database.

Supports multiple real-time documents, with live cursors. Based on CodeMirror 6 and operational transformation, so all changes are resolved by server code. It's designed to be as easy to integrate as possible (read: boring). The backend is stateless, and you can bring your own transport; even a single HTTP handler is enough.

Unlike most toy examples, Rushlight supports persistence in any durable database you choose. Real-time updates are replicated in-memory by Redis, with automatic log compaction.

An experiment by Eric Zhang, author of Rustpad.

Motivation

Let's say you're writing a web application. You already have a database, and you want to add real-time collaborative editing. However, most libraries are unsuitable because they:

  • Require proprietary gadgets
  • Are not flexible enough, e.g., to customize appearance
  • Make you subscribe to a cloud service where you can't control the data
  • Use decentralized algorithms like CRDTs that are hard to reason about
  • Make it difficult to authenticate users or apply rate limits
  • Rely on a single stateful server, which breaks with replication / horizontal autoscaling
  • Need WebSockets or other protocols that aren't supported by some providers
  • Are just generally too opinionated

This library tries to take a more practical approach.

Usage

Install the client and server packages.

# client
npm install rushlight

# server
npm install rushlight-server

On the frontend, create a CollabClient object and attach it to your CodeMirror instance via extensions.

import { EditorView } from "codemirror";
import { CollabClient } from "rushlight";

const rushlight = await CollabClient.of({
  async connection(message) {
    // You can use any method to send messages to the server. This example
    // executes a simple POST request.
    const resp = await fetch(`/doc/${id}`, {
      method: "POST",
      body: JSON.stringify(message),
      headers: { "Content-Type": "application/json" },
    });
    if (resp.status !== 200) {
      throw new Error(`Request failed with status ${resp.status}`);
    }
    return await resp.json();
  },
});

const view = new EditorView({
  extensions: [
    // ...
    rushlight,
    rushlight.presence, // Optional, if you want to show remote cursors.
  ],
  // ...
});

Then, on the server, we need to write a corresponding handler for the POST request. Create a CollabServer object, which requires a Redis connection string and a persistent database for document storage.

The example below is with express, but you can use any framework.

import express from "express";
import { Checkpoint, CollabServer } from "rushlight-server";

const rushlight = await CollabServer.of({
  redisUrl: process.env.REDIS_URL || "redis://localhost:6473",
  async loadCheckpoint(id: string): Promise<Checkpoint> {
    // ... Load the document from your database.
    return { version, doc };
  },
  async saveCheckpoint(id: string, { version, doc }: Checkpoint) {
    // ... Save the new version of the document to your database.
  },
});

rushlight.compactionTask(); // Run this in the background.

const app = express();

app.post("/doc/:id", express.json(), async (req, res) => {
  const id = req.params.id;
  try {
    res.json(await rushlight.handle(id, req.body));
  } catch (e: any) {
    console.log("Failed to handle user message:", e.toString());
    res.status(400).send(e.toString());
  }
});

app.listen(8080);

That's it! See the ClientOptions and ServerOptions types for more configuration options.

To view a full demo application, a collaborative Markdown editor using Postgres to store documents, see the app/ folder in this repository.

Development

These are instructions for developing the library itself and running the demo application. Clone the repository, which is an NPM workspace. To build the TypeScript files, just run:

npm install
npm run lint
npm run build

The demo application requires Node.js version 18 or higher and Docker Compose.

docker compose up
npm run dev

Visit http://localhost:6480 in your browser.

Deployment

For the demo application:

npm ci
npm run build

export REDIS_URL=redis://...
export DATABASE_URL=postgres://...
npm start -w=app

Listens on port 6471 by default, or the PORT environment variable if set.

Why the name?

It comes from this quote, and the fact that rushlights are a type of makeshift candle; you make do with what you have.

“Early Sunday morning, Natasha and I lit a candle, looked in the mirror … They say you can see your future in the long row of candles, stretching back and back and back, into the depths of the mirror.”

”I see nothing but the candle in the mirror. No visions of the future. So lost and alone.”

―Dave Malloy, Natasha, Pierre & The Great Comet of 1812

rushlight's People

Contributors

ekzhang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.