class SyncClient {
constructor(url, scope) {
this.url = url;
this.scope = scope;
this.pending = [];
this.state = [];
}
async createTodo(title, priority = 'medium') {
await this.mutate('todo.create', {
id: crypto.randomUUID(),
title,
priority,
});
}
async setPriority(id, priority) {
await this.mutate('todo.setPriority', { id, priority });
}
async mutate(type, args) {
const mutation = {
id: crypto.randomUUID(),
type,
args,
scope: this.scope,
};
// Optimistic update
this.applyLocal(mutation);
this.render();
// Queue and sync
this.pending.push(mutation);
await this.sync();
}
applyLocal(mutation) {
switch (mutation.type) {
case 'todo.create':
this.state.push({
id: mutation.args.id,
title: mutation.args.title,
completed: false,
priority: mutation.args.priority || 'medium',
});
break;
case 'todo.setPriority':
const todo = this.state.find(t => t.id === mutation.args.id);
if (todo) todo.priority = mutation.args.priority;
break;
}
}
render() {
const container = document.getElementById('todos');
container.innerHTML = this.state
.sort((a, b) => this.priorityOrder(a) - this.priorityOrder(b))
.map(todo => `
<div class="todo priority-${todo.priority}">
<span>${todo.title}</span>
<select onchange="sync.setPriority('${todo.id}', this.value)">
<option value="low" ${todo.priority === 'low' ? 'selected' : ''}>Low</option>
<option value="medium" ${todo.priority === 'medium' ? 'selected' : ''}>Medium</option>
<option value="high" ${todo.priority === 'high' ? 'selected' : ''}>High</option>
</select>
</div>
`).join('');
}
priorityOrder(todo) {
return { high: 0, medium: 1, low: 2 }[todo.priority];
}
async sync() {
if (this.pending.length === 0) return;
try {
const res = await fetch(this.url + '/_sync/push', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
scope: this.scope,
mutations: this.pending,
}),
});
if (res.ok) {
const { changes } = await res.json();
if (changes && changes.length > 0) {
this.state = JSON.parse(changes[0].data);
this.render();
}
this.pending = [];
}
} catch (e) {
console.log('Sync failed, will retry:', e);
}
}
}
// Initialize
const sync = new SyncClient('', 'default');