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

@nimbusai/webchat-sdk

v1.0.5

Published

Embeddable WebChat SDK with Shadow DOM isolation and WebSocket messaging

Readme

Nimbus WebChat SDK

A modern, embeddable WebChat SDK with Shadow DOM isolation and real-time WebSocket messaging. Built with TypeScript, Tailwind CSS, and Lucide icons.

npm version License: MIT TypeScript 5.7 Tailwind CSS 3.4 Shadow DOM


Screenshots

Full Dashboard View

Theme Variations

Layout Options

File Upload & Media Handling

Features

  • Zero dependencies (except Lucide icons)
  • Fully customizable UI and theming
  • Responsive design with mobile support
  • Shadow DOM isolation prevents CSS conflicts
  • Real-time WebSocket messaging
  • TypeScript support with full type definitions
  • Multiple formats (ESM, CommonJS, UMD)
  • Flexible icons (Lucide icons or custom images)
  • Automatic reconnection with configurable retries
  • Optional message history loading with resume conversation
  • Multiple layouts (floating popup or sidepanel)
  • File upload support with image previews (config-driven)
  • Character limits with counter display
  • Developer-friendly debug mode and logging

Tech Stack

| Technology | Version | Purpose | |---|---|---| | TypeScript | ^5.7.2 | Type-safe development | | Tailwind CSS | ^3.4.17 | Utility-first styling (pre-compiled into Shadow DOM) | | tsup | ^8.3.5 | Bundler (ESM + CJS + IIFE) | | PostCSS | ^8.4.49 | CSS processing | | Autoprefixer | ^10.4.20 | Vendor prefix automation | | Vitest | ^2.1.8 | Unit testing | | Lucide | inline SVGs | Icons (Shadow DOM compatible) |

Installation

npm / yarn / pnpm

npm install @nimbusai/webchat-sdk
# or
yarn add @nimbusai/webchat-sdk
# or
pnpm add @nimbusai/webchat-sdk
import { NimbusChat } from "@nimbusai/webchat-sdk";

const chat = new NimbusChat({
  agent_version_id: "550e8400-e29b-41d4-a716-446655440000",
});

chat.open();

CDN (script tag)

<script src="https://cdn.nimbus.ai/sdk/nimbus-chat.umd.global.js"></script>
<script>
  NimbusChat.init({
    agent_version_id: "550e8400-e29b-41d4-a716-446655440000",
  });
</script>

The CDN bundle exposes a global NimbusChat object with a singleton init() method — safe to call multiple times.

Quick Start

const chat = new NimbusChat({
  agent_version_id: "550e8400-e29b-41d4-a716-446655440000",
  style: { position: "bottom-right" }
});

The widget renders a floating chat bubble in the corner of the page. Click it to open the chat panel. The WebSocket connection is established lazily — only when the user opens the chat for the first time.

API Reference

Initialization

// NPM usage
const chat = new NimbusChat(config);

// CDN usage
const chat = NimbusChat.init(config);

Methods

| Method | Description | |--------|-------------| | chat.open() | Show the chat widget | | chat.close() | Hide the chat widget | | chat.toggle() | Toggle chat widget visibility | | chat.destroy() | Remove the widget from DOM completely |


Configuration Reference

The SDK provides extensive configuration options to customize every aspect of the chat widget. All properties are optional except agent_version_id.

Required Configuration

| Property | Type | Description | |----------|------|-------------| | agent_version_id | string | Required - Your agent ID (UUID) |

Core Settings

| Property | Type | Default | Description | |----------|------|---------|-------------| | dns | string | "api.nimbus.ai/api/v1/webchat" | API endpoint for chat services | | debug | boolean | false | Enable debug logging to console. When true, the widget auto-opens on init. | | allowNewChat | boolean | false | Show "New Chat" button in header |

Style Configuration

Controls layout, dimensions, and visual appearance of the widget:

style: {
  position: "bottom-right",
  width: "380px",             // CSS width string (e.g. "380px", "100%")
  height: "560px",            // CSS height string (window mode only)
  font: '"Inter Variable", sans-serif',  // Global font family override
  background: "#ffffff",      // CSS color or image URL
  mobile: {
    position: "bottom-right", // Override position on mobile devices
    breakpoint: "480px"       // Viewport width to trigger mobile mode
  }
}

