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

@bnagaraju7/chat-widget

v0.1.0

Published

GarudaVPN support chat widget — embeddable via npm (React) or a CDN <script> bundle.

Readme

@bnagaraju7/chat-widget

The GarudaVPN support chat widget — AI chatbot, voice call + OTP, and browser speech-to-text input — packaged for reuse outside the main Next.js app:

  • as an npm package for other React apps
  • as a CDN <script> bundle for any third-party website

Everything talks to your backend over plain REST (apiBaseUrl) — there is no Supabase or any other direct database dependency in this package.

Published under the @bnagaraju7 npm scope. Forking this for your own org? Change name in package.json to your own scope (@your-npm-username/chat-widget) or an unscoped name (garuda-chat-widget) before running npm publish.

Scope

This package is intentionally smaller than the chat experience inside the main app. It covers:

  • AI chatbot (text chat via POST {apiBaseUrl}/api/v1/agents/chat)
  • Voice call + OTP verification (via {apiBaseUrl}/api/v1/call/*, Twilio Voice SDK)
  • Browser speech-to-text input (Web Speech API)
  • End-of-chat resolution/rating flow (via POST {apiBaseUrl}/api/v1/ratings/respond)

It does not include session history, human-agent live handoff, or edited-message display — those depended on the main app's direct browser-to-Supabase access, which this package doesn't have. If you need them here, your backend would need to expose REST endpoints for sessions/messages/agent-routing/agent-messages (with polling in place of Supabase Realtime).

Build

cd chat
npm install
npm run build

Produces:

  • dist/index.mjs, dist/index.cjs, dist/index.d.ts — the npm package
  • dist/cdn/garuda-chat-widget.iife.global.js — the CDN bundle (React/ReactDOM included)

Usage — CDN

<script
  src="https://cdn.example.com/garuda-chat-widget.iife.global.js"
  data-api-base-url="https://api.example.com"
  data-organisation-id="your-org-id"
  data-support-phone="+1 555 0100"
  async
></script>

The script auto-mounts using the data-* attributes on its own <script> tag. For full control (custom user, authToken, callbacks, or a dynamic SPA re-init), call init yourself instead of relying on auto-mount:

<script src="https://cdn.example.com/garuda-chat-widget.iife.global.js"></script>
<script>
  window.GarudaChat.init({
    apiBaseUrl: "https://api.example.com",
    organisationId: "your-org-id",
    supportPhone: "+1 555 0100",
  });
</script>

Usage — npm

npm install @bnagaraju7/chat-widget
import { GarudaChatWidget } from "@bnagaraju7/chat-widget";

<GarudaChatWidget
  config={{
    apiBaseUrl: "https://api.example.com",
    organisationId: "your-org-id",
    supportPhone: "+1 555 0100",
  }}
/>;

react and react-dom are peer dependencies (>=18), so consumer apps don't end up with a duplicate React copy. The package ships a "use client" banner, so it works as-is in a React Server Components tree too (see Next.js below) — no extra client wrapper needed.

Usage — Next.js

Works with both the App Router and the Pages Router.

App Router — the component can be imported directly into a Server Component; it renders itself on the client because the bundle already carries "use client":

// app/layout.tsx
import { GarudaChatWidget } from "@bnagaraju7/chat-widget";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <GarudaChatWidget
          config={{
            apiBaseUrl: process.env.NEXT_PUBLIC_CHAT_API_BASE_URL!,
            organisationId: process.env.NEXT_PUBLIC_CHAT_ORG_ID,
            supportPhone: "+1 555 0100",
          }}
        />
      </body>
    </html>
  );
}

Pages Router — mount it once in _app.tsx:

// pages/_app.tsx
import type { AppProps } from "next/app";
import { GarudaChatWidget } from "@bnagaraju7/chat-widget";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <GarudaChatWidget
        config={{ apiBaseUrl: process.env.NEXT_PUBLIC_CHAT_API_BASE_URL! }}
      />
    </>
  );
}

Use NEXT_PUBLIC_* env vars for any config value needed in the browser — plain (non-NEXT_PUBLIC_) env vars aren't available client-side.

Usage — Odoo 19

Odoo isn't React-based, so integrate via the CDN <script> bundle (self-contained, includes React) rather than the npm package.

Host dist/cdn/garuda-chat-widget.iife.global.js somewhere Odoo can reach it (your own static hosting, or as a public asset in a custom module) and add the <script> tag using one of:

  • Website Builder, no custom module — Website ‣ Configuration ‣ Settings ‣ SEO section has a "Custom Code" / head-and-body-script field (or Website ‣ Site ‣ Settings ‣ Tracking Codes on some builds) — paste the snippet into the "Body" custom code box so it loads on every page:

    <script
      src="https://your-static-host.example.com/garuda-chat-widget.iife.global.js"
      data-api-base-url="https://api.example.com"
      data-organisation-id="your-org-id"
      data-support-phone="+1 555 0100"
      async
    ></script>
  • Custom module — bundle the JS file under your_module/static/src/js/ and add it to the website's assets bundle in __manifest__.py:

    "assets": {
        "web.assets_frontend": [
            "your_module/static/src/js/garuda-chat-widget.iife.global.js",
        ],
    },

    then set the config once from a small QWeb-injected script (e.g. in a website.layout inherited template) instead of data-* attributes:

    <xpath expr="//body" position="inside">
      <script t-if="request.website">
        window.GarudaChat &amp;&amp; window.GarudaChat.init({
          apiBaseUrl: "https://api.example.com",
          organisationId: "your-org-id",
        });
      </script>
    </xpath>

Either way, make sure the backend behind apiBaseUrl has CORS enabled for your Odoo site's domain (see "Backend prerequisite" below).

Config reference

| Field | Required | Description | | ---------------------------- | -------- | ----------------------------------------------------------------------------- | | apiBaseUrl | yes | Base URL of the support/chat REST API. | | organisationId | no | Sent as the organisation_id header on every REST request. | | supportPhone | no | Phone number for the voice-call fallback. Omit to hide the call button. | | user | no | { id, fullname?, email? } — used for the welcome message and rating submission. | | authToken | no | Bearer token for REST requests. Omit for guest (unauthenticated) mode. | | onNavigateToKnowledgeBase | no | Called when a user clicks a knowledge-base article result. | | onUnauthorized | no | Called on a 401 from an authenticated request. |

Backend prerequisite

The backend behind apiBaseUrl (chat, voice token, OTP, ratings endpoints) needs CORS enabled for cross-origin requests from whatever domains will embed the widget.

Example

example/cdn-demo.html loads the built IIFE bundle with placeholder config for manual smoke-testing — see that file for how to serve it locally.