npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

chatstorm-client

v2.2.6

Published

A real-time chat client built using Socket.IO for seamless communication. Compatible with both React and React Native. This client handles connection, message exchange, event-driven updates, and user session management in a modular and extensible structur

Readme

ChatStorm Client

A powerful React hook for real-time chat functionality using Socket.IO. ChatStorm Client provides an easy-to-use interface for integrating socket-based messaging into your React and React Native applications with comprehensive event handling and callback systems.

🚀 Features

  • Real-time Communication: Instant message delivery and updates
  • Socket.IO Integration: Robust WebSocket connection management
  • Event-driven Architecture: Comprehensive callback system for all events
  • Typing Indicators: Real-time typing status notifications
  • Message History: Retrieve and search past conversations
  • Chat Management: Join chats, get chat lists, and manage conversations
  • Message Operations: Send, delete, and update messages (supports text, links, and media)
  • Online Status: Check if users are online in real-time
  • Error Handling: Built-in error notification system
  • TypeScript Support: Full TypeScript definitions included
  • Auto-reconnection: Automatic connection handling and cleanup

📦 Installation

Install the package via npm:

npm install chatstorm-client

Peer Dependencies

Make sure you have the following dependencies installed:

For React:

npm install react react-dom socket.io-client

For React Native:

npm install react socket.io-client
# react-dom is not needed for React Native

🏃‍♂️ Quick Start

React Native Setup

For React Native projects, you may need to install additional polyfills for Socket.IO:

npm install react-native-get-random-values

Then import it at the top of your entry file (usually index.js or App.js):

import 'react-native-get-random-values';

Basic Setup

import React from 'react';
import useChatSocket from 'chatstorm-client';

const ChatComponent = () => {
  const BACKEND_SOCKET_URL = 'ws://localhost:3001';
  const MONGO_USER_ID = 'your-user-id-here';

  const {
    messages,
    sendMessage,
    joinChat,
    getChatList,
    retrieveMessages,
    updateTypingAlert,
    deleteMessage,
    leaveChat,
    checkOnlineStatus,
    disconnectUser,
    setHandshakeSuccessCallback,
    setMessageReceivedCallback,
    setChatListCallback,
    setRetrieveMessagesCallback,
    setMessageSentCallback,
    setMessageUpdateCallback,
    setReceiverMessageUpdateCallback,
    setTypingAlertCallback,
    setOnLeaveCallback,
    setChatStatusCallback,
    setOnCheckOnlineStatus,
    setOnErrorNotify,
    setOnDisconnect,
    socketInstance,
  } = useChatSocket(BACKEND_SOCKET_URL, MONGO_USER_ID);

  // Set up event callbacks
  React.useEffect(() => {
    setHandshakeSuccessCallback((data) => {
      console.log('Connected successfully:', data);
    });

    setMessageReceivedCallback((message) => {
      console.log('New message received:', message);
    });

    setChatListCallback((chatList) => {
      console.log('Chat list updated:', chatList);
    });

    setRetrieveMessagesCallback((messages) => {
      console.log('Messages retrieved:', messages);
    });

    setOnCheckOnlineStatus((data) => {
      console.log('Online status:', data);
    });

    setOnErrorNotify((error) => {
      console.error('Error notification:', error);
    });

    setOnDisconnect((data) => {
      console.log('Disconnected:', data);
    });

    setChatStatusCallback((data) => {
      if (data.isJoined) {
        console.log('User joined chat:', data.data);
      } else if (data.isLeft) {
        console.log('User left chat');
      }
    });
  }, []);

  return (
    <div>
      <h1>Chat Application</h1>
      {/* Your chat UI components here */}
    </div>
  );
};

📚 API Reference

Hook Parameters

useChatSocket(serverUrl: string, userId: string)
  • serverUrl: WebSocket server URL (e.g., 'ws://localhost:3001')
  • userId: Unique identifier for the current user

Returned Functions

Core Functions

