• Stars
    star
    129
  • Rank 279,262 (Top 6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 1 year ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

tRPC integrations for CRDTs: CRDT-native RPC calls

trpc-crdt

tRPC integrations for CRDTs: CRDT-native RPC calls

For when you're building with CRDTs but you want to run code on a server.

Install

NPM packages are available for the following CRDT systems:

In progress

Please PR additional integrations — the goal is to support all CRDT implementations.

How to use

Run server functions from the client that write to replicated data structures.

// Run a job
await trpc.aiSummarizationJob.mutate({ id })
console.log(jobResults.get(id))

// Schedule an event
const eventId = await trpc.scheduleRoom.mutate({
  date: `2023-11-04`,
  startTime: 12,
  endTime: 13
})
console.log(events.get(eventId))

A simple Yjs implementation (see the examples directory for full examples for each integration).

Browser

import * as Y from "yjs"
import { createTRPCProxyClient } from "@trpc/client"
import { link } from "trpc-yjs/link"

// Doc needs replicated via a server e.g. with y-websocket.
const doc = new Y.Doc()
const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    link({
      doc,
    }),
  ],
})

// Tell server to create a new user.
await trpc.userCreate.mutate({id: `1`, name: `Kyle Mathews`})

// The new user, written by the server, is now available at
doc.getMap(`users`).get(`1`)

Server

import { adapter } from "trpc-yjs/adapter"
import { initTRPC, TRPCError } from "@trpc/server"
import { z } from "zod"

const t = initTRPC.create()
const router = t.router
const publicProcedure = t.procedure

const appRouter = router({
  userCreate: publicProcedure
    .input(z.object({ name: z.string(), id: z.string() }))
    .mutation(async (opts) => {
      const {
        input,
        ctx: { users },
      } = opts
      const user = { ..input }

      // Set new user on the Y.Map users.
      users.set(user.id, user)

      return `ok`
    })
})

// Get replicated Yjs doc to listen for new tRPC calls.
const doc = getYDoc(`doc`)

// Setup trpc-yjs adapter.
adapter({ appRouter, context: { doc, users: doc.getMap(`users`) } })

Why Build with CRDTs?

CRDTs enable local-first style development — local-first is a software architecture which shifts reads/writes to an embedded database in each client. Local writes are replicated between clients by a Sync Engine.

The benefits are multiple:

  • Simplified state management for developers
  • Built-in support for real-time sync, offline usage, and multiplayer collaborative features
  • Faster (60 FPS) CRUD
  • More robust applications for end-users

Read my longer write-up on why I think local-first is the future of app development: https://bricolage.io/some-notes-on-local-first-development/

Why trpc-crdt?

But not everything is cute puppies and warm bread and butter in CRDT-land.

CRDTs (and local writes) are amazing until... you need a server (it happens).

Common reasons for needing a server when building with CRDTs:

Only a server can run the code:

  • the code requires specialized hardware not available in the client
  • the code is written in a non-javascript language (it happens)
  • the code needs to talk to 3rd party API with restricted access
  • the code needs more resources to run than are available on the client (common with mobile)
  • the code needs data that's not available on the client (data doesn't fit or too expensive to load)

An optimistic client mutation isn't safe:

CRDTs make optimistic client mutations far safer than normal but an authoritative server is still often needed:

  • mutations that need complex or secure validation (e.g. money transfer)
  • mutations that include writes to external systems that must be completed in the same transaction e.g. writes to a 3rd party API
  • mutations to complex data that's not easily expressed in CRDTs
  • mutations against limited resources e.g. reserving a ticket to a show

For each of these, the good ol' request/response RPC pattern is a lot easier and safer than optimistic client writes.

Why do server authoritative mutations over a CRDT?

You might be wandering: why not just write normal tRPC (or REST/GraphQL) API calls?

This is possible but there are some potent advantages to keeping everything in CRDT-land:

  • No need for client-side state invalidation/refetching after server writes. Writes by the server during a tRPC mutations are pushed to all clients by the sync engine. Data across your component tree will be updated simultaneously along with your UI — a major pain point for normal API mutations!
  • RPC calls get all the benefits of of CRDTs:
    • server calls over CRDTs are resilient to network glitches with guaranteed exactly-once delivery. No need to add retry logic to your calls.
    • RPC calls are now replicated (if you choose) in real-time to other users of the application
  • Simplify your architecture. If you're using CRDTs extensively in your applications, tRPC over CRDT helps keep your architecture simple and consistent.
  • A free audit log! Which may or may not be useful but it can be handy or even essential to see a log of all mutations.
  • Easy real-time updates for long-running requests e.g. the server can simply update a progress percentage or what step the request is on. If some requests are of interest to a wider audience e.g. in group collaboration, running requests over CRDT means you get free real-time job notifications.

Get involved!

This library and local-first in general is very early so there's lots of ideas to explore and code to write.

More Repositories

1

typography.js

A powerful toolkit for building websites with beautiful design
JavaScript
3,825
star
2