| Property | Type | Default | Description | |----------|------|---------|-------------| | style.position | ChatPosition | "bottom-right" | Widget position on page. Options: "bottom-right", "bottom-left", "sidepanel-left", "sidepanel-right" | | style.width | string | "380px" | Chat window width (CSS value) | | style.height | string | "560px" | Chat window height (CSS value, window mode only) | | style.font | string | System font | Global font family override | | style.background | string | "#f3f1ef" | Chat body background (CSS color or image URL) | | style.mobile.position | ChatPosition | Same as style.position | Widget position on mobile devices | | style.mobile.breakpoint | string | undefined | Viewport width breakpoint for mobile mode (e.g. "480px") |

Theme Configuration

Global theme colors used throughout the widget:

theme: {
  primary: "#ffce1c",      // Primary color (buttons, headers, bubbles)
  secondary: "#f3f1ef"     // Secondary color (text, icons on primary bg)
}

Chat Bubble Settings

The floating trigger button that opens/closes the chat:

bubble: {
  position: "bottom-right",
  autoHide: false,           // Hide bubble when chat is open
  icon: {
    img: "message-circle",   // Lucide icon or image URL
    size: { width: 35, height: 35 }
  }
}

| Property | Type | Default | Description | |----------|------|---------|-------------| | position | BubblePosition | "bottom-right" | Bubble position. Options: "bottom-right", "bottom-left" | | autoHide | boolean | false | Hide the bubble when the chat panel is open | | icon | IconConfig \| null | Default Lucide icon | Custom icon for the bubble |

Header Configuration

header: {
  icon: {
    img: "https://example.com/logo.svg",  // Custom image URL or Lucide icon
    size: { width: 125, height: 19 }
  },
  text: {
    value: "Support Chat",
    color: "#1e293b",
    font: "Inter",
  },
  color: {
    primary: "#f3f1ef",    // Header background color
    secondary: "#ffce1c"   // Close button icon color
  }
}

Welcome Message

Shown when chat is empty, automatically hidden after first message:

welcome: {
  display: true,          // Show/hide welcome message
  preTitle: {
    value: "Welcome to :",
    text: { color: "#1e293b", font: "" }
  },
  title: {
    value: " Nimbus Chat!",
    text: { color: "#1e293b", font: "" }
  },
  subtitle: {
    value: "Send a message to start a conversation",
    text: { color: "gray", font: "" }
  }
}

Message Styling

Configure user and bot message bubbles independently:

userMessage: {
  background: "#DCF8C6",
  width: "80%",             // Max width of message bubble (CSS value). Default: "80%"
  text: {
    color: "#111B21",
    font: "",
    size: 13
  },
  icon: {
    img: "user",  // Lucide icon or custom image URL
    size: { width: 20, height: 20 }
  }
}

botMessage: {
  background: "#FFFFFF",
  width: "80%",             // Max width of message bubble (CSS value). Default: "80%"
  text: {
    color: "#111B21",
    font: "",
    size: 13
  },
  icon: {
    img: "bot",  // Lucide icon or custom image URL
    size: { width: 20, height: 20 }
  }
}

Note: Set icon: null to explicitly hide the avatar. Omit icon entirely to use the default.

Input Configuration

input: {
  placeholder: "Ask Nimbus",
  expandable: true,        // Auto-expanding textarea (up to 8 lines)
  text: {
    color: "#1e293b",
    font: "",
  },
  background: {
    primary: "white",      // Input field background
    secondary: "#f3f1ef"   // Container background
  },
  upload: {                // File upload settings (omit or set null to disable)
    maxFileSize: 5242880,  // 5MB in bytes
    errorDisplayDuration: 2000,  // Error message duration (ms)
    allowedFileTypes: [
      "image/jpeg",
      "image/png",
      "image/gif",
      "application/pdf"
    ],
    icon: {
      img: "paperclip",
      size: { width: 20, height: 20 }
    }
  },
  maxCharacters: {         // Character limit with counter
    limit: 10000,          // Maximum characters allowed
    text: {
      color: "gray",
      size: 12
    }
  }
}

Note: File upload is config-driven. Omit the upload property or set it to null to disable file uploads. Provide an upload object to enable the upload button.

Send Button

