@lattestream/client
v1.2.0
Published
LatteStream client SDK for browsers and frontend frameworks
Maintainers
Readme
@lattestream/client
LatteStream client SDK for browsers and frontend frameworks. Real-time messaging with WebSocket support, Pusher-style API, and TypeScript-first design.
Features
- Framework Agnostic - Works with React, Vue, Angular, Svelte, or vanilla JS
- TypeScript First - Full type safety with comprehensive type definitions
- Auto-reconnection - Robust connection handling with exponential backoff
- Channel Authentication - Built-in support for private and presence channels
- Presence Channels - Track who's online with user presence
- Performance Optimized - Event batching, object pooling, and lazy loading
- Tiny Bundle Size - Optimized for modern bundlers
Installation
npm install @lattestream/clientOr with yarn/pnpm:
yarn add @lattestream/client
# or
pnpm add @lattestream/clientQuick Start
import LatteStream from '@lattestream/client';
// Initialize with public key
const client = new LatteStream('lspk_your_public_key', {
cluster: 'eu1',
authEndpoint: '/auth', // Required for private/presence channels
});
// Connect
client.connect();
// Subscribe to a channel (must subscribe within 30 seconds)
const channel = client.subscribe('private-channel-name');
// Listen for events
channel.bind('client-example-event', (data) => {
console.log('Received:', data);
});
// Trigger client events (private/presence channels only)
channel.trigger('client-example-event', { message: 'Hello!' });Channel Types
Public Channels
No authentication required. Anyone can subscribe.
const channel = client.subscribe('public-updates');
channel.bind('announcement', (data) => {
console.log('Announcement:', data);
});Private Channels
Require authentication via your auth endpoint. Channel names must start with private-.
const channel = client.subscribe('private-user-123');
channel.bind('message', (data) => {
console.log('Private message:', data);
});Presence Channels
Track online users. Channel names must start with presence-.
Note: Webhooks are currently in development. Presence channels currently function as private channels with extra metadata.
const channel = client.subscribe('presence-chat');
// Listen for members joining
channel.bind('lattestream:member_added', (member) => {
console.log('User joined:', member);
});
// Listen for members leaving
channel.bind('lattestream:member_removed', (member) => {
console.log('User left:', member);
});
// Get current members
const members = channel.getMembers();
console.log('Online users:', members);API Reference
LatteStream
Constructor
new LatteStream(appKey: string, options?: LatteStreamOptions)Methods
connect()- Connect to LatteStreamdisconnect()- Disconnect from LatteStreamsubscribe(channelName: string, authOptions?: AuthOptions)- Subscribe to a channelunsubscribe(channelName: string)- Unsubscribe from a channelbind(eventName: string, callback: EventCallback)- Listen for global eventsunbind(eventName?: string, callback?: EventCallback)- Remove global event listenersgetSocketId()- Get current socket IDgetConnectionState()- Get connection stategetReconnectionAttempts()- Get number of reconnection attemptsforceReconnect()- Force immediate reconnection
Channel
Methods
bind(eventName: string, callback: EventCallback)- Listen for channel eventsunbind(eventName?: string, callback?: EventCallback)- Stop listening for eventstrigger(eventName: string, data?: any)- Trigger client event (private/presence only)isSubscribed()- Check if subscribedgetType()- Get channel type ('public', 'private', or 'presence')
PresenceChannel
Extends Channel with presence-specific methods:
getMembers()- Get all online membersgetMember(id: string)- Get specific membergetMyId()- Get your user IDgetMemberCount()- Get member count
Configuration Options
interface LatteStreamOptions {
wsEndpoint?: string; // Custom WebSocket endpoint
authEndpoint?: string; // Auth endpoint for private/presence channels
cluster?: string; // Cluster region (default: 'eu1')
forceTLS?: boolean; // Force TLS connection
enableLogging?: boolean; // Enable debug logging
activityTimeout?: number; // Activity timeout in ms
pongTimeout?: number; // Pong timeout in ms
unavailableTimeout?: number; // Unavailable timeout in ms
maxReconnectionAttempts?: number; // Max reconnection attempts
maxReconnectGapInSeconds?: number; // Max gap between reconnections
reconnectBaseDelay?: number; // Base delay in ms (default: 1000)
reconnectBackoffMultiplier?: number; // Backoff multiplier (default: 2)
reconnectJitter?: boolean; // Add random jitter (default: true)
enableBatching?: boolean; // Enable event batching
batchSize?: number; // Max batch size
batchInterval?: number; // Batch interval in ms
enablePerformanceMonitoring?: boolean;
}Connection States
The client can be in one of these states:
connecting- Attempting to connectconnected- Successfully connecteddisconnected- Disconnectedunavailable- Connection unavailablefailed- Connection failed
Listen for state changes:
client.bind('connection_state_change', (event) => {
console.log(`${event.previous} -> ${event.current}`);
});Authentication
For private and presence channels, set up an auth endpoint on your server:
// Client side
const client = new LatteStream('lspk_your_public_key', {
authEndpoint: '/auth',
});
const channel = client.subscribe('private-user-123');Your server should handle the auth request and use @lattestream/server to authorize:
// Server side (see @lattestream/server docs)
import LatteStreamServer from '@lattestream/server';
const server = new LatteStreamServer('lsk_your_encrypted_secret');
app.post('/auth', async (req, res) => {
const { socket_id, channel_name } = req.body;
// Your authorization logic
const authResponse = await server.authorizeChannel(
socket_id,
channel_name,
userData // For presence channels
);
res.json(authResponse);
});Advanced Features
Lazy Loading
For code splitting and dynamic imports:
import { LazyLatteStream } from '@lattestream/client';
// Lazy load the client
const client = await LazyLatteStream.createClient('lspk_your_key', options);Performance Utilities
Export performance utilities for advanced use cases:
import {
MessageQueue,
ObjectPool,
FastEventEmitter,
PerformanceMonitor,
debounce,
throttle,
} from '@lattestream/client';Examples
React Integration
import { useEffect, useState } from 'react';
import LatteStream from '@lattestream/client';
function App() {
const [messages, setMessages] = useState([]);
useEffect(() => {
const client = new LatteStream('lspk_your_key', {
authEndpoint: '/auth',
});
client.connect();
const channel = client.subscribe('chat');
channel.bind('message', (data) => {
setMessages((prev) => [...prev, data]);
});
return () => {
client.disconnect();
};
}, []);
return (
<div>
{messages.map((msg, i) => (
<div key={i}>{msg.text}</div>
))}
</div>
);
}Vue Integration
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import LatteStream from '@lattestream/client';
const messages = ref([]);
let client;
onMounted(() => {
client = new LatteStream('lspk_your_key', {
authEndpoint: '/auth',
});
client.connect();
const channel = client.subscribe('private-chat');
channel.bind('message', (data) => {
messages.value.push(data);
});
});
onUnmounted(() => {
if (client) client.disconnect();
});
</script>
<template>
<div v-for="(msg, i) in messages" :key="i">
{{ msg.text }}
</div>
</template>Browser Support
- Chrome/Edge (latest 2 versions)
- Firefox (latest 2 versions)
- Safari (latest 2 versions)
- iOS Safari (latest 2 versions)
- Chrome for Android (latest 2 versions)
TypeScript
This package includes TypeScript definitions out of the box. No need for @types packages.
import LatteStream, { Channel, PresenceChannel, LatteStreamOptions, ConnectionState } from '@lattestream/client';
const client: LatteStream = new LatteStream('lspk_key', {
cluster: 'eu1',
});Related Packages
- @lattestream/server - Server SDK for Node.js and Deno
License
MIT License - see LICENSE for details.
