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

@netwatchai/chat

v0.42.0

Published

Embeddable AI chat widget for Netwatch monitoring

Readme

Netwatch Widget

Quark, Netwatch's AI monitoring assistant, shipped as a self-contained Web Component (Shadow DOM — styles are fully isolated from the host page). Drop in one script tag to add a chat bubble to any page.

Published to npm as @netwatchai/chat and served over jsDelivr:

https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js

(Pin a version with @0.1.0 instead of @latest for stability.)

Features

  • 💬 Real-time streaming chat interface
  • 📱 Fully responsive and embeddable
  • 🎨 Tailwind CSS styling with complete style isolation
  • 🔄 Web Component with Shadow DOM
  • ↔️ Resizable and expandable interface
  • 🌙 Dark mode support
  • 📦 Distributable via CDN

Embedding

Two equivalent ways — both load the single bundle from jsDelivr.

1. Declarative (custom element)

<script type="module"
  src="https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js"></script>

<netwatch-widget
  client-id="b48ea317-…"
  api-endpoint="http://your-api:8000">
</netwatch-widget>

2. Programmatic (one-liner — PHP / CMS friendly)

<script type="module">
  import NetwatchChat from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";
  NetwatchChat.initBubble({
    clientId: "b48ea317-…",
    apiHost:  "http://your-api:8000",
  });
</script>

Options

| Attribute | initBubble key | Required | Notes | |----------------|-----------------------|----------|-------| | client-id | clientId | yes | Netwatch client UUID | | api-endpoint | apiHost / apiEndpoint | yes | API base URL (a trailing /api/chat is stripped automatically) | | username | username | no | Auto-resolved from the host page's localStorage when embedded in the Netwatch UI. Pass explicitly to override, or when embedding on other hosts. | | stall-timeout-ms | stallTimeoutMs | no | Progress-watchdog window (default 90000; 0 disables). A reply with no stream frame for this long is re-sent once, then shown as failed with a Retry button. Widen for a slow model; the stub-server harness (scripts/chat_stall_stub.py) shrinks it. |

Embedding in the Netwatch monitoring UI

The widget auto-reads the logged-in user from the host page's localStorage, so it only needs its script injected on every (logged-in) page. The UI has no built-in custom-JS setting, so use one of:

Option A — reverse proxy injection (recommended, survives upgrades). With nginx in front of the frontend:

location / {
    proxy_pass http://frontend-upstream;
    proxy_set_header Accept-Encoding "";   # sub_filter needs uncompressed HTML
    sub_filter_once on;
    sub_filter_types text/html;
    sub_filter '</body>'
      '<script type="module">import N from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";N.initBubble({clientId:"b48ea317-…",apiHost:"http://your-api:8000"});</script></body>';
}

Option B — edit the frontend's page layout template (ui/include/views/layout.htmlpage.php), just before the </body> output. ⚠️ This is overwritten on every upgrade, so reapply it after upgrading:

echo '<script type="module">import N from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";N.initBubble({clientId:"b48ea317-…",apiHost:"http://your-api:8000"});</script>';

⚠️ Mixed content: if the UI is served over HTTPS but api-endpoint is http://…, browsers silently block the API calls. Serve the API over HTTPS too, or keep both on plain HTTP within a private network/tunnel.

Development

pnpm install

# Copy the env template and fill it in.
cp .env.example .env

Edit .env:

VITE_API_ENDPOINT=http://localhost:8000
VITE_DEV_CLIENT_ID=your-client-uuid
VITE_DEV_USERNAME=your-netwatch-username

Both .env and .env.local are gitignored; only .env.example is committed.

Start the dev server:

pnpm run dev

Visit http://localhost:5173 for the test page; it reads the env vars via src/config.js and mounts the widget automatically.

Build

pnpm run build

Outputs to lib/ (the @latest/lib/web.min.js jsDelivr path):

  • lib/web.min.js — ES module (modern <script type="module"> / npm import)
  • lib/web.umd.js — UMD build (legacy <script> tag → window.NetwatchChat)

Publishing / Deploying

Published to npm as @netwatchai/chat by .github/workflows/widget-publish.yml, triggered by pushing a widget-v* git tag. The version is taken from the tag, so a release never commits back to the protected main branch and needs no privileged token — just NPM_TOKEN. Consumers pick it up via jsDelivr at https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js.

Quick path: bump the version (changesets, below) and commit, then run pnpm run release:tag from widget/ — it validates, builds, tags, pushes, and watches the publish run. Full reference: docs/widget-release.md.

Release steps

  1. Bump the version on main via a normal PR. Easiest is to consume any changesets into package.json + CHANGELOG.md:

    cd frontend/widget
    pnpm changeset             # (optional) describe the change → feeds CHANGELOG
    pnpm run version-packages  # bumps package.json + CHANGELOG, consumes changesets

    Keep changeset summaries in Netwatch terms — they become the public CHANGELOG.md. Commit, open a PR, and merge it to main.

  2. Tag the merge commit and push the tag (must match package.json):

    git fetch origin
    git tag widget-v0.6.0 origin/main      # widget-v<version>
    git push origin widget-v0.6.0
  3. The workflow fires on the tag: it sets package.json to the tag's version, builds, and runs npm publish. It fails loudly if that version is already on npm (bump and re-tag) or if the tag isn't widget-v<semver>.

Why tags, not push-to-main? The org ruleset requires PRs on main and blocks the Actions bot from pushing — so a CI-driven version-bump commit can't land. Pushing a tag sidesteps the protected branch entirely. (The earlier auto-on-merge workflow failed silently for exactly this reason.)

Requires repo secret NPM_TOKEN — a granular npm token with "Bypass two-factor authentication (2FA)" checked and read/write on the @netwatchai scope (a token without the 2FA bypass fails publish with EOTP).

What a release looks like (the 0.7.0 example)

The exact sequence used to cut @netwatchai/[email protected] (pnpm commands from widget/, git from anywhere in the repo):

# 1. Describe the change (feeds CHANGELOG); pick patch / minor / major.
pnpm changeset                         # or hand-write .changeset/<slug>.md

# 2. Roll pending changesets into the version + CHANGELOG.
pnpm run version-packages              # e.g. 0.6.0 → 0.7.0, deletes the changeset

# 3. Commit the bump and push the branch.
git commit -am "chore(widget): release 0.7.0 (SLA settings UI)"
git push origin <branch>

# 4. Tag that commit and push the tag — pushing the tag is what publishes.
git tag widget-v0.7.0
git push origin widget-v0.7.0          # → fires .github/workflows/widget-publish.yml

The tag may point at any commit, not just main: CI checks out the tagged commit, sets package.json to the tag's version, builds, and publishes. 0.7.0 was cut from a feature branch this way — shipping the widget ahead of merging its backend PR. Prefer tagging main for normal releases.

Verify the publish

gh run watch --exit-status          # follow the "Widget publish" run to green
npm view @netwatchai/chat version   # → 0.7.0

Live within a few minutes via jsDelivr at https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js (@latest resolves to the new version; pin @0.7.0 to be explicit).

Architecture

  • Web Components — native browser API for encapsulation
  • Shadow DOM — complete style isolation from the parent page
  • React — internal rendering framework
  • Vercel AI SDK — streaming chat interface
  • Tailwind CSS — utility-first styling
  • Streamdown — markdown rendering

License

MIT