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

@quickly-desk/sdk

v0.0.5

Published

SDK for easy integration of Quickly Desk in React and React Native applications

Readme

Quickly Desk SDK

SDK for easy integration of Quickly Desk in React and React Native applications.

Installation

npm install @quickly-desk/sdk
# or
yarn add @quickly-desk/sdk

Usage

React (Web)

import React, { useMemo } from "react";
import {
  QuicklyDeskProvider,
  useCustomerAuth,
  useChatsWithWebSocket,
} from "@quickly-desk/sdk";

function App() {
  const config = useMemo(
    () => ({
      publicKey: "your-public-key",
      customerReference: "unique-customer-id",
      customerName: "Customer Name",
      phone: "11999999999", // optional
      email: "[email protected]", // optional
      avatar: "https://example.com/avatar.png", // optional
      metadata: {
        // Other optional metadata such as device, IP address, country...
      },
    }),
    [],
  );

  return (
    <QuicklyDeskProvider config={config}>
      <YourApp />
    </QuicklyDeskProvider>
  );
}

function YourApp() { const { loading, error, signOut } = useCustomerAuth(); const { chats, messages, sendMessage, createChat } = useChatsWithWebSocket();

// Use the hooks as needed return ...; }


### React Native

```tsx
import React, { useMemo } from "react";
import {
  QuicklyDeskProvider,
  useCustomerAuth,
  useChatsWithWebSocket,
} from "@quickly-desk/sdk";

function App() {
  const config = useMemo(
    () => ({
      publicKey: "your-public-key",
      customerReference: "unique-customer-id",
      customerName: "Customer Name",
      phone: "11999999999",
      email: "[email protected]",
    }),
    []
  );

  return (
    <QuicklyDeskProvider config={config}>
      <YourApp />
    </QuicklyDeskProvider>
  );
}

Features

  • No caching: The SDK always authenticates when the provider is executed
  • Automatic token refresh: Tokens are automatically refreshed when expired
  • Request queue: Failed requests are queued and retried after token refresh
  • WebSocket support: Real-time chat functionality with WebSocket connections

API

Hooks

useCustomerAuth()

Hook for managing customer authentication.

const { loading, error, signOut } = useCustomerAuth();
  • loading: Loading state during authentication (boolean)
  • error: Error message if authentication fails (string | null)
  • signOut(): Function to sign out manually

useChatsWithWebSocket()

Main hook for managing chats and messages. Automatically manages the WebSocket connection based on the component lifecycle.

Features:

  • ✅ Automatically connects to WebSocket when the component mounts
  • ✅ Waits for the WebSocket connection to be ready before loading chats
  • ✅ Automatically calls loadChats() after connecting
  • ✅ Automatically disconnects when the component unmounts (if it's the last component using it)
  • ✅ Uses reference counting to keep the connection alive during screen navigation
  • ✅ Protection against race conditions and multiple calls
  • ✅ Robust error and timeout handling
  • ✅ Can be used in multiple components simultaneously
const {
  chats,
  currentChat,
  messages,
  staffPresence,
  typingStatus,
  ws,
  loading,
  sendMessageLoading,
  createChatLoading,
  loadChats,
  loadChatHistory,
  sendMessage,
  createChat,
} = useChatsWithWebSocket();

Returned properties:

  • chats: List of chats (Chat[])
  • currentChat: Currently selected chat (Chat | null)
  • messages: Messages of the current chat (ChatMessage[])
  • staffPresence: Staff members currently viewing chats (string[], each entry is "staffId:chatId")
  • typingStatus: Typing status per chat ({ [id_chat: string]: { [id_user: string]: string } })
  • ws: WebSocket connection (WebSocket | null)
  • loading: Loading state (boolean)
  • sendMessageLoading: Message sending state (boolean)
  • createChatLoading: Chat creation state (boolean)
  • loadChats(): Loads the chat list
  • loadChatHistory(id_chat): Loads a specific chat's history
  • sendMessage(id_chat, content): Sends a message
  • createChat(): Creates a new chat
  • markAsRead(id_chat): Marks all messages in the chat as read for the customer (zeroes unread_count)

Usage examples:

// Chat list screen
function ChatsListScreen() {
  const { chats, loading, loadChats, createChat } = useChatsWithWebSocket();

  // WebSocket connects automatically on mount
  // loadChats() is called automatically after connection
  // WebSocket disconnects automatically on unmount

  const onRefresh = async () => {
    await loadChats(); // Can be called manually for refresh
  };

  return (
    <FlatList
      data={chats}
      renderItem={({ item }) => <ChatListItem chat={item} />}
      onRefresh={onRefresh}
      refreshing={loading}
    />
  );
}

// Individual chat screen
function ChatScreen({ id_chat }: { id_chat: string }) {
  const { messages, loadChatHistory, sendMessage, loading } =
    useChatsWithWebSocket();

  // Can use the same hook - WebSocket connection is shared
  // No need to manage the connection manually

  useEffect(() => {
    if (id_chat) {
      loadChatHistory(id_chat);
    }
  }, [id_chat, loadChatHistory]);

  return (
    <View>
      <FlatList
        data={messages}
        renderItem={({ item }) => <MessageBubble message={item} />}
      />
      <MessageInput onSend={(content) => sendMessage(id_chat, content)} />
    </View>
  );
}

Types

interface Chat {
  id_chat: string;
  id_tenant: string;
  id_customer: string;
  created_at?: string;
  updated_at?: string;
  customer_name?: string;
  last_message?: string | null;
  last_message_time?: string | null;
  unread_count?: number;
}

interface ChatMessage {
  id_chat_message: number;
  id_chat: string;
  sender: string;
  id_sender: string;
  read: boolean;
  content: string;
  created_at?: string;
}

Configuration

SDKConfig

interface SDKConfig {
  publicKey: string; // Public key (required)
  customerReference: string; // Unique customer ID (required)
  customerName: string; // Customer name (required)
  phone?: string; // Customer phone (optional)
  email?: string; // Customer email (optional)
  avatar?: string; // Customer avatar URL (optional)
  metadata?: Record<string, any>; // Additional customer metadata (optional)
  apiUrl?: string; // API URL (optional, overrides build default)
  wsUrl?: string; // WebSocket URL (optional, overrides build default)
}

Authentication Flow

The SDK automatically:

  1. Authenticates when the provider is executed (calls /auth/customer)
  2. Stores the token in memory (no persistent storage)
  3. Refreshes the token automatically when it expires
  4. Queues failed requests during token refresh and retries them after refresh

Edge Cases and Behaviors

Limits and Validations

  • Maximum message size: 1000 characters
  • Maximum request queue size: 50 requests
  • Queue timeout: 30 seconds
  • WebSocket connection timeout: 10 seconds (default)
  • Maximum WebSocket retry attempts: 3 attempts
  • Maximum processed messages in memory: 100 IDs

Automatic Behaviors

  1. WebSocket reconnection: The SDK automatically reconnects if the connection closes unexpectedly (code !== 1000)
  2. Duplicate prevention: Duplicate messages are automatically ignored using a Set of processed IDs
  3. Message validation: All WebSocket messages are validated before being processed
  4. Automatic retry: WebSocket attempts to reconnect up to 3 times with exponential backoff (1s, 2s, 4s, max 10s)
  5. Resource cleanup: All timeouts and listeners are properly cleaned up when components unmount

Error Handling

The SDK classifies errors into specific types:

  • NetworkError: Network connection errors
  • TimeoutError: Request or connection timeouts
  • AuthenticationError: Authentication errors
  • ValidationError: Input validation errors

Multiple Components

You can use useChatsWithWebSocket in multiple components simultaneously:

  • The WebSocket connection is shared between all components
  • A reference counter manages when to connect/disconnect
  • The connection only closes when the last component unsubscribes

Screen Navigation

  • When navigating from the chat list to a specific chat, the WebSocket connection is kept alive
  • When leaving the list screen, the connection closes automatically
  • Messages keep arriving even when not on the list screen (if another component is using it)

Troubleshooting

For common problems and solutions, see TROUBLESHOOTING.md.

License

MIT