sendButton: {
  align: false,            // true = input and button on same row
  icon: {
    img: "send",          // Lucide icon or custom image URL
    size: { width: 20, height: 20 }
  }
}

Reconnection Settings

Control automatic reconnection behavior:

reconnect: {
  attempts: 5,      // Maximum reconnection attempts
  timeout: 5000     // Delay between attempts (ms)
}

Wait for Reply Configuration

Control message sending while waiting for bot responses. Works independently from the typing indicator.

waitForReply: {
  timeout: 30000,          // Max wait time (ms) before allowing next message
  firstReply: false        // Wait for bot's first message in new chat
}

Note: Omit waitForReply to disable input blocking entirely.

Typing Indicator Configuration

Show a typing indicator when waiting for bot responses. Independent from waitForReply — you can use either or both.

isTypingIndicator: {
  position: "bottom",
  title: {
    value: "AI Assistant is typing...",
    text: {
      color: "#1e293b",
      font: ""
    }
  }
}

| Property | Type | Default | Description | |----------|------|---------|-------------| | position | "top" \| "bottom" | "top" | Where to display the indicator. Options: "top" (header status area), "bottom" (above input area) | | title.value | string | "AI Assistant is typing..." | Indicator text | | title.text | TextConfig | { color: "#1e293b" } | Text styling |

Note: Omit isTypingIndicator to disable the typing indicator.

Resume Conversation

When provided, enables loading message history on reconnect and shows a "Show More" button to load older messages. Omit or set to null to disable (default). The flow_id is always persisted and reused regardless.

resumeConversation: {
  messagesPerPage: 10,       // Messages loaded per page
  showMore: {
    value: "Show More",
    sticky: true,            // Stick to top of message list
    background: "#FFF4CC",
    text: {
      color: "black",
      size: 13
    },
    icon: {
      img: "chevron-down",
      size: { width: 16, height: 16 }
    }
  }
}

| Field | Type | Default | Description | |-------|------|---------|-------------| | messagesPerPage | number | 10 | Number of messages loaded per page when scrolling history | | showMore.value | string | "Show More" | Button label text | | showMore.sticky | boolean | true | Stick button to top of message list while scrolling | | showMore.background | string | theme secondary | Button background color | | showMore.text | TextConfig | { color: "black", size: 13 } | Button text styling | | showMore.icon | IconConfig | { img: "chevron-down", size: 16x16 } | Button icon |


Icon System

The SDK supports two types of icons throughout all configuration:

Lucide Icons (Recommended)

Text-based icon names that render as inline SVG:

icon: {
  img: "message-circle",
  size: { width: 24, height: 24 },
  color: "#ffffff"
}

Popular Lucide Icons:

  • "message-circle" - Chat bubble
  • "send" - Send arrow
  • "x" - Close/X mark
  • "rotate-cw" - Refresh/new chat
  • "chevron-down" / "chevron-up" - Arrows
  • "user" - User avatar
  • "bot" - Bot avatar
  • "paperclip" - File attachment

Browse all 1000+ Lucide icons →

Custom Images

URL-based custom images:

icon: {
  img: "https://example.com/logo.png",
  size: { width: 32, height: 32 }
  // color is ignored for image URLs
}

Hiding Icons

icon: null  // Explicitly hide the icon
// or
// Omit the icon property entirely to use default

Shared Type Definitions

TextConfig

Used for styling text elements throughout the SDK:

interface TextConfig {
  display?: boolean;  // Show/hide text (not used everywhere)
  value?: string;     // The text content
  color?: string;     // CSS color value
  font?: string;      // Font family override
  size?: number;      // Font size in pixels
}

IconConfig

Used for all icons in the SDK:

interface IconConfig {
  img?: string;    // Lucide icon name or image URL
  size?: {
    width: number;   // Width in pixels
    height: number;  // Height in pixels
  };
  color?: string;  // Icon color (CSS color). Only applies to Lucide icons, ignored for image URLs.
}

ColorPair

Used for primary/secondary color combinations:

interface ColorPair {
  primary?: string;    // Primary color (usually background)
  secondary?: string;  // Secondary color (usually foreground)
}

Complete Configuration Example