| Function | Parameters | Description | |----------|------------|-------------| | sendMessage | { receiverId: string, message: { text: string, link: string, media: string } } | Send a message to a specific user (supports text, link, and media) | | joinChat | { receiverId: string } | Join a chat with another user | | getChatList | { keyword?: string } | Retrieve list of available chats (keyword is optional) | | retrieveMessages | { receiverId: string, keyword?: string } | Get message history with a user (keyword is optional, automatically marks messages as seen) | | updateTypingAlert | { receiverId: string, isTyping: boolean } | Send typing status | | deleteMessage | { messageId: string } | Delete a specific message | | leaveChat | { receiverId: string } | Leave a chat conversation | | checkOnlineStatus | { receiverId: string } | Check if a user is online | | disconnectUser | () | Manually disconnect the user from the socket |

Callback Setters

| Function | Description | |----------|-------------| | setHandshakeSuccessCallback | Called when connection is established | | setMessageReceivedCallback | Called when a new message is received | | setMessageSentCallback | Called when a message is sent successfully | | setChatListCallback | Called when chat list is updated | | setRetrieveMessagesCallback | Called when messages are retrieved | | setMessageUpdateCallback | Called when a message is updated | | setReceiverMessageUpdateCallback | Called when receiver updates a message | | setTypingAlertCallback | Called when typing status is received | | setOnLeaveCallback | Called when a user leaves the chat | | setChatStatusCallback | Called when chat status changes (user joined/left) | | setOnCheckOnlineStatus | Called when online status is received | | setOnErrorNotify | Called when an error notification is received | | setOnDisconnect | Called when the socket connection is disconnected |

State

  • messages: Array of current messages in the chat

💡 Use Cases

1. Private Messaging App

import React, { useState } from 'react';
import useChatSocket from 'chatstorm-client';

const PrivateChat = () => {
  const [currentChat, setCurrentChat] = useState(null);
  const [messageInput, setMessageInput] = useState('');
  const [chatList, setChatList] = useState([]);

  const {
    messages,
    sendMessage,
    joinChat,
    getChatList,
    retrieveMessages,
    setMessageReceivedCallback,
    setChatListCallback,
    setRetrieveMessagesCallback,
  } = useChatSocket('ws://localhost:3001', 'user123');

  React.useEffect(() => {
    // Load chat list on component mount
    getChatList({ keyword: '' });

    setChatListCallback((data) => {
      setChatList(data.chats || []);
    });

    setMessageReceivedCallback((message) => {
      console.log('New message:', message);
    });

    setRetrieveMessagesCallback((data) => {
      console.log('Messages loaded:', data);
    });
  }, []);

  const handleSendMessage = () => {
    if (messageInput.trim() && currentChat) {
      sendMessage({
        receiverId: currentChat.id,
        message: {
          text: messageInput,
          link: '',
          media: '',
        },
      });
      setMessageInput('');
    }
  };

  const handleSelectChat = (chat) => {
    setCurrentChat(chat);
    joinChat({ receiverId: chat.id });
    retrieveMessages({ receiverId: chat.id, keyword: '' });
  };

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      {/* Chat List Sidebar */}
      <div style={{ width: '300px', borderRight: '1px solid #ccc' }}>
        <h3>Chats</h3>
        {chatList.map((chat) => (
          <div
            key={chat.id}
            onClick={() => handleSelectChat(chat)}
            style={{
              padding: '10px',
              cursor: 'pointer',
              backgroundColor: currentChat?.id === chat.id ? '#f0f0f0' : 'white',
            }}
          >
            {chat.name}
          </div>
        ))}
      </div>

      {/* Chat Area */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {currentChat ? (
          <>
            <div style={{ padding: '10px', borderBottom: '1px solid #ccc' }}>
              <h3>{currentChat.name}</h3>
            </div>
            
            {/* Messages */}
            <div style={{ flex: 1, padding: '10px', overflowY: 'auto' }}>
              {messages.map((message, index) => (
                <div key={index} style={{ marginBottom: '10px' }}>
                  <strong>{message.sender}:</strong> {message.content}
                </div>
              ))}
            </div>

            {/* Message Input */}
            <div style={{ padding: '10px', borderTop: '1px solid #ccc' }}>
              <input
                type="text"
                value={messageInput}
                onChange={(e) => setMessageInput(e.target.value)}
                onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
                placeholder="Type a message..."
                style={{ width: '100%', padding: '8px' }}
              />
              <button onClick={handleSendMessage}>Send</button>
            </div>
          </>
        ) : (
          <div style={{ padding: '20px', textAlign: 'center' }}>
            Select a chat to start messaging
          </div>
        )}
      </div>
    </div>
  );
};

