Installation

npm install @klastra/ksync
No dependencies required! kSync v0.2 works out of the box with smart defaults. Zod is now optional for advanced schema validation.

Quick Start (30 seconds)

The fastest way to get real-time sync working:
import { createKSync } from '@klastra/ksync';

// Works instantly with smart defaults
const ksync = createKSync();

// Listen for events
ksync.on('message', (data, event) => {
  console.log(`${event.userId}: ${data.text}`);
});

// Send events (instant local, auto-synced if server configured)
await ksync.send('message', {
  text: 'Hello world!',
  timestamp: Date.now()
});

// Get current state
const state = ksync.getState();

Factory Functions (Optimized Presets)

kSync v0.2 provides factory functions optimized for different use cases:
import { createChat } from '@klastra/ksync';

// Chat with presence and optimized batching
const chat = createChat('my-room', {
  serverUrl: 'ws://localhost:8080'
});

// Set user presence
await chat.setPresence({
  status: 'online',
  metadata: { name: 'Alice', avatar: 'avatar-url' }
});

// Send messages
await chat.send('message', {
  text: 'Hello everyone!',
  author: 'Alice',
  timestamp: Date.now()
});

// Listen for messages and presence
chat.on('message', (data) => {
  console.log(`${data.author}: ${data.text}`);
});

chat.on('presence-update', (data) => {
  console.log(`${data.metadata?.name} is ${data.status}`);
});

Real-time Chat Example

Let’s build a complete chat application in under 50 lines:
import { createChat } from '@klastra/ksync';

// Create chat instance
const chat = createChat('general', {
  serverUrl: 'ws://localhost:8080',  // Optional - works offline without server
  features: { presence: true }
});

// Set user info
await chat.setPresence({
  status: 'online',
  metadata: { 
    name: 'Alice',
    avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Alice'
  }
});

// UI Elements (assuming HTML exists)
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const presenceDiv = document.getElementById('presence');

// Send message function
async function sendMessage() {
  const text = messageInput.value.trim();
  if (!text) return;

  await chat.send('message', {
    text,
    author: 'Alice',
    timestamp: Date.now(),
    id: `msg-${Date.now()}`
  });

  messageInput.value = '';
}

// Listen for messages
chat.on('message', (data) => {
  const messageEl = document.createElement('div');
  messageEl.innerHTML = `
    <strong>${data.author}</strong>: ${data.text}
    <small>(${new Date(data.timestamp).toLocaleTimeString()})</small>
  `;
  messagesDiv.appendChild(messageEl);
  messagesDiv.scrollTop = messagesDiv.scrollHeight;
});

// Listen for presence updates
chat.on('presence-update', (data) => {
  updatePresenceUI();
});

function updatePresenceUI() {
  const presence = chat.getPresence();
  presenceDiv.innerHTML = presence
    .map(p => `<span class="user ${p.status}">${p.metadata?.name || p.userId}</span>`)
    .join('');
}

// Event listeners
sendButton.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
  if (e.key === 'Enter') sendMessage();
});

// Initial presence update
updatePresenceUI();

React Integration

For React applications, kSync v0.2 provides simple state integration:
import React, { useState, useEffect } from 'react';
import { createChat } from '@klastra/ksync';

function ChatApp() {
  const [chat] = useState(() => createChat('my-room'));
  const [messages, setMessages] = useState([]);
  const [presence, setPresence] = useState([]);

  useEffect(() => {
    // Listen for messages
    chat.on('message', (data) => {
      setMessages(prev => [...prev, data]);
    });

    // Listen for presence
    chat.on('presence-update', () => {
      setPresence(chat.getPresence());
    });

    // Set initial presence
    chat.setPresence({
      status: 'online',
      metadata: { name: 'React User' }
    });

    return () => {
      chat.disconnect();
    };
  }, [chat]);

  const sendMessage = async (text: string) => {
    await chat.send('message', {
      text,
      author: 'React User',
      timestamp: Date.now(),
      id: `msg-${Date.now()}`
    });
  };

  return (
    <div>
      <div>
        <h3>Online ({presence.length})</h3>
        {presence.map(p => (
          <div key={p.userId}>{p.metadata?.name || p.userId}</div>
        ))}
      </div>
      
      <div>
        <h3>Messages</h3>
        {messages.map(msg => (
          <div key={msg.id}>
            <strong>{msg.author}</strong>: {msg.text}
          </div>
        ))}
      </div>
      
      <input 
        onKeyPress={e => e.key === 'Enter' && sendMessage(e.target.value)}
        placeholder="Type a message..."
      />
    </div>
  );
}

AI Streaming Example

Build a real-time AI chat with streaming responses:
import { createAI } from '@klastra/ksync';

const ai = createAI('gpt-assistant', {
  features: { streaming: true }
});

// Simple streaming chat interface
class AIChat {
  private currentResponse = '';
  private responseElement: HTMLElement;

  constructor(responseElementId: string) {
    this.responseElement = document.getElementById(responseElementId);
    this.setupListeners();
  }

  private setupListeners() {
    // Listen for streaming chunks
    ai.on('stream-chunk', (data) => {
      this.currentResponse += data.data;
      this.responseElement.textContent = this.currentResponse;
    });

    // Response complete
    ai.on('stream-end', (data) => {
      console.log('AI response complete');
      // Save to message history, etc.
    });
  }

  async askQuestion(question: string) {
    // Clear previous response
    this.currentResponse = '';
    this.responseElement.textContent = 'AI is thinking...';

    // Simulate AI response stream
    const responseId = `response-${Date.now()}`;
    await ai.startStream(responseId);

    // Simulate streaming response (replace with real AI API)
    const words = [
      'I understand your question. ',
      'Let me think about this carefully. ',
      'Based on my knowledge, ',
      'I would recommend the following approach...'
    ];

    for (const word of words) {
      await new Promise(resolve => setTimeout(resolve, 500));
      await ai.streamChunk(responseId, { data: word });
    }

    await ai.endStream(responseId);
  }
}

// Usage
const chat = new AIChat('ai-response');
document.getElementById('ask-button').onclick = () => {
  const question = document.getElementById('question-input').value;
  chat.askQuestion(question);
};

Advanced Configuration

For production applications, you can customize kSync extensively:
import { createKSync } from '@klastra/ksync';

const ksync = createKSync({
  // Connection
  serverUrl: 'wss://your-server.com/ws',
  room: 'my-app',
  userId: 'user-123',

  // Authentication
  auth: {
    token: 'your-jwt-token',
    type: 'bearer'
  },

  // Performance tuning
  performance: {
    batchSize: 200,         // Higher for throughput
    batchDelay: 5,          // Lower for real-time
    materializationCaching: true,
    compressionThreshold: 1024
  },

  // Offline support
  offline: {
    enabled: true,
    queueSize: 10000,
    persistence: true,
    syncOnReconnect: true
  },

  // Features
  features: {
    presence: true,
    streaming: true,
    encryption: false
  },

  // Production debugging
  debug: {
    events: false,      // Disable in production
    performance: true   // Monitor performance
  }
});

Next Steps


You now have a real-time sync engine running in under 2 minutes! kSync v0.2’s smart defaults mean you can focus on building features, not configuring infrastructure.