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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@elqnt/chat

v3.1.0

Published

Platform-agnostic chat SDK for React and React Native

Readme

@elqnt/chat

Platform-agnostic chat SDK for React and React Native. Uses HTTP + SSE for reliable real-time communication.

Key Features:

  • Mutations via HTTP - startChat(), loadChat() return data directly (no waiting for SSE events)
  • Events via SSE - Real-time messages, typing indicators, agent updates
  • Multi-transport - Browser EventSource, React Native fetch-based SSE, WhatsApp webhooks
  • TypeScript-first - Full type definitions for all models and events

Installation

pnpm add @elqnt/chat

TypeScript Configuration

This package uses subpath exports. Ensure your tsconfig.json includes a compatible moduleResolution setting:

{
  "compilerOptions": {
    "moduleResolution": "bundler"
  }
}

Supported values: "bundler", "node16", or "nodenext".

Expo / React Native

For Expo projects, add to your tsconfig.json:

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "moduleResolution": "bundler"
  }
}

Quick Start

import { useChat } from "@elqnt/chat/hooks";

function ChatComponent() {
  const {
    connect,
    disconnect,
    sendMessage,
    startChat,
    loadChat,
    messages,
    isConnected,
    currentChat,
  } = useChat({
    baseUrl: "https://api.example.com/chat",
    orgId: "org-123",
    userId: "user-456",
  });

  useEffect(() => {
    connect();
    return () => disconnect();
  }, []);

  // Start a new chat - returns chatKey immediately
  const handleNewChat = async () => {
    const chatKey = await startChat({ agentId: "support-agent" });
    console.log("Created chat:", chatKey);
  };

  // Load existing chat - returns Chat immediately
  const handleLoadChat = async (chatKey: string) => {
    const chat = await loadChat(chatKey);
    console.log("Loaded chat with", chat.messages.length, "messages");
  };

  const handleSend = async (text: string) => {
    await sendMessage(text);
  };

  return (
    <div>
      <ConnectionStatus connected={isConnected} />
      <MessageList messages={messages} />
      <MessageInput onSend={handleSend} />
    </div>
  );
}

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        Your App                              │
├─────────────────────────────────────────────────────────────┤
│                      useChat Hook                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │   State     │  │   Events    │  │   Chat Operations   │  │
│  │  messages   │  │  onMessage  │  │   sendMessage       │  │
│  │  chatKey    │  │  on(type)   │  │   startChat         │  │
│  │  isConnected│  │             │  │   loadChat          │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                    Transport Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │  SSE         │  │  SSE-Fetch   │  │  WhatsApp        │   │
│  │  (Browser)   │  │  (React      │  │  (Backend        │   │
│  │              │  │   Native)    │  │   Webhook)       │   │
│  └──────────────┘  └──────────────┘  └──────────────────┘   │
├─────────────────────────────────────────────────────────────┤
│                    Chat Server                               │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  POST /create, /send, /load, /end, /typing, /event   │   │
│  │  GET  /stream (SSE)                                   │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Exports

/hooks - React Hooks

import { useChat } from "@elqnt/chat/hooks";

useChat Options:

| Option | Type | Required | Description | |--------|------|----------|-------------| | baseUrl | string | Yes | Chat server URL | | orgId | string | Yes | Organization ID | | userId | string | Yes | User ID | | clientType | "customer" \| "humanAgent" \| "observer" | No | Client type (default: "customer") | | transport | ChatTransport \| "sse" \| "sse-fetch" | No | Transport to use | | onMessage | (event: ChatEvent) => void | No | Event callback | | onError | (error: TransportError) => void | No | Error callback | | autoConnect | boolean | No | Connect on mount | | debug | boolean | No | Enable logging |

useChat Return:

interface UseChatReturn {
  // Connection
  connect: () => Promise<void>;
  disconnect: () => void;
  connectionState: TransportState;
  isConnected: boolean;

  // Chat Operations (return data directly via HTTP)
  startChat: (metadata?: Record<string, unknown>) => Promise<string>;  // Returns chatKey
  loadChat: (chatKey: string) => Promise<Chat>;                        // Returns loaded Chat
  sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;
  sendEvent: (event: Omit<ChatEvent, "timestamp">) => Promise<void>;
  endChat: (reason?: string) => Promise<void>;

  // Typing Indicators
  startTyping: () => void;
  stopTyping: () => void;

  // State (auto-updated by hook)
  currentChat: Chat | null;
  chatKey: string | null;
  messages: ChatMessage[];
  error: TransportError | null;
  metrics: ConnectionMetrics;

  // Events (SSE push events)
  on: (eventType: string, handler: (event: ChatEvent) => void) => () => void;
  clearError: () => void;
}

Note: startChat() and loadChat() use direct HTTP calls and return data immediately. You don't need to listen for new_chat_created or load_chat_response events - those are only broadcast for multi-tab synchronization.

/api - Low-Level API Functions

import {
  // Browser API (uses @elqnt/api-client)
  getChatHistoryApi,
  getChatApi,
  updateChatApi,
  deleteChatApi,
  getActiveChatsApi,
  getActiveChatsCountApi,

  // Stream API (direct HTTP)
  createChat,
  sendChatMessage,
  loadChat,
  endChat,
  sendTypingIndicator,
  sendEvent,
} from "@elqnt/chat/api";

/models - TypeScript Types

import type {
  Chat,
  ChatMessage,
  ChatEvent,
  ChatEventTypeTS,
  ChatUser,
  ChatStatusTS,
  MessageStatusTS,
  Attachment,
} from "@elqnt/chat/models";

/transport - Transport Adapters