2. Customer Support Chat

import React, { useState, useEffect } from 'react';
import useChatSocket from 'chatstorm-client';

const CustomerSupport = () => {
  const [isTyping, setIsTyping] = useState(false);
  const [supportAgent, setSupportAgent] = useState(null);

  const {
    messages,
    sendMessage,
    joinChat,
    updateTypingAlert,
    setMessageReceivedCallback,
    setHandshakeSuccessCallback,
    setTypingAlertCallback,
  } = useChatSocket('ws://support.example.com', 'customer123');

  useEffect(() => {
    // Connect to support agent
    joinChat({ receiverId: 'support-agent-001' });

    setHandshakeSuccessCallback((data) => {
      console.log('Connected to support:', data);
      setSupportAgent(data.agent);
    });

    setMessageReceivedCallback((message) => {
      console.log('Support message:', message);
    });

    setTypingAlertCallback((data) => {
      setIsTyping(data.isTyping);
    });
  }, []);

  const handleTyping = (isTyping) => {
    updateTypingAlert({
      receiverId: 'support-agent-001',
      isTyping,
    });
  };

  return (
    <div>
      <h2>Customer Support</h2>
      {supportAgent && (
        <p>Connected to: {supportAgent.name}</p>
      )}
      
      <div>
        {messages.map((message, index) => (
          <div key={index}>
            <strong>{message.sender}:</strong> {message.content}
          </div>
        ))}
      </div>

      {isTyping && (
        <p>Support agent is typing...</p>
      )}

      <input
        type="text"
        onFocus={() => handleTyping(true)}
        onBlur={() => handleTyping(false)}
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            sendMessage({
              receiverId: 'support-agent-001',
              message: {
                text: e.target.value,
                link: '',
                media: '',
              },
            });
            e.target.value = '';
          }
        }}
        placeholder="Type your message..."
      />
    </div>
  );
};

3. Group Chat Application

import React, { useState } from 'react';
import useChatSocket from 'chatstorm-client';

