Realtime
Weblisk provides signal-driven wrappers for real-time communication protocols.
WebSocket
Reactive WebSocket with auto-reconnect and heartbeat:
import { socket } from 'weblisk/net/ws.js'; const ws = socket('wss://api.example.com/ws', { reconnect: true, // Auto-reconnect on disconnect maxRetries: 10, // Max reconnection attempts heartbeat: 30000, // Heartbeat ping every 30s }); // Reactive message signal effect(() => { const msgs = ws.messages(); if (msgs.length) { console.log('Latest:', msgs[msgs.length - 1]); } }); // Connection state effect(() => { console.log('WS state:', ws.state()); // 'connecting', 'open', 'closed' }); // Send data ws.send({ type: 'subscribe', channel: 'updates' }); // Close ws.close();
Server-Sent Events (SSE)
Signal-driven SSE connection:
import { stream, latest } from 'weblisk/net/sse.js'; const sse = stream('/api/events', { channels: ['notifications', 'updates'], }); // All events effect(() => { console.log('Events:', sse.events()); }); // Just the latest event const lastEvent = latest(sse.events); effect(() => { const event = lastEvent(); if (event) showNotification(event.data); }); // Connection state effect(() => { console.log('SSE:', sse.status()); // 'connecting', 'open', 'closed' }); sse.close();
WebTransport
HTTP/3 bidirectional transport with WebSocket fallback:
import { transport } from 'weblisk/net/transport.js'; const conn = transport('https://api.example.com/transport', { wsUrl: 'wss://api.example.com/ws', // Fallback URL reconnect: true, heartbeat: 15000, }); // Connection state effect(() => console.log('State:', conn.state())); // Send data conn.send({ type: 'message', text: 'hello' }); // Listen for messages conn.on('message', (data) => { console.log('Received:', data); }); // Named channels const chat = conn.channel('chat'); chat.send({ text: 'Hi!' }); chat.on('message', (msg) => console.log(msg)); conn.close();
The transport module automatically selects WebTransport when available, falling back to WebSocket in all browsers.
CRDT Primitives Pro
Conflict-free replicated data types for offline-first collaboration. Resolve concurrent writes automatically without a central server — sync state between peers, tabs, or devices.
LWW Register
Last-Writer-Wins Register — resolves concurrent writes by timestamp. Ties broken by node ID.
import { lwwRegister } from 'weblisk/pro/crdt.js'; const title = lwwRegister('Untitled', 'node-a'); // Local write title.set('Meeting Notes'); // Merge a remote state received over WebSocket title.merge(remoteState); // Export state for syncing to other nodes ws.send(title.state());
Counters
Grow-Only (G-Counter) and Positive-Negative (PN-Counter) for distributed counts:
import { gCounter, pnCounter } from 'weblisk/pro/crdt.js'; // Grow-only counter (likes, page views) const likes = gCounter('node-a'); likes.increment(); likes.merge(remoteLikes); console.log(likes.value()); // Total across all nodes // PN counter (inventory, votes — supports decrement) const stock = pnCounter('node-a'); stock.increment(10); stock.decrement(3);
LWW Map
A key-value map where each key is an independent LWW Register — ideal for collaborative document fields:
import { lwwMap } from 'weblisk/pro/crdt.js'; const doc = lwwMap('node-a'); doc.set('title', 'Sprint Retro'); doc.set('status', 'in-progress'); // Merge remote changes doc.merge(remoteState); console.log(doc.get('title')); // Latest value console.log(doc.entries()); // All key-value pairs
CRDT Types
| Type | Use Case | Operations |
|---|---|---|
lwwRegister | Single value (name, status) | get, set, merge, state |
gCounter | Grow-only counts (likes, views) | increment, value, merge, state |
pnCounter | Counts with decrement (stock, votes) | increment, decrement, value, merge, state |
lwwMap | Key-value document fields | get, set, delete, entries, merge, state |