Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/logux/docs
Guide, recipes, and protocol specifications for Logux
https://github.com/logux/docs
Last synced: 4 days ago
JSON representation
Guide, recipes, and protocol specifications for Logux
- Host: GitHub
- URL: https://github.com/logux/docs
- Owner: logux
- License: mit
- Created: 2016-12-06T23:44:24.000Z (almost 8 years ago)
- Default Branch: main
- Last Pushed: 2024-09-19T14:50:09.000Z (about 2 months ago)
- Last Synced: 2024-11-01T21:35:55.172Z (12 days ago)
- Language: JavaScript
- Homepage: https://logux.org/
- Size: 1.06 MB
- Stars: 356
- Watchers: 14
- Forks: 38
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - docs
README
# Logux
Logux is a flexible JS framework to make [local-first](https://www.inkandswitch.com/local-first/) **sync engine** with **real-time updates**, **offline-first**, **CRDT**, an **optimistic UI**.
- Instead of other local-first solutions, it is **not a database, but a framework** to build sync engines with specific needs of your project.
- **No vendor lock-in**. It works with any database and in any cloud.
- Great **TypeScript** support with end-to-end type checking from client to server.
- We thought about many production-ready problems like **monitoring**, **scaling**, **outdated clients**, authentication, rich test API.
- Optional **end-to-end encryption**.
- Just extra [**7 KB**](https://github.com/logux/client/blob/main/package.json#L141-L148) in client-side JS bundle.Ask your questions at [community](https://github.com/orgs/logux/discussions) or [commercial support](mailto:[email protected]).
[Next chapter](./guide/starting/project.md)
## Client Example
Using [Logux Client](https://github.com/logux/client/):
React client
```ts
import { syncMapTemplate } from '@logux/client'export type TaskValue = {
finished: boolean
text: string
authorId: string
}export const Task = syncMapTemplate('tasks')
``````ts
export const ToDo = ({ userId }) => {
const tasks = useFilter(Task, { authorId: userId })
if (tasks.isLoading) {
return
} else {
return
- {task.text} )}
{tasks.map(task =>
}
}
```
```ts
export const TaskPage = ({ id }) => {
const client = useClient()
const task = useSync(Task, id)
if (task.isLoading) {
return
} else {
return
{
changeSyncMapById(client, Task, id, { finished: e.target.checked })
}}>
{
changeSyncMapById(client, Task, id, { text: e.target.value })
}} />
}
}
```
Vue client
Using [Logux Vuex](https://github.com/logux/vuex/):
```html
Loading
{{ counter }}
import { computed } from 'vue'
import { useStore, useSubscription } from '@logux/vuex'
export default {
setup () {
// Inject store into the component
let store = useStore()
// Retrieve counter state from store
let counter = computed(() => store.state.counter)
// Load current counter from server and subscribe to counter changes
let isSubscribing = useSubscription(['counter'])
function increment () {
// Send action to the server and all tabs in this browser
store.commit.sync({ type: 'INC' })
}
return {
counter,
increment,
isSubscribing
}
}
}
```
Pure JS client
You can use [Logux Client](https://github.com/logux/client/) API with any framework:
```js
client.type('INC', (action, meta) => {
counter.innerHTML = parseInt(counter.innerHTML) + 1
})
increase.addEventListener('click', () => {
client.sync({ type: 'INC' })
})
loading.classList.add('is-show')
await client.sync({ type: 'logux/subscribe' channel: 'counter' })
loading.classList.remove('is-show')
```
## Server Example
Using [Logux Server](https://github.com/logux/server/):
```js
addSyncMap(server, 'tasks', {
async access (ctx, id) {
const task = await Task.find(id)
return ctx.userId === task.authorId
},
async load (ctx, id, since) {
const task = await Task.find(id)
if (!task) throw new LoguxNotFoundError()
return {
id: task.id,
text: ChangedAt(task.text, task.textChanged),
finished: ChangedAt(task.finished, task.finishedChanged),
}
},
async create (ctx, id, fields, time) {
await Task.create({
id,
authorId: ctx.userId,
text: fields.text,
textChanged: time,
finished: fields.finished,
finishedChanged: time
})
},
async change (ctx, id, fields, time) {
const task = await Task.find(id)
if ('text' in fields) {
if (task.textChanged < time) {
await task.update({
text: fields.text,
textChanged: time
})
}
}
if ('finished' in fields) {
if (task.finishedChanged < time) {
await task.update({
finished: fields.finished,
finishedChanged: time
})
}
}
}
async delete (ctx, id) {
await Task.delete(id)
}
})
addSyncMapFilter(server, 'tasks', {
access (ctx, filter) {
return true
},
initial (ctx, filter, since) {
let tasks = await Tasks.where({ ...filter, authorId: ctx.userId })
return tasks.map(task => ({
id: task.id,
text: ChangedAt(task.text, task.textChanged),
finished: ChangedAt(task.finished, task.finishedChanged),
}))
},
actions (filterCtx, filter) {
return (actionCtx, action, meta) => {
return actionCtx.userId === filterCtx.userId
}
}
})
```