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

@velnai/chat-react

v0.1.1

Published

Drop the Velnai web-chat widget into any React app. Provider + hook around the existing iframe loader.

Downloads

228

Readme

@velnai/chat-react

Drop the Velnai web-chat widget into any React app.

npm install @velnai/chat-react

Usage

Mount the Provider once at your app root:

import { VelnaiChatProvider } from '@velnai/chat-react'

export default function RootLayout({ children }) {
  return (
    <VelnaiChatProvider
      publicKey="wac_xxx"
      visitorAttrs={{ email: user.email, plan: user.plan }}
      onReady={() => console.log('chat ready')}
    >
      {children}
    </VelnaiChatProvider>
  )
}

The bubble appears in the corner of every page automatically.

Control the widget from anywhere via the hook:

import { useVelnaiChat } from '@velnai/chat-react'

function LogoutButton() {
  const { reset } = useVelnaiChat()
  return <button onClick={reset}>Log out</button>
}

function OpenChatButton() {
  const { open } = useVelnaiChat()
  return <button onClick={open}>Need help?</button>
}

Props

| Prop | Type | What it does | |---|---|---| | publicKey | string | The agent's public key (wac_xxx). | | visitorAttrs | Record<string, string \| number \| boolean \| null> | Visitor identity — max 16 keys. Re-applied on prop change. | | widgetBase | string | Override the widget host. Default https://widget.velnai.com. | | onReady | () => void | Fires once the bubble has loaded. | | onOpen | () => void | Fires when the visitor opens the panel. | | onClose | () => void | Fires when the visitor closes the panel. |

Hook API

useVelnaiChat() returns:

| Method | Behavior | |---|---| | identify(attrs) | Merge visitor attributes mid-session. | | reset() | Clear all visitor attributes (e.g. after logout). | | getAttrs() | Snapshot of current attributes. | | open() | Programmatically expand the panel. | | close() | Programmatically collapse to the bubble. |

How it works

The Provider injects the official widget boot script (https://widget.velnai.com/widget/boot.js) on mount. The boot script creates a sandboxed iframe in the corner of the page — same iframe every visitor sees, same renderer as the script-tag embed. The Provider just wires React props and hook callbacks into the existing postMessage channel.

Mount the Provider once. The boot script is injected once per page; mounting two Providers on the same page is harmless (script-tag guard) but you only get one widget instance regardless.

Why iframe instead of a native React port?

The widget has 30+ features (signature, file upload, voice messages, RTC voice calls, ticket forms, conditional logic, theming) that would need to be re-implemented and kept in sync if we shipped a native renderer. iframe means new features land in your app the day they ship on the web — zero work on your side.

License

MIT