Home Getting Started Server Client Shared Types GitHub ↗
sockr-client@1.2.0

Client SDK

Framework-agnostic SocketClient core and 12 purpose-built React hooks. Full API reference.

Client SDK Reference

Complete reference for sockr-client. Covers the framework-agnostic SocketClient core, all 12 React hooks, and platform-specific notes.

SocketClient

The core client class. Works in any JavaScript environment — browser, Node.js, React Native — with no React dependency.

import { SocketClient } from 'sockr-client';

const client = new SocketClient(config: ClientConfig);

ClientConfig

PropertyTypeDefaultDescription
urlstringrequiredWebSocket server URL.
autoConnectbooleantrueConnect immediately on instantiation.
reconnectionbooleantrueEnable automatic reconnection.
reconnectionAttemptsnumber5Maximum reconnection attempts before giving up.
reconnectionDelaynumber1000Base delay in ms. Delay = reconnectionDelay × attempt (linear backoff).
timeoutnumber20000Connection timeout in milliseconds.
transports('websocket'|'polling')[]['websocket']Allowed Socket.IO transports. Use ['websocket'] for React Native.

ConnectionState

An enum describing the client's current connection lifecycle state.

ValueDescription
IDLEInitial state — not yet connected.
CONNECTINGConnection attempt in progress.
CONNECTEDSocket connected, not yet authenticated.
AUTHENTICATEDSocket connected and user authenticated.
RECONNECTINGLost connection, attempting reconnect.
DISCONNECTEDSocket fully disconnected.
ERRORConnection error occurred.

Methods

Connection

MethodDescription
connect(): voidManually initiate connection. Only needed if autoConnect: false.
disconnect(): voidDisconnect socket and stop any pending reconnect timer.

Authentication

MethodDescription
authenticate(token: string): voidSend auth token to server. Must be called after connect. Throws if not connected.

Direct Messaging (1:1)

MethodDescription
sendMessage(to, content, metadata?)Send a direct message to another user.
markMessageRead(messageId, from)Mark a received message as read.
getMessageHistory(withUserId, opts?)Fetch paginated DM history. opts: { limit?: number; before?: number }
startTyping(to)Send typing start indicator to a user.
stopTyping(to)Send typing stop indicator to a user.

Presence

MethodDescription
getOnlineStatus(userIds: string[])Request online status for a list of users. Listen for the online_status event for the response.

Group Management

MethodDescription
createGroup(name, members?, metadata?)Create a new group. Listen for group_created.
joinGroup(groupId)Join an existing group. Listen for group_joined.
leaveGroup(groupId)Leave a group. Listen for group_left.
getGroupMembers(groupId)Fetch group members. Listen for group_members.
getUserGroups()Fetch all groups the current user belongs to. Listen for user_groups.

Group Messaging

MethodDescription
sendGroupMessage(groupId, content, metadata?)Send a message to a group.
markGroupMessageRead(groupId, messageId)Mark a group message as read.
getGroupMessageHistory(groupId, opts?)Fetch paginated group history. opts: { limit?: number; before?: number }
startGroupTyping(groupId)Broadcast typing start to a group.
stopGroupTyping(groupId)Broadcast typing stop to a group.

Voice Calling (P2P)

MethodDescription
getIceServers()Request ICE/TURN servers from the server. Listen for call_ice_servers.
initiateCall(to, sdpOffer)Start a P2P call. Listen for call_ringing then call_answered.
answerCall(callId, sdpAnswer)Accept an incoming call. Caller receives call_answered.
rejectCall(callId)Decline an incoming call. Caller receives call_rejected.
hangUp(callId)End an active or ringing call. Both parties receive call_ended.
sendIceCandidate(callId, candidate)Trickle an ICE candidate to the remote peer during call setup.

Conference Calling (SFU)

MethodDescription
joinConference(groupId)Join (or create) a group conference. Listen for conference_token to connect to the SFU.
leaveConference(groupId)Leave a group conference. If last participant, the SFU room is torn down.

Event Subscriptions

MethodDescription
on(event, handler): () => voidSubscribe to an event. Returns an unsubscribe function.
off(event, handler): voidUnsubscribe a specific handler.

State

MethodReturnsDescription
isConnected()booleanTrue if state is CONNECTED or AUTHENTICATED.
isAuthenticated()booleanTrue if state is AUTHENTICATED.
getConnectionState()ConnectionStateCurrent state enum value.
getUserId()string | nullAuthenticated userId, or null.
onStateChange(listener)() => voidSubscribe to state changes. Returns unsubscribe function.