const chat = new NimbusChat({
  // Required
  agent_version_id: "550e8400-e29b-41d4-a716-446655440000",

  // Core Settings
  dns: "api.nimbus.ai/api/v1/chat/ws",
  debug: true,
  allowNewChat: true,

  // Theme
  theme: {
    primary: "#ffce1c",
    secondary: "#f3f1ef"
  },

  // Style
  style: {
    position: "bottom-right",
    width: "450px",
    height: "500px",
    font: "",
    background: "#f3f1ef",
    mobile: {
      position: "bottom-right",
      breakpoint: "480px"
    }
  },

  // Chat Bubble
  bubble: {
    position: "bottom-right",
    autoHide: false,
    icon: {
      img: "message-circle",
      size: { width: 35, height: 35 }
    }
  },

  // Header
  header: {
    icon: {
      img: "https://example.com/logo.svg",
      size: { width: 125, height: 19 }
    },
    text: {
      value: "",
      color: "#1e293b",
      font: "",
    },
    color: {
      primary: "#f3f1ef",
      secondary: "#ffce1c"
    }
  },

  // Welcome Message
  welcome: {
    display: true,
    preTitle: {
      value: "Welcome to :",
      text: { color: "#1e293b", font: "" }
    },
    title: {
      value: " Nimbus Chat!",
      text: { color: "#1e293b", font: "" }
    },
    subtitle: {
      value: "Send a message to start a conversation",
      text: { color: "gray", font: "" }
    }
  },

  // Messages
  userMessage: {
    background: "#DCF8C6",
    width: "80%",
    text: { color: "#111B21", font: "", size: 13 },
    icon: {
      img: "user",
      size: { width: 20, height: 20 }
    }
  },

  botMessage: {
    background: "#FFFFFF",
    width: "80%",
    text: { color: "#111B21", font: "", size: 13 },
    icon: {
      img: "bot",
      size: { width: 20, height: 20 }
    }
  },

  // Input Area
  input: {
    placeholder: "Ask Nimbus",
    expandable: true,
    text: {
      color: "#1e293b",
      font: "",
    },
    background: {
      primary: "white",
      secondary: "#f3f1ef"
    },
    maxCharacters: {
      limit: 10000,
      text: {
        color: "gray",
        font: "",
        size: 12
      }
    },
    upload: null
  },

  // Send Button
  sendButton: {
    align: false,
    icon: {
      img: "send",
      size: { width: 20, height: 20 }
    }
  },

  // Reconnection
  reconnect: {
    attempts: 5,
    timeout: 5000
  },

  // Wait for Reply
  waitForReply: {
    timeout: 30000,
    firstReply: false
  },

  // Typing Indicator (independent from waitForReply)
  isTypingIndicator: {
    position: "bottom",
    title: {
      value: "AI Assistant is typing...",
      text: { color: "#1e293b", font: "" }
    }
  },

  // Resume Conversation (omit or set null to disable)
  resumeConversation: {
    messagesPerPage: 10,
    showMore: {
      value: "Show More",
      sticky: true,
      background: "#FFF4CC",
      text: {
        color: "black",
        font: "",
        size: 13
      },
      icon: {
        img: "chevron-down",
        size: { width: 16, height: 16 }
      }
    }
  },
});

Debug Mode

Enable comprehensive logging for development and troubleshooting:

const chat = new NimbusChat({
  agent_version_id: "your-uuid-here",
  debug: true
});

Debug mode provides:

  • WebSocket connection events
  • Message send/receive logs
  • Session state changes
  • Configuration resolution details
  • Error stack traces

Development

Prerequisites

  • Node.js >= 18
  • npm >= 9

Setup

git clone https://github.com/nichemarket/chat-sdk.git
cd chat-sdk
npm install

Scripts

npm run build          # Full build (CSS + TypeScript)
npm run build:css      # Compile Tailwind only
npm run build:ts       # Compile TypeScript only
npm run type-check     # Type-check without emitting
npm run dev            # Watch mode
npm test               # Run tests
npm run test:watch     # Watch mode tests

Testing

The SDK uses Vitest with jsdom for unit testing. Tests cover configuration resolution, validation, core modules, UI utilities, and DOM components.

npm test               # Run all tests
npm run test:watch     # Run in watch mode

Test suite structure:

