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

ajaxter-chat

v3.2.0

Published

Drawer/popup/inline chat widget with real-time Socket.IO, WebRTC calling, voice messages, tickets, and display-mode config from server.

Readme

ajaxter-chat

A production-ready drawer/slider-based chat widget for React.js and Next.js (App Router and Pages Router). All configuration is loaded remotely from your hosted chatData.json.

| Audience | Where to start | |----------|----------------| | Frontend (React / Next.js embed) | This file — install, env vars, chatData.json, and usage below. | | Backend (APIs, WebSockets, auth, payloads) | BACKEND.mdChatMessage, tickets, presence, viewer blocked, WebRTC signalling, and recommended REST/socket shapes. |


Install

npm install ajaxter-chat

Peer dependencies: React ≥ 17 and react-dom.


Environment variables (2 only)

Create React App / Vite (.env)

REACT_APP_CHAT_API_KEY=demo1234
REACT_APP_CHAT_WIDGET_ID=demo

Next.js (.env.local)

NEXT_PUBLIC_CHAT_API_KEY=demo1234
NEXT_PUBLIC_CHAT_WIDGET_ID=demo

Remote config URL

The widget fetches config from:

GET https://window.mscorpres.com/TEST/chatData.json

With headers:

X-Chat-Api-Key:   demo1234
X-Chat-Widget-Id: demo

Optional widget flags for spam-blocked viewers (see BACKEND.md): widget.viewerBlocked, or per-user viewerBlocked on the matching users / developers row for the logged-in uid, plus blockedViewerMessage, reenableRequestUrl.

Browser permissions: On first use (per tab), the widget asks for microphone, location, and screen capture (for voice, calls, and verification). If anything is denied, access is blocked until the user fixes site permissions and taps Try again. Successful grants are remembered for the session. Use HTTPS so geolocation works.

Presence (ACTIVE / AWAY / DND): Set widget.presenceUpdateUrl to your API; each change sends POST JSON { widgetId, apiKey, viewerUid?, status } for DB storage. Include widget.presenceStatus in chatData.json (from your DB) so the UI matches the server after reload.

chatData.json schema

Host this file at the URL above:

{
  "widget": {
    "id": "demo",
    "apiKey": "demo1234",
    "status": "ACTIVE",
    "chatType": "BOTH",
    "primaryColor": "#2563EB",
    "buttonLabel": "Support",
    "buttonPosition": "bottom-right",
    "welcomeTitle": "Hi there 👋",
    "welcomeSubtitle": "Need help? Start a conversation:",
    "allowVoiceMessage": true,
    "allowAttachment": true,
    "allowEmoji": true,
    "allowWebCall": true,
    "maxEmojiCount": 20,
    "allowTranscriptDownload": true,
    "allowReport": true,
    "allowBlock": true
  },
  "developers": [ { "uid":"dev_001","name":"...","type":"developer","status":"online", ... } ],
  "users":      [ { "uid":"usr_001","name":"...","type":"user","status":"online", ... }      ],
  "sampleChats":   { "dev_001": [ { "id":"msg_001","senderId":"me","text":"Hi!","type":"text", ... } ] },
  "sampleTickets": [ { "id":"TKT-0001","title":"...","status":"open","priority":"high", ... } ],
  "blockedUsers":  []
}

Usage

React.js (CRA, Vite, or any React app)

import { ChatWidget } from 'ajaxter-chat';
import type { ChatWidgetViewer } from 'ajaxter-chat';

const viewer: ChatWidgetViewer = {
  uid: 'usr_001',
  name: 'Ravi Kumar',
  type: 'user', // or 'developer' — controls Support vs staff UI
  projectId: 'Client Portal', // optional; exact match to `project` in chatData users
};

export default function App() {
  return (
    <>
      <main>App</main>
      <ChatWidget viewer={viewer} />
    </>
  );
}

Omit viewer to rely on viewerUid / viewerType from remote chatData.json only.

Next.js — App Router

ChatWidget uses browser APIs; import it only from a Client Component ('use client').