Events Reference

All events available via client.on(event, handler). In React, use useSocketEvent(event, handler).

Connection & Auth

EventPayloadDescription
connectnoneSocket connected to server.
disconnectstring (reason)Socket disconnected. Reconnection may follow.
errorErrorConnection error.
authenticated{ userId, socketId }Authentication succeeded.
auth_error{ message }Authentication rejected by server.

Presence

EventPayloadDescription
user_online{ userId }A user came online.
user_offline{ userId }A user went offline (last socket disconnected).
online_status{ statuses: Record<string, boolean> }Bulk online status response.

Direct Messages

EventPayloadDescription
message{ from, content, timestamp, messageId, metadata? }Incoming direct message.
message_delivered{ messageId }Your message was delivered to recipient.
message_read{ messageId, from? }Recipient read your message.
message_error{ messageId, error }Message delivery failed.
typing_start{ from }Another user started typing to you.
typing_stop{ from }Another user stopped typing.
message_history{ conversationId, messages: PersistedMessage[] }Paginated DM history response.

Groups & Group Messages

EventPayloadDescription
group_created{ group: Group }New group created by you.
group_create_error{ error }Group creation failed.
group_joined{ groupId, group, queuedMessages? }Successfully joined a group. Includes offline messages.
group_join_error{ groupId, error }Failed to join group.
group_left{ groupId }You left a group.
group_member_joined{ groupId, member: GroupMember }A member joined a group you're in.
group_member_left{ groupId, userId }A member left a group you're in.
group_members{ groupId, members: GroupMember[] }Group members list response.
user_groups{ groups: Group[] }All groups the authenticated user belongs to.
group_message{ groupId, messageId, from, content, timestamp, metadata? }Incoming group message.
group_message_delivered{ groupId, messageId }Your group message was delivered.
group_message_read{ groupId, messageId }A group message was read.
group_message_error{ groupId, messageId?, error }Group message delivery failed.
group_typing_start{ groupId, from }A group member started typing.
group_typing_stop{ groupId, from }A group member stopped typing.
group_message_history{ groupId, messages: PersistedMessage[] }Paginated group history response.

Voice Calls (P2P)

EventPayloadDescription
call_ice_servers{ iceServers: IceServer[] }ICE/TURN server list response (includes STUN + generated TURN credentials).
call_incoming{ callId, from, sdpOffer, iceServers }Incoming call from another user.
call_ringing{ callId }Callee received your call initiation.
call_answered{ callId, sdpAnswer }Remote peer accepted the call with their SDP answer.
call_rejected{ callId }Remote peer declined the call.
call_ended{ callId }Call was ended by either party (or remote disconnect).
call_busy{ callId }Called user is already in another call.
call_ice_candidate{ callId, candidate: IceCandidateInit }Trickled ICE candidate from the remote peer.

Conference Calls (SFU)

EventPayloadDescription
conference_token{ groupId, sfuUrl, token }SFU access token — connect to sfuUrl using token.
conference_started{ groupId, startedBy, participantCount }First participant joined a group conference.
conference_ended{ groupId }Last participant left — conference is over.
conference_participant_joined{ groupId, userId, participantCount }A group member joined the active conference.
conference_participant_left{ groupId, userId, participantCount }A participant left the conference.
conference_error{ groupId, error }Conference join/leave error (e.g. not a group member).

SocketProvider

React context provider. Wraps your component tree and makes all hooks available.

import { SocketProvider } from 'sockr-client';

function App() {
  return (
    <SocketProvider
      config={{ url: "http://localhost:3000", transports: ['websocket'] }}
      token={authToken}
    >
      {children}
    </SocketProvider>
  );
}

When token is provided, the provider calls client.authenticate(token) automatically once the socket connects. If token changes, it will re-authenticate.

useSocket()

1 useSocket()

Access the raw SocketClient instance and current connection state.

const {
  client,            // SocketClient | null
  isConnected,       // boolean
  isAuthenticated,   // boolean
  connectionState,   // ConnectionState enum
  userId,            // string | null
} = useSocket();

useSocketEvent(event, handler)

2 useSocketEvent(event, handler)

Subscribe to any socket event. Automatically unsubscribes on component unmount. Handler is called with the event payload.

useSocketEvent('message', (data) => {
  console.log('New message from', data.from, ':', data.content);
});

useSocketEvent('user_online', ({ userId }) => {
  setOnlineUsers(prev => new Set(prev).add(userId));
});

useMessages()

3 useMessages()

Collects all incoming direct messages into a local array. Listens for the message event automatically.

