Skip to main content

Overview

socket-serve provides a clean, type-safe API for building real-time applications in serverless environments. The API is divided into three main parts:

Quick Reference

Server

import { createSocketServer } from 'socket-serve';
import { createNextJSAdapter, createExpressAdapter } from 'socket-serve/adapters';

// Create server
const server = createSocketServer(options);

// Handle connections
server.on('connection', (socket) => {
  // Socket methods
  socket.emit(event, data, ackCallback?);
  socket.on(event, handler);
  socket.join(room);
  socket.leave(room);
  socket.getRooms();
  socket.broadcastToRoom(room, event, data);
  socket.disconnect();
});

// Adapters
const nextAdapter = createNextJSAdapter(server);
const expressAdapter = createExpressAdapter(server);

Client

import { connect } from 'socket-serve/client';

// Connect
const socket = connect(url, options?);

// Events
socket.on('connect', () => {});
socket.on('disconnect', () => {});
socket.on(event, handler);

// Methods
socket.emit(event, data, ackCallback?);
socket.disconnect();

// Properties
socket.id;
socket.connected;

Core Concepts

Event-Driven

Both server and client use an event-driven architecture:
// Server listens for events from clients
socket.on('message', (data) => {
  console.log('Received:', data);
});

// Server emits events to clients
socket.emit('response', { success: true });

// Client listens for events from server
socket.on('response', (data) => {
  console.log('Server said:', data);
});

// Client emits events to server
socket.emit('message', { text: 'Hello!' });

Acknowledgments

Request/response pattern with callbacks:
// Client requests with acknowledgment
socket.emit('getData', { id: 123 }, (response) => {
  console.log('Got response:', response);
});

// Server responds
socket.on('getData', (data, ack) => {
  const result = fetchData(data.id);
  ack({ success: true, data: result });
});

Rooms

Group clients for targeted broadcasting:
// Join room
socket.join('lobby');

// Broadcast to room
socket.broadcastToRoom('lobby', 'announcement', {
  message: 'Welcome to the lobby!'
});

// Leave room
socket.leave('lobby');

Type Safety

socket-serve is written in TypeScript and provides full type safety:
import type {
  SocketServer,
  ServerSocket,
  ClientSocket,
  SocketMessage,
  SocketServerOptions
} from 'socket-serve/types';

// Typed event handlers
socket.on<{ message: string }>('chat', (data) => {
  data.message; // TypeScript knows this is a string
});

// Typed acknowledgments
socket.emit<{ id: number }, { data: string }>(
  'getData',
  { id: 123 },
  (response) => {
    response.data; // TypeScript knows this is a string
  }
);

Error Handling

Server Errors

server.on('connection', (socket) => {
  socket.on('error', (error) => {
    console.error('Socket error:', error);
  });
  
  socket.on('riskyOperation', async (data) => {
    try {
      const result = await performOperation(data);
      socket.emit('success', result);
    } catch (error) {
      socket.emit('error', {
        message: 'Operation failed',
        details: error.message
      });
    }
  });
});

Client Errors

socket.on('error', (error) => {
  console.error('Connection error:', error);
});

socket.on('connect_error', (error) => {
  console.error('Failed to connect:', error);
});

// Acknowledgment timeout
socket.emit('getData', { id: 123 }, (response, error) => {
  if (error) {
    console.error('Request timed out');
  } else {
    console.log('Got response:', response);
  }
});

Best Practices

Server Side

// ✅ Clean up on disconnect
socket.on('disconnect', () => {
  // Release resources
  // Clean up subscriptions
  // Notify other users
});

// ✅ Validate input
socket.on('message', (data) => {
  if (!data.text || typeof data.text !== 'string') {
    socket.emit('error', { message: 'Invalid message' });
    return;
  }
  // Process message
});

// ✅ Use rooms for efficient broadcasting
socket.join(`user:${userId}`);
socket.broadcastToRoom(`user:${userId}`, 'notification', data);

Client Side

// ✅ Handle reconnection
socket.on('connect', () => {
  // Re-subscribe to events
  // Sync state
});

// ✅ Clean up on unmount
useEffect(() => {
  const socket = connect('/api/socket');
  
  return () => {
    socket.disconnect();
  };
}, []);

// ✅ Use acknowledgments for critical operations
socket.emit('saveData', data, (response, error) => {
  if (error) {
    showError('Save failed');
  } else {
    showSuccess('Saved!');
  }
});

Next Steps