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

@apteva/ui

v0.1.1

Published

Generic React UI components for Apteva applications, starting with a production-ready agent chat surface.

Readme

@apteva/ui

Generic React components for Apteva applications. The first surface is a complete agent chat UI backed by @apteva/web-sdk.

The package is intentionally independent from the Apteva dashboard and its internal @apteva/ui-kit. It has scoped CSS, works in ordinary React sites, and exposes both a ready-made component and a headless hook.

Install

bun add @apteva/web-sdk @apteva/ui

Ready-made chat

import { AptevaClient } from "@apteva/web-sdk";
import { AptevaChat } from "@apteva/ui/chat";
import "@apteva/ui/styles.css";

const client = new AptevaClient({
  baseURL: "https://agents.example.com",
  // Prefer a logged-in session cookie in browser applications.
});

export function SupportChat() {
  return (
    <AptevaChat
      client={client}
      agentId={42}
      heading="Support"
      description="Usually replies in a few seconds"
      placeholder="How can we help?"
    />
  );
}

AptevaChat resumes the agent's most recently updated conversation. If none exists, it creates one. Pass conversationId to open a specific conversation or createIfMissing={false} to prevent automatic creation.

Image attachments are enabled by default. Users can choose, paste, or drag up to four PNG, JPEG, WebP, or GIF images into the unified composer, preview and remove them before sending, and reopen durable images from chat history. Set allowImageAttachments={false} to keep a text-only composer.

Provider

For an application with several Apteva surfaces, provide the client once:

import { AptevaProvider } from "@apteva/ui";
import { AptevaChat } from "@apteva/ui/chat";

<AptevaProvider client={client}>
  <AptevaChat agentId={42} />
</AptevaProvider>

Headless chat

useAptevaChat provides the same conversation resolution, history merge, live stream, and send behavior without imposing markup:

import { useAptevaChat } from "@apteva/ui/chat";

function CustomChat() {
  const chat = useAptevaChat({ agentId: 42 });

  return (
    <>
      {chat.messages.map((message) => (
        <p key={message.id}>{message.content}</p>
      ))}
      {chat.streamingMessages.map((message) => (
        <p key={message.callId}>{message.text}</p>
      ))}
      <button onClick={() => chat.send("Hello")}>Send</button>
    </>
  );
}

The hook handles several details inherited from the production dashboard:

  • REST history, POST responses, and SSE rows are merged by durable message ID.
  • A late lower-ID POST response is not lost behind a newer SSE cursor.
  • Streaming text is cumulative and replaced per call_id, not appended.
  • Provisional streaming bubbles are settled when the durable agent message arrives.
  • EventSource reconnects are reflected through status.
  • A dashboard-style thinking placeholder appears immediately for an active user turn and is replaced by cumulative SSE response text.
  • Durable messages are reconciled in the background as a safety net if an intermediary drops an SSE frame.
  • Remounting resumes an existing conversation instead of creating duplicates.

Tool activity

Tool calls are enabled by default. AptevaChat subscribes to the selected agent's telemetry SSE feed, accepts events only from the conversation's exact runtime thread, correlates tool.call with tool.result, and restores the same rows from telemetry after a refresh. Internal delivery and pacing tools stay hidden.

The generic row shows the agent's reason, tool name, running/success/error state, duration, and expandable arguments/result. Replace individual tools with site-owned renderers when needed:

function SearchActivity({ activity }) {
  return <p>{activity.reason || "Searching…"}</p>;
}

<AptevaChat
  agentId={42}
  toolActivityRenderers={{
    crm_search: SearchActivity,
  }}
/>

Set showToolActivity={false} to disable it. Headless UIs can use useAptevaToolActivity({ agentId, chatId }) and render the returned activities themselves.

Rich message components

Agents can attach message.components. Register site-owned renderers by app:name:

function ContactCard({ component }) {
  return <a href={`/contacts/${component.props?.id}`}>Open contact</a>;
}

<AptevaChat
  agentId={42}
  componentRenderers={{
    "crm:contact-card": ContactCard,
  }}
/>

Unknown components are ignored while the message text remains visible.

Styling

Every selector is scoped below .apteva-chat. Override CSS variables on the component or a parent class:

.support-chat {
  --apteva-chat-accent: #155eef;
  --apteva-chat-accent-text: white;
  --apteva-chat-radius: 20px;
  --apteva-chat-font: "DM Sans", sans-serif;
  height: 640px;
}
<AptevaChat className="support-chat" agentId={42} theme="light" />

theme accepts "light", "dark", or "auto".

Authentication

The chat API requires an authenticated Apteva user. For browser applications, prefer session-cookie authentication. Do not put a full account API key in a publicly accessible website bundle. A public anonymous widget should use a separate short-lived, chat-scoped token flow.