typefaces

NPM packages for Open Source typefaces
CSS
2,603
star
3

react-headroom

Hide your header until you need it
JavaScript
1,828
star
4

react-spinkit

A collection of loading indicators animated with CSS for React
CSS
1,491
star
5

docker-nginx

Nginx Docker image for easy hosting of static sites
Nginx
337
star
6

react-gravatar

React component for rendering a gravatar profile image
JavaScript
279
star
7

coffee-react-quickstart

Quickstart for building React single page apps using Coffeescript, Gulp, Webpack, and React-Router
CoffeeScript
254
star
8

superagent-bluebird-promise

Add promise support to superagent using Bluebird
CoffeeScript
183
star
9

element-resize-event

Library to make it easy to listen for element resize events
JavaScript
175
star
10

react-sparkline

React component for rendering simple sparklines
CoffeeScript
147
star
11

blog

my blog!
JavaScript
124
star
12

react-markdown-textarea

Component for React to create textareas for entering Markdown with built-in preview inspired by Github's design
CoffeeScript
120
star
13

react-micro-bar-chart

React component for micro bar-charts rendered with D3
CoffeeScript
112
star
14

react-retina-image

React component for serving high-resolution images to devices with retina displays
CoffeeScript
109
star
15

facebook-export

Tools to help administer your Facebook groups
CoffeeScript
100
star
16

react-responsive-grid

Power tools for building responsive layouts with React
CoffeeScript
91
star
17

react-component-gallery

React component for creating an evenly spaced gallery of children components
CoffeeScript
88
star
18

react-icon-factory

Simply add icon SVGs and the react icon factory will manufacture a custom icon component!
JavaScript
66
star
19

cjsx-loader

coffee-react-transform loader module for webpack
Makefile
53
star
20

react-smart-time-ago

Show relative "time ago" dates for anything in last two weeks and absolute dates from then on back
JavaScript
33
star
21

react-component-width-mixin

React mixin which sets width as state variable and updates as component changes shape
JavaScript
29
star
22

react-simple-table

For when you just want a table
CoffeeScript
23
star
23

isRetina

Simple function which determines if your code is running on a high DPR device or not
JavaScript
23
star
24

gatsby-starter-theme-ui

Fork of the Gatsby default starter but with theme-ui
JavaScript
19
star
25

react-autoupdate-time

Renders a <time> element that autoupdates at a configurable interval
CoffeeScript
19
star
26

og_mailinglist

Drupal Module that converts individual Organic Groups into mailing lists.
PHP
18
star
27

compass-vertical-rhythm

A port-in-progress of the Compass vertical rhythm library
CoffeeScript
18
star
28

check-gatsby-caching

Checks if your Gatsby site's cache-control headers are correct and optimized
JavaScript
18
star
29

Fuzzymatcher.js

Fuzzymatching library optimized for powering auto-complete widgets
JavaScript
18
star
30

docker-nginx-reverse-proxy-ssl

Docker image for creating simple reverse proxy with ssl termination
Shell
17
star
31

linux-config

my personal config files
Vim Script
16
star
32

color-pairs-picker

Given a color, it picks pleasing and well contrasted background and foreground colors
CoffeeScript
14
star
33

react-page-width

React mixin so a component can always know the current page width
CoffeeScript
13
star
34

Eduglu-Chatroom

Awesome Drupal-groups aware Chatroom built on Node.js
JavaScript
12
star
35

toml-loader

TOML loader module for webpack
JavaScript
11
star
36

makersgtd

Yet Another GTD Single Page App
CoffeeScript
10
star
37

engagement

Track when a user is engaging with a page
CoffeeScript
9
star
38

docker-nodejs-base

Base for building node.js web apps. Node.js, Ruby, Bundler, etc.
9
star
39

hapi-rethinkdb-thinky

Hapi plugin that automatically loads your Thinky models for RethinkDB
CoffeeScript
9
star
40

modularscale

Calculate a modular scale
CoffeeScript
9
star
41

image-exists

Check if an image exists
JavaScript
8
star
42

aiocalendar

All-in-one calendar feature built in Drupal
JavaScript
8
star
43

gray-percentage

Convenience function to get a gray value by percentage e.g. gray(60) -> "hsl(0,0%,60%)"
CoffeeScript
8
star
44

react-component-starter

Quickstart for creating a Coffeescript React component with examples
JavaScript
8
star
45

phpmailer

a temporary (hopefully) fork of PHPMailer to work on some changes we need for OG Mailinglist. The issue for our changes can be found at http://sourceforge.net/tracker/?func=detail&aid=3080711&group_id=26031&atid=385707
PHP
7
star
46

react-ghost-button

A simple react-ghost-button
CoffeeScript
7
star
47

gatsby-starter-building-blog

Gatsby v2 starter with colors taken from a photo of a building in Berkeley, CA
JavaScript
6
star
48

Journal

Backbone.js / Node.js multi-user journal app
CoffeeScript
6
star
49

gatsby-theme-cooper-hewitt