// app/ChatWidgetWrapper.tsx
'use client';

import { ChatWidget } from 'ajaxter-chat';

export function ChatWidgetWrapper() {
  return <ChatWidget />;
}
// app/layout.tsx
import { ChatWidgetWrapper } from './ChatWidgetWrapper';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <ChatWidgetWrapper />
      </body>
    </html>
  );
}

Next.js — Pages Router

// pages/_app.tsx
import type { AppProps } from 'next/app';
import { ChatWidget } from 'ajaxter-chat';

export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <ChatWidget />
    </>
  );
}

A minimal App Router proxy route example lives at examples/next-app-router-chat-proxy.ts (optional pattern for server-side forwarding).


Features

| Feature | Details | |---|---| | Drawer/Slider UI | Slides in from right (or left) with smooth animation. | | Home Screen | "Hi there 👋" hero, cards for Support / New Conversation / Raise Ticket | | User List | Slide-in panel with online status dot, designation, project | | Chat Screen | Matches the UI image — hamburger back, title "Support", phone + fullscreen icons | | Enter Your Details | Blue card at top of chat (ticket chat body placeholder) | | Voice Messages | Record via MediaRecorder API, shows duration | | Attachments | File picker, shows filename + size as message | | Emoji Picker | 20 curated emojis, limited count via maxEmojiCount | | Pause Chat | Developer can pause — user cannot send messages | | Resume Chat | One-click resume from banner or menu | | Report Chat | Flags chat, shows warning banner | | Block User | Blocks users only (not developers), with confirm dialog | | Block List Tab | View all blocked users, one-click unblock | | Download Transcript | Saves plain-text .txt file of full conversation | | WebRTC Calls | Secure P2P voice/video call with mute + camera toggle | | Ticket Screen | Raise tickets with title, description, priority selector | | Ticket History | Shows all tickets with status badge and priority color | | Recent Chats Tab | Shows past conversations with unread badges | | Responsive width | ~30% width on desktop; full width on small screens | | Slide Close | Smooth slide-out animation on close | | SSR Safe | isMounted guard, works in Next.js App Router and Pages Router | | CHAT_STATUS | ACTIVE / DISABLE / MAINTENANCE handled |


WebSocket integration points

In src/hooks/useChat.ts — find the // TODO: comments:

// In selectUser:
// socket.emit('join', { roomId: user.uid });
// socket.on('message', msg => setMessages(prev => [...prev, msg]));

// In sendMessage:
// socket.emit('message', msg);

In src/hooks/useWebRTC.ts — find the // TODO: comments:

// ICE candidate: socket.emit('ice-candidate', { candidate, to: peer.uid });
// Offer:         socket.emit('call-offer', { offer, to: peer.uid });
// Answer:        socket.emit('call-answer', { answer, to: peer.uid });

Full event naming and payloads for backend teams are in BACKEND.md.


Package layout (source)

src/
├── index.ts
├── types/index.ts
├── config/index.ts              ← reads CHAT_API_KEY + CHAT_WIDGET_ID, fetches chatData.json
├── utils/theme.ts
├── utils/chat.ts                ← transcript, avatarColor, formatTime, downloadText
├── hooks/
│   ├── useRemoteConfig.ts       ← fetches chatData.json
│   ├── useChat.ts               ← messages, pause, report
│   └── useWebRTC.ts             ← P2P WebRTC calling
└── components/
    ├── ChatWidget.tsx            ← Root drawer orchestrator
    ├── HomeScreen/
    ├── UserListScreen/
    ├── ChatScreen/               ← voice, attach, emoji, pause, report, block, transcript, call
    ├── CallScreen/               ← WebRTC video/audio UI
    ├── EmojiPicker/
    ├── TicketScreen/
    ├── RecentChatsScreen/
    ├── BlockList/
    ├── MaintenanceView/
    └── Tabs/BottomTabs.tsx       ← Home / Chats / Tickets / Blocked

public/
└── chatData.json                 ← Sample JSON — host at window.mscorpres.com/TEST/chatData.json