const {
  messages,     // Array<{ id, from, content, timestamp, metadata? }>
  addMessage,   // (message) => void — manually add a message
  clearMessages // () => void — clear all messages
} = useMessages();

useSendMessage()

4 useSendMessage()

Send direct messages with loading and error state. isSending resets when message_delivered or message_error is received.

const {
  sendMessage, // (to: string, content: string, metadata?) => void
  isSending,   // boolean
  error,       // string | null
} = useSendMessage();

// Usage
sendMessage('user-456', 'Hello!');
sendMessage('user-456', 'With metadata', { priority: 'high' });

usePresence()

5 usePresence()

Track online/offline status. Maintains a Set of online user IDs, updated from user_online, user_offline, and online_status events.

const {
  onlineUsers,      // Set<string> — set of online userIds
  isUserOnline,     // (userId: string) => boolean
  checkOnlineStatus // (userIds: string[]) => void — triggers online_status event
} = usePresence();

// Check if a user is online
if (isUserOnline('user-123')) {
  console.log('User is online');
}

// Bulk check
checkOnlineStatus(['user-1', 'user-2', 'user-3']);

useTypingIndicator(typingTimeout?)

6 useTypingIndicator(typingTimeout?)

For direct message conversations. Tracks who is typing. Typing indicators auto-clear after typingTimeout ms (default: 3000) if no stop event is received.

const {
  startTyping, // (to: string) => void
  stopTyping,  // (to: string) => void
  usersTyping, // Set<string> — userIds currently typing
} = useTypingIndicator(3000);

// In a chat input
<input
  onFocus={() => startTyping(recipientId)}
  onBlur={() => stopTyping(recipientId)}
  onChange={() => startTyping(recipientId)}
/>

// Display
{[...usersTyping].map(id => (
  <span key={id}>{id} is typing...</span>
))}

useGroup(groupId)

7 useGroup(groupId)

Manages membership state for a single group. Keeps the members list in sync by listening to group_member_joined and group_member_left events. Automatically fetches members once joined.

const {
  group,          // Group | null — full group object
  members,        // GroupMember[] — current member list
  isJoined,       // boolean
  join,           // () => void — emit group_join
  leave,          // () => void — emit group_leave
  refreshMembers, // () => void — re-fetch members from server
} = useGroup('group-id-123');

// Usage
if (!isJoined) join();
console.log(group?.name, 'has', members.length, 'members');

useGroupMessages(groupId, options?)

8 useGroupMessages(groupId, options?)

Manages messages for a single group. Auto-fetches history on mount. Handles queued messages from the group_joined payload. Deduplicates by message ID on reconnect replay.

const {
  messages,         // GroupMessage[] — sorted by timestamp
  isLoadingHistory, // boolean
  sendMessage,      // (content, metadata?) => void
  markRead,         // (messageId) => void
  fetchHistory,     // (before?: number) => void — load older messages
  clearMessages,    // () => void
} = useGroupMessages('group-id-123', {
  fetchHistory: true, // auto-fetch on mount (default: true)
  limit: 50,          // messages per page (default: 50)
});

// Paginate older messages
fetchHistory(messages[0]?.timestamp); // pass oldest timestamp as 'before'

useGroupTyping(groupId, stopDelay?)

9 useGroupTyping(groupId, stopDelay?)

Tracks typing indicators for a group. Excludes the local user from typingMembers. startTyping() debounces — calling it repeatedly on each keypress auto-stops after stopDelay ms of inactivity. Stale indicators auto-clear after stopDelay × 2 ms.

const {
  typingMembers, // string[] — userIds currently typing (excludes you)
  startTyping,   // () => void — call on keypress
  stopTyping,    // () => void — call on blur or message send
} = useGroupTyping('group-id-123', 2000);

// In a group chat input
<input
  onKeyDown={startTyping}
  onBlur={stopTyping}
  placeholder="Type a message..."
/>

{typingMembers.length > 0 && (
  <p>{typingMembers.join(', ')} {typingMembers.length === 1 ? 'is' : 'are'} typing...</p>
)}

useUserGroups()

10 useUserGroups()

Returns the authenticated user's group list. Fetches on mount. Auto-updates when groups are created, joined, or left (listens to group_created, group_joined, group_left events).

const {
  groups,      // Group[] — all groups the user belongs to
  isLoading,   // boolean
  refresh,     // () => void — re-fetch from server
  createGroup, // (name, members?, metadata?) => void
} = useUserGroups();

// Create a group
createGroup('Engineering', ['user-2', 'user-3'], { private: true });