| File | Covers | |---|---| | tests/types/resolveConfig.test.ts | Config resolution, defaults, overrides, deep merging | | tests/utils/validateConfig.test.ts | Required fields, type validation, nested config validation | | tests/core/EventBus.test.ts | Pub/sub, on/off/once/emit, error isolation, typed events | | tests/core/ChatSession.test.ts | Session ID, messages, history load/merge, dedup, clear | | tests/utils/FileUtils.test.ts | File size formatting, Base64 conversion | | tests/utils/DOMBuilder.test.ts | Element creation, props, chaining, append, conditionals, fragments | | tests/ui/ThemeManager.test.ts | CSS variables, theme colors, backgrounds, fonts, input styles | | tests/utils/IconRenderer.test.ts | Lucide SVG rendering, URL images, unknown icons, wrapper/simple modes |

Common Development Commands

# Clean installation (recommended for troubleshooting)
rm -rf node_modules package-lock.json && npm install && npm run build

# Fast build and serve for testing
npm run build && npx http-server -p 8081 -c-1

Code Standards

Logging: Always use the custom logger instead of console.* statements:

import { createLogger } from './utils/logger';

// For utility files - create logger at top level
const logger = createLogger('ComponentName');

// For classes - create logger in constructor
class MyComponent {
  private logger: Logger;

  constructor(debug = false) {
    this.logger = createLogger('MyComponent', debug);
  }
}

// Usage
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message');

Output Files

| Format | File | Size | |---|---|---| | ESM | dist/index.mjs | ~48 KB | | CJS | dist/index.js | ~49 KB | | IIFE/UMD | dist/nimbus-chat.umd.global.js | ~49 KB | | Types | dist/index.d.ts | ~8.5 KB |

Project Structure

chat-sdk/
├── src/
│   ├── core/              # EventBus, ChatSession, WebSocketManager, ApiClient
│   ├── icons/             # Lucide SVG icon definitions
│   ├── styles/            # Tailwind globals + compiled CSS
│   ├── types/             # TypeScript interfaces (config, message)
│   ├── ui/                # UI components (Header, MessageList, InputArea, etc.)
│   ├── utils/             # Utilities (logger, validator, parser, etc.)
│   ├── NimbusChat.ts      # Main SDK orchestrator
│   └── index.ts           # Public exports
├── examples/
│   ├── cdn-usage.html         # CDN integration example (full config)
│   ├── cdn-usage-basic.html   # CDN integration example (minimal config)
│   └── cdn-usage-black.html   # CDN integration example (dark theme)
├── dist/                  # Build output
├── tsconfig.json
├── tsup.config.js
├── tailwind.config.js
├── postcss.config.js
└── package.json

Architecture

The SDK uses Shadow DOM (open mode) to fully isolate styles from the host page. Tailwind CSS is pre-compiled at build time and injected into the shadow root at runtime alongside CSS custom properties for theming.

Component Architecture

NimbusChat (orchestrator)
├── EventBus (pub/sub messaging)
├── ChatSession (message state + history)
├── WebSocketManager (connection lifecycle)
├── ApiClient (REST API)
└── UI Components
    ├── ShadowContainer (DOM isolation)
    ├── ThemeManager (CSS custom properties)
    ├── ChatWindow/SidepanelWindow (containers)
    ├── Header
    ├── MessageList
    ├── InputArea (with FileUpload)
    ├── MessageBubble
    └── ChatBubble (floating trigger)

Connection Lifecycle

  1. Initial Connection: Client opens WebSocket with agent_version_id (and flow_id if available from localStorage)
  2. Connected: Server responds with { "type": "connected", "flow_id": "uuid" }
  3. Persistence: flow_id is always stored in localStorage and reused on reconnect
  4. History Loading: If resumeConversation is configured (not null), fetches message history via REST API after connection
  5. Messaging: Simple message exchange with direction: "inbound" (user) and direction: "outbound" (bot)

WebSocket Events

Incoming:

  • connected - Connection established, provides flow_id
  • message - New message from server (direction: "outbound")

Outgoing:

  • message - User message (direction: "inbound")

Message Schema

// User message (sent to server)
{ "type": "message", "direction": "inbound", "content": "Hello!" }

// Bot message (received from server)
{ "type": "message", "direction": "outbound", "content": "Hi there!" }

// Connected event (received from server)
{ "type": "connected", "flow_id": "550e8400-e29b-41d4-a716-446655440000" }

License

MIT