const GroupChat = () => {
  const [groupMembers, setGroupMembers] = useState([]);
  const [messageInput, setMessageInput] = useState('');

  const {
    messages,
    sendMessage,
    joinChat,
    getChatList,
    setMessageReceivedCallback,
    setChatListCallback,
  } = useChatSocket('ws://localhost:3001', 'user123');

  React.useEffect(() => {
    // Get group chats
    getChatList({ keyword: 'group' });

    setChatListCallback((data) => {
      setGroupMembers(data.chats || []);
    });

    setMessageReceivedCallback((message) => {
      console.log('Group message:', message);
    });
  }, []);

  const handleSendGroupMessage = () => {
    if (messageInput.trim()) {
      // Send to all group members
      groupMembers.forEach(member => {
        sendMessage({
          receiverId: member.id,
          message: {
            text: messageInput,
            link: '',
            media: '',
          },
        });
      });
      setMessageInput('');
    }
  };

  return (
    <div>
      <h2>Group Chat</h2>
      <div>
        <h3>Members ({groupMembers.length})</h3>
        {groupMembers.map(member => (
          <span key={member.id}>{member.name}, </span>
        ))}
      </div>
      
      <div>
        {messages.map((message, index) => (
          <div key={index}>
            <strong>{message.sender}:</strong> {message.content}
          </div>
        ))}
      </div>

      <input
        type="text"
        value={messageInput}
        onChange={(e) => setMessageInput(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && handleSendGroupMessage()}
        placeholder="Type a group message..."
      />
      <button onClick={handleSendGroupMessage}>Send</button>
    </div>
  );
};

📱 React Native Example

Here's a complete example for React Native:

import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from 'react-native';
import useChatSocket from 'chatstorm-client';

const ChatScreen = () => {
  const [messageInput, setMessageInput] = useState('');
  const [chatMessages, setChatMessages] = useState([]);
  const BACKEND_SOCKET_URL = 'ws://your-server.com';
  const USER_ID = 'your-user-id';

  const {
    messages,
    sendMessage,
    joinChat,
    setMessageReceivedCallback,
    setHandshakeSuccessCallback,
  } = useChatSocket(BACKEND_SOCKET_URL, USER_ID);

  useEffect(() => {
    setHandshakeSuccessCallback((data) => {
      console.log('Connected:', data);
      // Join a chat after connection
      joinChat({ receiverId: 'target-user-id' });
    });

    setMessageReceivedCallback((message) => {
      setChatMessages((prev) => [...prev, message]);
    });
  }, []);

  const handleSend = () => {
    if (messageInput.trim()) {
      sendMessage({
        receiverId: 'target-user-id',
        message: {
          text: messageInput,
          link: '',
          media: '',
        },
      });
      setMessageInput('');
    }
  };

  return (
    <View style={styles.container}>
      <FlatList
        data={chatMessages}
        keyExtractor={(item, index) => index.toString()}
        renderItem={({ item }) => (
          <View style={styles.messageContainer}>
            <Text style={styles.messageText}>{item.message}</Text>
          </View>
        )}
      />
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          value={messageInput}
          onChangeText={setMessageInput}
          placeholder="Type a message..."
        />
        <TouchableOpacity onPress={handleSend} style={styles.button}>
          <Text style={styles.buttonText}>Send</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 10,
  },
  messageContainer: {
    padding: 10,
    marginVertical: 5,
    backgroundColor: '#f0f0f0',
    borderRadius: 5,
  },
  messageText: {
    fontSize: 16,
  },
  inputContainer: {
    flexDirection: 'row',
    padding: 10,
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 5,
    padding: 10,
    marginRight: 10,
  },
  button: {
    backgroundColor: '#007bff',
    padding: 10,
    borderRadius: 5,
    justifyContent: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
});

export default ChatScreen;

🔧 Advanced Configuration

Custom Event Handling

const AdvancedChat = () => {
  const {
    setMessageUpdateCallback,
    setReceiverMessageUpdateCallback,
    setOnLeaveCallback,
    setOnCheckOnlineStatus,
    setOnErrorNotify,
    setOnDisconnect,
    deleteMessage,
    checkOnlineStatus,
    disconnectUser,
  } = useChatSocket('ws://localhost:3001', 'user123');

  React.useEffect(() => {
    // Handle message updates
    setMessageUpdateCallback((data) => {
      console.log('Message updated:', data);
      // Update UI to show edited message
    });

    setReceiverMessageUpdateCallback((data) => {
      console.log('Receiver updated message:', data);
      // Handle when other user edits their message
    });

    setOnLeaveCallback((data) => {
      console.log('User left:', data);
      // Handle user leaving the chat
    });

    setOnCheckOnlineStatus((data) => {
      console.log('User online status:', data);
      // Handle online status updates
    });

    setOnErrorNotify((error) => {
      console.error('Error occurred:', error);
      // Handle error notifications
    });

    setOnDisconnect((data) => {
      console.log('Socket disconnected:', data);
      // Handle disconnection (e.g., show reconnection UI)
    });
  }, []);

  const handleDeleteMessage = (messageId) => {
    deleteMessage({ messageId });
  };

  const handleCheckOnline = (receiverId) => {
    checkOnlineStatus({ receiverId });
  };

  const handleDisconnect = () => {
    disconnectUser();
  };

  return (
    <div>
      {/* Your chat UI with delete functionality */}
    </div>
  );
};

🐛 Troubleshooting

Common Issues

  1. Connection Failed
    // Ensure your server URL is correct and accessible
    const serverUrl = 'ws://localhost:3001'; // or 'wss://' for secure connections

React Native Specific Issues

  1. Socket.IO Connection Issues in React Native

    • Make sure you've installed react-native-get-random-values and imported it at the top of your entry file
    • For Android, ensure you have internet permissions in AndroidManifest.xml:
      <uses-permission android:name="android.permission.INTERNET" />
    • For iOS, ensure your server URL uses http:// or https:// instead of ws:// or wss:// in some cases
    • The package automatically configures transports for React Native compatibility
  2. Metro Bundler Issues

    • If you encounter module resolution errors, try clearing the Metro cache:
      npx react-native start --reset-cache
  3. Network Requests Blocked

    • For Android 9+, you may need to configure network security:
      • Add android:usesCleartextTraffic="true" to AndroidManifest.xml for HTTP connections
      • Or use HTTPS/WSS for production
  4. Messages Not Received

    // Make sure to set up callbacks before sending messages
    useEffect(() => {
      setMessageReceivedCallback((message) => {
        console.log('Message received:', message);
      });
    }, []);
  5. Typing Indicators Not Working

    // Ensure you're calling updateTypingAlert with correct parameters
    updateTypingAlert({
      receiverId: 'target-user-id',
      isTyping: true, // or false
    });

Debug Mode

Enable debug logging by checking the browser console for socket events:

useEffect(() => {
  setHandshakeSuccessCallback((data) => {
    console.log('🔗 Connection established:', data);
  });
  
  setMessageReceivedCallback((message) => {
    console.log('📨 Message received:', message);
  });
  
  setChatListCallback((chatList) => {
    console.log('💬 Chat list updated:', chatList);
  });

  setOnCheckOnlineStatus((data) => {
    console.log('🟢 Online status:', data);
  });

  setOnErrorNotify((error) => {
    console.error('❌ Error notification:', error);
  });

  setOnDisconnect((data) => {
    console.log('🔌 Disconnected:', data);
  });
}, []);

Chat Status Example

Handle chat join/leave notifications:

const ChatWithStatus = () => {
  const { joinChat, leaveChat, setChatStatusCallback } = useChatSocket('ws://localhost:3001', 'user123');

  useEffect(() => {
    setChatStatusCallback((data) => {
      if (data.isJoined) {
        console.log('User joined:', data.data);
        // Show notification: "User has joined the chat"
      } else if (data.isLeft) {
        console.log('User left the chat');
        // Show notification: "User has left the chat"
      }
    });
  }, []);

  const handleJoinChat = (receiverId) => {
    joinChat({ receiverId });
  };

  const handleLeaveChat = (receiverId) => {
    leaveChat({ receiverId });
  };

  return (
    <div>
      <button onClick={() => handleJoinChat('target-user-id')}>Join Chat</button>
      <button onClick={() => handleLeaveChat('target-user-id')}>Leave Chat</button>
    </div>
  );
};

Online Status Example

Check if a user is online:

const ChatWithOnlineStatus = () => {
  const [isOnline, setIsOnline] = useState(false);
  const { checkOnlineStatus, setOnCheckOnlineStatus } = useChatSocket('ws://localhost:3001', 'user123');

  useEffect(() => {
    setOnCheckOnlineStatus((data) => {
      setIsOnline(data.isOnline || false);
    });
  }, []);

  const handleCheckStatus = (receiverId) => {
    checkOnlineStatus({ receiverId });
  };

  return (
    <div>
      <button onClick={() => handleCheckStatus('target-user-id')}>
        Check Online Status
      </button>
      {isOnline ? <span>🟢 Online</span> : <span>🔴 Offline</span>}
    </div>
  );
};

Disconnect Example

Manually disconnect from the socket:

const ChatWithDisconnect = () => {
  const { disconnectUser, setOnDisconnect } = useChatSocket('ws://localhost:3001', 'user123');

  useEffect(() => {
    setOnDisconnect((data) => {
      console.log('Disconnected from server:', data);
      // Handle disconnection (e.g., show offline message, clear UI)
    });
  }, []);

  const handleLogout = () => {
    // Disconnect before logging out
    disconnectUser();
    // Additional logout logic here
  };

  return (
    <div>
      <button onClick={handleLogout}>Logout</button>
    </div>
  );
};

📄 License

ISC License - see package.json for details.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📞 Support

For support and questions, please open an issue on the GitHub repository.


🔽 Download Examples (ZIP)

  • React Web Example ZIP
    👉 https://github.com/Vikas-Rajput-JS/Chatstorm-client/raw/refs/heads/master/test/react-web.zip

  • React Native Example ZIP
    👉 https://github.com/Vikas-Rajput-JS/Chatstorm-client/raw/refs/heads/master/test/native.zip

Made with ❤️ by Vikas Rajput