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

@zoomrx/zena-chatbot-client

v1.0.2

Published

Zena AI chatbot web component for ZoomRx applications

Readme

Zena Chatbot

@zoomrx/zena-chatbot-client is a standalone web component (<zena-chatbot>) built with Svelte 5 and bundled via Vite into a single IIFE file. It is embedded inside host applications as a script tag — no framework dependency required on the host side.

Quick start

npm install
npm run dev    # dev server at http://localhost:5173

Requires Node.js 24 or newer. Use nvm use --lts if you manage multiple runtimes.

Installation

npm install @zoomrx/zena-chatbot-client

Tech stack

  • Framework: Svelte 5 (runes: $state, $derived, $effect, $props)
  • Build tool: Vite 8 (outputs ES module + IIFE)
  • Styles: Tailwind CSS 4
  • HTTP: ky with a memoized instance factory
  • Testing: Vitest + @testing-library/svelte + MSW
  • Error tracking: Sentry (@sentry/browser)
  • Analytics: PostHog
  • E2E: Playwright

Scripts

| Command | Purpose | |---|---| | npm run dev | Dev server at http://localhost:5173 with MSW + PostHog stub | | npm run build | Production IIFE + ES module in dist/ | | npm run preview | Serve the production build locally | | npm test -- --run | Run all unit tests once | | npm run test:coverage | Coverage report | | node e2e-test.cjs | Playwright E2E test against localhost:5173 |


Web Component API

Usage

The recommended approach is to pass all configuration via get-config — one event, one place.

<script src="path/to/zena-chatbot-client.iife.js"></script>

<zena-chatbot></zena-chatbot>

<script>
  const chatbot = document.querySelector('zena-chatbot');

  // All config — URLs, user ID, tokens, analytics keys — resolved in one place.
  chatbot.on('get-config', ({ resolve }) => {
    resolve({
      authToken: 'Bearer eyJ...',         // required
      zenaServerUrl: 'https://your-zena-api.com',
      panelistServerUrl: 'https://your-panelist-server.com',
      userId: '12345',
      availableSurveyIds: '[1, 2, 3]',
      nativeApp: false,
      fabStyle: { bottom: '20px', right: '20px' },
      fabShape: 'circle',
      autoSuggestions: ["I'm stuck in the survey"],
      posthogKey: 'phc_xxx',
      posthogHost: 'https://app.posthog.com',
      sentryDsn: 'https://[email protected]/123',
      sentryRelease: '[email protected]', // optional
    });
  });
</script>

HTML attributes are also supported as a fallback (e.g. for static HTML pages), but get-config values take precedence when both are provided.

HTML Attributes (fallback)

All of these can alternatively be passed via get-config (see Events below). When both are provided, get-config wins.

| Attribute | Type | Required | Default | Description | |---|---|---|---|---| | zena-server-url | string | Yes* | — | Base URL for the Zena API | | user-id | string | No | '' | User identifier passed to analytics | | available-survey-ids | string (JSON array) | No | '[]' | Array of IDs (or objects with survey_id) currently on the user's dashboard | | panelist-server-url | string | No | '' | Base URL for the panelist server (survey fetching) | | native-app | boolean (presence) | No | false | Set to enable native app mode | | fab-style | string (JSON object) | No | {} | CSS properties for FAB position/size (e.g. {"bottom":"20px","right":"20px"}) | | fab-shape | string | No | 'circle' | 'circle' or 'rectangle' | | auto-suggestions | string (JSON array) | No | [] | Priority suggestions prepended to defaults |

*Not required if zenaServerUrl is passed via get-config.

Methods

| Method | Returns | Description | |---|---|---| | close() | void | Programmatically close the chat panel | | generateConversationSummary() | string | Returns last user + bot message as plain text (useful for support ticket context) | | setFabStyle(style) | void | Update FAB position/style without remounting — preserves chat state | | on(event, handler) | void | Subscribe to a component event | | off(event, handler) | void | Unsubscribe from a component event |

Events

| Event | Payload | Description | |---|---|---| | get-config | { resolve } | Fired once on init. Call resolve(config) to provide sensitive credentials. See below. | | before-send | { message, resolve } | Fired before each message is sent. Call resolve(data) with any extra data to merge into the request. | | stuck-survey-selected | { survey } | Fire-and-forget. Fired when the user selects a survey from a stuck-survey dropdown, before the support ticket is created. |

get-config

Fired once when the component connects. The host must call resolve with a ZenaChatbotConfig object. If the host does not handle the event within 2 seconds the component mounts with an empty auth token (API calls will fail).

chatbot.on('get-config', ({ resolve }) => {
  resolve({
    // Credentials (required / recommended)
    authToken: 'Bearer eyJ...',             // required
    sentryDsn: 'https://...',               // optional — omit to disable Sentry
    sentryRelease: '1.0.0',                 // optional — defaults to package version
    posthogKey: 'phc_xxx',                  // optional — omit to disable analytics
    posthogHost: 'https://app.posthog.com', // optional

    // Component config (can also be set via HTML attributes as fallback)
    zenaServerUrl: 'https://your-zena-api.com',        // required
    panelistServerUrl: 'https://your-panelist.com',    // optional
    userId: '12345',                                   // optional
    availableSurveyIds: '[1, 2, 3]',                   // optional
    nativeApp: false,                                  // optional
    fabStyle: { bottom: '20px', right: '20px' },       // optional
    fabShape: 'circle',                                // optional — 'circle' | 'rectangle'
    autoSuggestions: ["I'm stuck in the survey"],      // optional
    defaultOpen: false,                                // optional — open panel on mount
    initialMessage: {                                  // optional — hidden trigger sent to server;
      type: 'assistant',                               //   only the assistant response is shown.
      text: 'Hello! How can I help?',                  //   Skipped on page reload automatically.
    },
  });
});

before-send

chatbot.on('before-send', ({ message, resolve }) => {
  resolve({ userId: 42, sessionToken: 'abc' });
});

stuck-survey-selected

Fired when the user picks a survey from a stuck_survey_dropdown response. Fires before the support-ticket API call — the host receives it even if ticket creation subsequently fails.

chatbot.on('stuck-survey-selected', ({ survey }) => {
  // survey — the selected survey object { name, survey_id, wave_id, users_wave_id, ... }
  console.log('User is stuck in survey:', survey.name);
});

Sentry Error Tracking

The package ships with Sentry support but does not auto-initialize it. Provide sentryDsn via the get-config event — the component initialises Sentry after credentials are resolved:

chatbot.on('get-config', ({ resolve }) => {
  resolve({
    authToken: '...',
    sentryDsn: 'https://[email protected]/XXXXXX',
    sentryRelease: '[email protected]', // optional
  });
});
  • sentryRelease is optional. When omitted it defaults to zena-chatbot-client@<package version> and must match the release name used when uploading sourcemaps in CI (sentry-cli sourcemaps upload).
  • Omit sentryDsn from the resolved config in local / UAT environments and Sentry will never initialise.
  • tracesSampleRate is always 0 — errors only, no performance tracing overhead.

Capturing errors manually

captureError is the only Sentry helper exported from the package:

import { captureError } from '@zoomrx/zena-chatbot-client';

try {
  // ...
} catch (err) {
  captureError(err);
}

For contribution guidelines, staging workflow, and publishing instructions see CONTRIBUTING.md.