Skip to content

Latest commit

History

1,232 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Logux Client

Logux is a new way to connect client and server. Instead of sending HTTP requests (e.g., AJAX and GraphQL) it synchronizes log of operations between client, server, and other clients.

This repository contains Logux base components to build web client:

  • CrossTabClient and Client to create web client for Logux.
  • IndexedStore to store Logux log in IndexedDB.
  • SqlLogStore to store Logux log in SQLite or PGlite.
  • badge() widget to show Logux synchronization status in UI.
  • status() to write own UI to show Logux synchronization status in UI.
  • attention(), confirm(), favicon() to improve UX in Logux web app.
  • log() to print Logux synchronization status to browser DevTools.

Check demo page for widget UI.


Logux Client is built by Evil Martians, an American design and engineering consultancy for developer tools, AI, and cybersecurity startups.


Install

npm install @logux/core @logux/client nanostores

Usage

See documentation for Logux API.

import{CrossTabClient,badge,badgeEn,log}from'@logux/client'import{badgeStyles}from'@logux/client/badge/styles'letuserId=document.querySelector('meta[name=user]').contentlettoken=document.querySelector('meta[name=token]').contentconstclient=newCrossTabClient({subprotocol: 1,server: 'wss://example.com:1337',
userId,
token
})badge(client,{messages: badgeEn,styles: badgeStyles})log(client)client.start()

SQL Tables

@logux/client/db keeps CRDT tables in a local SQL database (like SQLite in the browser) filled from Logux log. All changes are synchronized as Logux actions, and edit conflicts are resolved with per-field last write wins.

It needs Nano Stores SQL database:

npm install @nanostores/sql
import{openDb}from'@nanostores/sql'import{sqlocalDriver}from'@nanostores/sql/sqlocal'import{bigint,createCrdtDatabase,number,optional,string}from'@logux/client/db'letdb=openDb(sqlocalDriver('app.sqlite'))letcrdt=createCrdtDatabase(client,db,{migrating(done){// Show “Migrating database” loader until done promise},asyncrepeat(){// Ask server to the full client log// Remove if you store the whole lo locally}})// The third argument defines indexes: a column, an array of columns,// `{ columns, unique }`, or the whole `CREATE INDEX` statement in `{ sql }`letuser=crdt.table('user',{age: optional(number()),createdAt: bigint({default: ()=>Date.now()}),name: string()},['name',['age','createdAt DESC']])awaitcrdt.readyletid=awaituser.create({name: 'Ann'})awaituser.update(id,{age: 30})let$adults=user.select`WHERE "age" >= ${18} ORDER BY "name"`// Arrays create batch actions, applied in a single SQL queryletids=awaituser.create([{name: 'Ben'},{name: 'Cat'}])awaituser.update(ids,{age: 20})awaituser.delete(ids)

Custom actions are applied to the database by your callback. Action types in the callback come from defineAction():

import{defineAction}from'@logux/actions'letuserRenamed=defineAction<{id: stringname: stringtype: 'user/renamed'}>('user/renamed')letrenameUser=crdt.action(userRenamed,async(tx,action,meta)=>{// change() keeps per-field last write wins, unlike your own UPDATEawaituser.change(tx,action.id,{name: action.name},meta)})awaitrenameUser({ id,name: 'New'})

The same database can keep the Logux log itself:

import{CrossTabClient}from'@logux/client'import{SqlLogStore}from'@logux/client/db'constclient=newCrossTabClient({,store: newSqlLogStore(db)})

End-to-End Encryption

encryptActions() encrypts actions before sending them to the server, so the server can’t read users’ data. Pass a password or an AES CryptoKey and list action types to be kept unencrypted.

import{encryptActions}from'@logux/client'encryptActions(client,localStorage.getItem('userPassword'),{ignore: ['server/public']})

About

Logux base components to build web client

Resources

Stars

747 stars

Watchers

10 watching

Forks

Releases

Used by

Contributors

Languages