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

@m8tes/react

v0.1.0-alpha.13

Published

Embed m8tes AI agents in your React app — headless client + hooks + a drop-in <MateChat> with a locked-down server proxy.

Readme

@m8tes/react

Alpha. Install with npm i @m8tes/react. Component and hook APIs may change before 1.0; the streaming wire protocol itself is versioned separately (m8tes.stream.v2) and stays semver-stable. Found a rough edge? Tell us.

Embed m8tes AI agents in your React app: a headless client + hooks and a drop-in <MateChat> that streams a live agent run — text, tool calls, and inline human approvals — themed to your app.

Full guide: m8tes.ai/docs/embed-a-ui. Deeper references ship inside this package (node_modules/@m8tes/react/docs/) and are readable without installing: customizing.md (theme tokens, slots, dark mode) and auth-adapters.md (Clerk, Auth.js, Supabase, custom JWT, Express).

Architecture

The secret m8_ key lives only on your server. The browser talks to a thin proxy you mount; the proxy injects the end-user user_id and pipes the SSE stream.

  • Client entry @m8tes/react (browser-safe): M8tesProvider, useMate, <MateChat>, the SSE normalizer, and the typed V2 client. Never touches the key.
  • Server entry @m8tes/react/server (server-only): createM8tesHandler — the locked-down proxy. Mount it at /api/m8tes/[...path].

Quick start (Next.js App Router)

Install with npm i @m8tes/react in your React web app (React 18 or newer), then add two files.

1. The proxy route — app/api/m8tes/[...path]/route.ts:

import { auth } from "@clerk/nextjs/server"; // or use your existing server auth
import { createM8tesHandler } from "@m8tes/react/server";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const maxDuration = 300;

export const { GET, POST } = createM8tesHandler({
  apiKey: process.env.M8TES_API_KEY!,
  // map the request to YOUR end-user id (Clerk shown; Auth.js/Supabase/custom also work)
  resolveUserId: async () => (await auth()).userId,
  // recommended: pin embed runs to ONE mate so the browser can't target others
  agentId: process.env.M8TES_AGENT_ID,
});

2. The UI — any client component:

"use client";
import { M8tesProvider, MateChat } from "@m8tes/react";
import "@m8tes/react/styles.css";

export function Assistant() {
  return (
    <M8tesProvider>
      <MateChat
        style={{ height: "min(640px, 80dvh)" }}
        greeting="What can I help you with?"
      />
    </M8tesProvider>
  );
}

3. Set M8TES_API_KEY in .env.local on your server, and optionally M8TES_AGENT_ID to pin your configured agent. Sign in through your app's auth and send a message. The provider defaults to /api/m8tes; use its endpoint prop if you mount the proxy elsewhere. Give the panel a height so the thread can scroll. The first message can take up to a minute while the agent's sandbox starts. When a run fails, the handler logs the original error ([m8tes] upstream …) to your server log; your end-user sees a neutral message. No Tailwind installation or CSS reset is required.

The Clerk import assumes Clerk is already configured. For Auth.js, Supabase, or Express, use the complete auth adapters. Missing a signed-in user returns 401 by design.

Working in this repository? From packages/react/examples/next-chat, run npm run setup, copy .env.local.example to .env.local, then npm run dev.

Chat widget (launcher + panel)

The familiar support-bubble layout: a round launcher opens a floating panel (full screen on phones) with a home view, quick links, starter prompts and the chat.

Use the same server proxy as above, then add this component to your layout:

"use client";
import { M8tesProvider, MateWidget } from "@m8tes/react";
import "@m8tes/react/styles.css";

export function AssistantWidget() {
  return (
    <M8tesProvider>
      <MateWidget
        title="Ask Acme"
        heading="How can we help?"
        links={[{ label: "Read the docs", href: "/docs" }]}
        starters={[{ label: "Set up billing", message: "How do I set up billing?" }]}
      />
    </M8tesProvider>
  );
}