JavaScript
6
star
50

gatsby-starter-theme-cooper-hewitt

Starter for gatsby-theme-cooper-hewitt
JavaScript
6
star
51

gatsby-starter-blog-child-theme

Starter for creating a child theme for gatsby-theme-blog
JavaScript
6
star
52

react-html-elements-styleguide

React styleguide component
JavaScript
6
star
53

react-message

React component for showing status messages
CoffeeScript
6
star
54

eduglu_features

Core eduglue features
PHP
5
star
55

Family-History-Distro-features

Features for the Family History Drupal Distro
PHP
5
star
56

create-gatsby-fs-routes

wee prototype
JavaScript
5
star
57

electric-cloudflare-kv-sync

Demo showing how to sync data with ElectricSQL from Postgres to Cloudflare's Workers KV
TypeScript
5
star
58

eduglu_make

Drush Make file for eduglu
4
star
59

docker-xelatex

Docker container with Xelatex and high quality free fonts installed
Shell
4
star
60

reactive-static-generation-benchmarks

Benchmarks for testing Reactive Static Generation vs SSG/SSR
TypeScript
4
star
61

index-gatsby-blog-demo

Gatsby starter for a Contentful project.
JavaScript
4
star
62

gatsby-plugin-emoji-cursor

Gatsby plugin to add emjois which trail behind your cursor
JavaScript
4
star
63

brunch-backbone-widgets

Reusable Widgets for apps built with Backbone.js + Brunch + Sass/Compass
JavaScript
4
star
64

lmdb-backed-array

LMDB-backed array implementation for node.js for lowering memory usage for huge arrays.
JavaScript
4
star
65

every-second

A Gatsby site which which updates a time counter every second
CSS
4
star
66

hapi-dynamic-scope

Create dynamic route scopes based on information in the request
JavaScript
4
star
67

gatsby-plugin-inspector

Use Node.js inspector API to sample CPU/memory of a Gatsby build
JavaScript
4
star
68

gatsby-shopify-wordpress-demo

A Gatsby starter using the latest Shopify plugin showcasing a store with product overview, individual product pages, and a cart
JavaScript
4
star
69

backbone.js-practice

JavaScript
3
star
70

agility-gatsby-starter2

A sample GatsbyJS website using the Agility CMS Gatsby source plugin
3
star
71

Family-History-distro-HTML-mockup

mockup yo
JavaScript
3
star
72

eduglu_profile

Install profile (think distro) for Drupal
3
star
73

gatsby-starter-shopify

A Gatsby starter using the latest Shopify plugin showcasing a store with product overview, individual product pages, and a cart
JavaScript
3
star
74

test-recipes

some API ideas
JavaScript
3
star
75

gatsby-starter-theme-hyde

Starter for gatsby-theme-hyde
JavaScript
3
star
76

gatsby-cli-exploration

exploring some ideas for new UI for gatsby cli
JavaScript
3
star
77

reactjs-twitter-stream-example

Example React.js / Node.js app that streams tweets
JavaScript
3
star
78

hapi-death

Help Hapi.js die gracefully by intercepting SIGINT and SIGTERM and calling server.stop()
JavaScript
3
star
79

familyhistorydistro

Drupal Family History Distro
PHP
3
star
80

sanity-kitchen-sink

Kitchen Sink
JavaScript
2
star
81

atrium_book

port of atrium_book to Eduglu, KIT-complient, likely soon to be superceeded by new atrium_book version
PHP
2
star
82

BYU-Starter-Drupal-Profile

.make file and .profile file for a basic BYU Drupall install
2
star
83

hapi-influx

Hapi plugin to create a shared InfluxDB client
CoffeeScript
2
star
84

gc-functions-test

JavaScript
2
star
85

fun-with-fauna

JavaScript
2
star
86

image-processing-benchmark

CSS
2
star
87

notesfromquarantinechurch-blog

JavaScript
2
star
88

react-flickr-example

Flickr search page build with React
CSS
2
star
89

gatsby-source-airtable-demo

TypeScript
2
star
90

bug-report-123

JavaScript
2
star
91

Drupal-Flot

Fork of Drupal flot module to keep track of patches / changes I make
PHP
2
star
92

trello-flow

Create a Cumulative Flow Diagram from your Trello Board(s)
CoffeeScript
2
star
93

file-upload-tests

Testing the fastest way to upload files w/ Node.js on Linux
JavaScript
2
star
94

preview-testing

Gatsby starter for a Contentful project from the community.
JavaScript
2
star
95

react-simple-form-inline-styles

Simple inline styles for React forms
CoffeeScript
2
star
96

agility-starter-2

JavaScript
2
star
97

gatsby-site

Gatsby Site
JavaScript
2
star
98

the-nope-game

thenopegame.com (or whatever the domain will be)
JavaScript
2
star
99

static-query-bug-repo

JavaScript
2
star
100

my-new-contentful-blog

Gatsby starter for a Contentful project from the community.
JavaScript
2
star