import {
  createSSETransport,      // Browser EventSource
  createFetchSSETransport, // React Native / Fetch-based
  createWhatsAppTransport, // WhatsApp Business API (stub)
} from "@elqnt/chat/transport";

import type {
  ChatTransport,
  TransportConfig,
  TransportState,
  TransportError,
  ConnectionMetrics,
  CreateChatOptions,
  CreateChatResponse,
  LoadChatOptions,
  LoadChatResponse,
} from "@elqnt/chat/transport";

Transport Options

Browser (Default)

Uses native EventSource for SSE. This is the default and recommended transport for browser environments.

const chat = useChat({
  baseUrl: "...",
  orgId: "...",
  userId: "...",
  // transport defaults to "sse"
});

React Native

Uses fetch with ReadableStream for SSE. Required for React Native since it doesn't have native EventSource.

import { createFetchSSETransport } from "@elqnt/chat/transport";

const transport = createFetchSSETransport();

const chat = useChat({
  baseUrl: "...",
  orgId: "...",
  userId: "...",
  transport,
});

Custom Transport

Implement the ChatTransport interface for custom integrations:

import type { ChatTransport } from "@elqnt/chat/transport";

const customTransport: ChatTransport = {
  // Connection
  async connect(config) { /* ... */ },
  disconnect() { /* ... */ },

  // Mutations (return data directly)
  async createChat(options) { /* returns { chatKey } */ },
  async loadChatData(options) { /* returns { chat, agentId? } */ },

  // Fire-and-forget operations
  async send(event) { /* ... */ },
  async sendMessage(message) { /* ... */ },

  // Event subscriptions
  onMessage(handler) { /* returns unsubscribe */ },
  on(eventType, handler) { /* returns unsubscribe */ },

  // State
  getState() { /* returns TransportState */ },
  getMetrics() { /* returns ConnectionMetrics */ },
  getError() { /* returns TransportError | undefined */ },
  clearError() { /* ... */ },
};

Event Types

Subscribe to specific events:

const { on } = useChat({ ... });

// Subscribe to typing events
const unsubscribe = on("typing", (event) => {
  console.log("User typing:", event.userId);
});

// Clean up
unsubscribe();

Common event types:

| Event | Description | |-------|-------------| | message | New message received | | typing | User started typing | | stopped_typing | User stopped typing | | new_chat_created | New chat session created | | load_chat_response | Chat loaded | | chat_ended | Chat session ended | | human_agent_joined | Human agent joined chat | | human_agent_left | Human agent left chat | | agent_execution_started | AI agent started processing | | agent_execution_ended | AI agent finished processing |

WhatsApp Integration

WhatsApp Business API integration happens via backend webhooks. The createWhatsAppTransport is a stub that documents the integration pattern.

Backend Setup

  1. Create a Meta Business App with WhatsApp integration
  2. Configure webhook URL pointing to your chat service
  3. Implement webhook handlers:
// Webhook verification
func HandleWhatsAppWebhook(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
        verifyToken := r.URL.Query().Get("hub.verify_token")
        if verifyToken == os.Getenv("WHATSAPP_VERIFY_TOKEN") {
            w.Write([]byte(r.URL.Query().Get("hub.challenge")))
            return
        }
        http.Error(w, "Invalid verify token", 403)
        return
    }

    // Handle incoming message
    var payload WhatsAppPayload
    json.NewDecoder(r.Body).Decode(&payload)

    // Map to chat event and publish
    chatEvent := mapWhatsAppToChatEvent(payload)
    publishToChatService(chatEvent)
}

Helper Functions

import { mapWhatsAppToChatEvent } from "@elqnt/chat/transport";

// In your webhook handler
const events = mapWhatsAppToChatEvent(webhookPayload, orgId);
events.forEach(event => publishToChatService(event));

Migration from v2

Breaking Changes in v3.0

  1. UI Components Removed - Build your own UI
  2. Contexts Removed - Use useChat hook directly
  3. WebSocket Removed - SSE only (more reliable)
  4. Redux Integration Removed - Use hook state

Changes in v3.0.1

  1. loadChat() returns Promise<Chat> - Previously returned Promise<void>, now returns the loaded chat directly
  2. startChat() returns immediately - No longer waits for SSE event, returns chatKey from HTTP response
  3. Transport interface extended - Added createChat() and loadChatData() methods for direct HTTP responses
  4. Event handlers simplified - new_chat_created and load_chat_response events are now only for multi-tab sync

Migration Steps

// Before (v2)
import { WebSocketChatCustomerProvider, useWebSocketChatCustomer } from "@elqnt/chat";

function App() {
  return (
    <WebSocketChatCustomerProvider config={...}>
      <ChatComponent />
    </WebSocketChatCustomerProvider>
  );
}

function ChatComponent() {
  const { messages, sendMessage } = useWebSocketChatCustomer();
  return <ChatUI messages={messages} onSend={sendMessage} />;
}

// After (v3)
import { useChat } from "@elqnt/chat/hooks";

function ChatComponent() {
  const { messages, sendMessage, connect, disconnect } = useChat({
    baseUrl: "...",
    orgId: "...",
    userId: "...",
  });

  useEffect(() => {
    connect();
    return () => disconnect();
  }, []);

  return <ChatUI messages={messages} onSend={sendMessage} />;
}

Removed Exports

  • WebSocketChatCustomerProvider
  • WebSocketChatAdminProvider
  • useWebSocketChatCustomer
  • useWebSocketChatAdmin
  • useWebSocketChatBase
  • All UI components (ChatMessages, ChatInput, etc.)

Development

# Build
pnpm build

# Type check
pnpm typecheck

# Watch mode
pnpm dev

License

MIT