// Display groups
groups.map(g => (
  <div key={g.id}>
    {g.name} — {g.members.length} members
  </div>
))

useVoiceCall(options?)

11 useVoiceCall(options?)

Full WebRTC P2P call lifecycle. Manages RTCPeerConnection, ICE candidate buffering, and local/remote media streams. Supports audio-only or audio+video calls.

const {
  callState,     // CallState — see values below
  incomingCall,  // IncomingCall | null — set when another user calls you
  localStream,   // MediaStream | null
  remoteStream,  // MediaStream | null
  currentCallId, // string | null
  startCall,     // (userId: string) => Promise<void>
  answerCall,    // () => Promise<void> — reads from incomingCall automatically
  rejectCall,    // () => void
  hangUp,        // () => void
} = useVoiceCall({ video: false }); // video: false is the default

// Initiate a call
await startCall('user-456');

// Incoming call — incomingCall is set automatically by the hook
if (incomingCall) {
  // Show UI: incomingCall.from, then:
  await answerCall(); // accepts the call
  // or: rejectCall();
}

Options

OptionTypeDefaultDescription
videobooleanfalseRequest camera access and include video track in the offer.

CallState

type CallState = 'idle' | 'calling' | 'ringing' | 'active' | 'busy' | 'ended'

ValueDescription
'idle'No active or pending call.
'calling'Outgoing call initiated, waiting for ringing confirmation.
'ringing'Caller: callee's device is ringing. Callee: incoming call received.
'active'Call is connected, media is flowing.
'busy'Callee was already in a call.
'ended'Call just ended (transitions back to 'idle' on cleanup).

useConferenceCall(sfuAdapter)

12 useConferenceCall(sfuAdapter)

SFU-based group conference calling. Handles join/leave, SFU connection lifecycle, and participant tracking. Pass an ISFUClientAdapter instance — use the included LiveKitClientAdapter or implement your own.

import { LiveKitClientAdapter } from 'sockr-client';
// npm install livekit-client  (peer dependency)

const adapter = new LiveKitClientAdapter();

const {
  conferenceState,   // ConferenceState — see values below
  participants,      // ConferenceCallParticipant[] — { userId: string }[]
  activeGroupId,     // string | null
  error,             // string | null
  joinConference,    // (groupId: string) => void
  leaveConference,   // () => void
  onRemoteTrack,     // (handler: (track, participantId) => void) => void
} = useConferenceCall({ adapter, audio: true, video: false });

// Join a group conference
joinConference('group-id-123');

// Handle incoming remote media tracks
onRemoteTrack((track, participantId) => {
  const el = document.getElementById(`video-${participantId}`) as HTMLVideoElement;
  el.srcObject = new MediaStream([track]);
});

ConferenceState

type ConferenceState = 'idle' | 'joining' | 'active' | 'ended' | 'error'

ValueDescription
'idle'Not in any conference.
'joining'Join requested, waiting for SFU token from server.
'active'Connected to the SFU room, media can flow.
'ended'Conference ended (by the server or last participant leaving).
'error'Conference join or SFU connection failed. Check error.

LiveKitClientAdapter

Install the LiveKit client SDK as a peer dependency:

npm install livekit-client

The adapter lazily requires livekit-client at runtime, so it won't affect bundle size if conference calling is unused.

ISFUClientAdapter interface

Implement this to use a different SFU (mediasoup, Janus, etc.):

interface ISFUClientAdapter {
  connect(sfuUrl: string, token: string, opts?: SFUConnectOptions): Promise<void>;
  disconnect(): Promise<void>;
  publishTracks(opts?: SFUPublishOptions): Promise<void>;
  onTrackSubscribed(handler: (track: MediaStreamTrack, participantId: string) => void): void;
  onTrackUnsubscribed(handler: (track: MediaStreamTrack, participantId: string) => void): void;
  onParticipantConnected(handler: (participantId: string) => void): void;
  onParticipantDisconnected(handler: (participantId: string) => void): void;
  onDisconnected(handler: () => void): void;
}

React Native

Sockr client works with React Native. Use WebSocket-only transport — polling is not supported in React Native environments.

import { SocketProvider } from 'sockr-client';

function App() {
  return (
    <SocketProvider
      config={{ url: "https://your-server.com", transports: ['websocket'] }}
      token={authToken}
    >
      <YourApp />
    </SocketProvider>
  );
}

// Or with vanilla SocketClient
import { SocketClient } from 'sockr-client';

const client = new SocketClient({
  url: 'https://your-server.com',
  transports: ['websocket'],
});
Shared Types → ← Server Reference