Closing the widget or returning home keeps the conversation, live stream, and unsent draft. Reopen and choose Continue conversation. Starter prompts appear before a conversation is opened. Unmount it (or change its React key) to reset.

Pass runId to restore a conversation and onRunIdChange to save new run IDs. loading / error cover your server's session setup; onOpenChange and onHome let you refresh that state. To send a first message from your own UI, use <MateChat initialMessage="…" />.

Save and restore a conversation

Both components accept onRunIdChange. Save the id in your app's state or backend, then pass it as runId when reopening the thread:

<MateChat runId={savedRunId} onRunIdChange={saveRunId} />

Scope saved IDs to the signed-in user. The proxy checks ownership on every request. Use your backend to list a user's threads; the browser proxy does not expose run listing. A completed run whose stream is unavailable restores its final output; this fallback is not a full historical transcript.

Connection recovery

Temporary stream drops reconnect automatically. If those attempts are exhausted, Retry rejoins the existing run without submitting another message — the server may still be executing it, so resending the prompt would run it twice. A failed initial request, where no run was created, offers the same button and re-sends. Pending approvals and questions keep waiting for the user's decision; a temporary submission failure can be retried.

Headless (bring your own UI)

const { messages, status, pendingApproval, canSend, isDisconnected, send, approve, retry } = useMate({ agentId });

Use canSend to enable your composer. When automatic reconnects run out the hook sets isDisconnected, puts the reason in connectionError, and keeps sending disabled until the run is reconciled — local status reads incomplete, but the server may still be running. retry() (or resume()) rejoins that same run without resending its prompt. An API refusal during a rejoin stays visible and can be retried once access is restored.

Theming

Styled to match the m8tes app out of the box (warm-white surface, onyx agent avatar, markdown replies, calm human-in-the-loop gates). It's chameleon: every --m8-* token maps to the matching shadcn / Tailwind-v4 token (--background, --primary, --border, --ring, --radius, --accent-blue, …) via var(--token, <m8tes fallback>), so dropped into a shadcn app it automatically adopts that app's theme — no mapping step. With no theme present it falls back to the m8tes palette. Override --m8-* on .m8tes-chat (or .m8tes-widget) in CSS loaded after the package stylesheet to fine-tune. (Assumes full-color tokens, i.e. shadcn on Tailwind v4 / OKLCH; older HSL-channel themes need the Tailwind v3 token bridge.)

Platform parity

<MateChat> targets the m8tes platform run page: what a run looks like there is what it looks like embedded. Current status:

Supported — streamed markdown replies with speaker grouping, readable long responses, live tool rows with verb labels, TodoWrite plan checklists, computer-use screenshots (inline + lightbox), approval gates (Allow / Always allow / Deny), AskUserQuestion cards (stepper, multi-select, free-text), plan approval (Approve / Revise), run file outputs with proxied downloads, sandbox status pills, notices/warnings, cancelled/failed states with retry, reconnect with exact-once replay, per-end-user limit cards.

Thinking and settled tool-history rows stay off the conversation, matching the Platform.

Not yet (tracked, on the beta path) — attachment upload through the proxy, the computer-use live desktop view, a shareable read-only run view.

Intentionally out of scope — permission-mode/model/tools pickers: the proxy strips execution-policy fields by design so the browser can never escalate what an embedded end-user may run. Configure policy on the Mate or the server proxy.

Security

The proxy keeps the key server-side, forwards only run-scoped routes, isolates end-users, and blocks policy escalation — but rate limiting, spend caps, and connection scoping are yours. Read the security model before going to production with real end-users.

Own the code

Prefer the component source in your repo, shadcn-style? Copy it and edit freely — the headless client stays a dependency:

npx shadcn@latest add https://www.m8tes.ai/r/mate-chat.json

Contributing

Bug reports and feature requests are welcome — open an issue; we review weekly. We don't currently accept external pull requests: this package is developed in our internal monorepo and synced out. If something blocks you, an issue (or [email protected]) is the fastest path to a fix.

License

MIT — see LICENSE. The m8tes name and logo are trademarks of m8tes; the MIT license does not grant trademark rights.