🚨 Active Supply Chain Attack:node-ipc Package Compromised.Learn More
Socket
Book a DemoSign in
Socket

@cstar.help/react

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cstar.help/react

React hooks for the cStar customer support platform

latest
Source
npmnpm
Version
0.10.0
Version published
Weekly downloads
59
-7.81%
Maintainers
1
Weekly downloads
 
Created
Source

@cstar.help/react

React hooks for the cStar customer support platform. Build custom chat widgets and knowledge base UIs with type-safe, SSR-compatible hooks.

  • React 18+ — hooks with automatic loading states and error handling
  • Three modules — Chat (real-time messaging), Library (knowledge base), and Community (forum)
  • TypeScript-first — full type definitions included
  • Tiny — ~18 KB, tree-shakeable, only peer deps

Install

npm install @cstar.help/react @cstar.help/js

Chat

Wrap your app in <CStarChatProvider> and use hooks anywhere inside.

Setup

import { CStarChatProvider } from '@cstar.help/react';

function App() {
	return (
		<CStarChatProvider teamSlug="acme">
			<ChatWidget />
		</CStarChatProvider>
	);
}

Identify the Customer

import { useChat } from '@cstar.help/react';

function ChatWidget() {
	const { identify, isIdentified, isRealtimeReady, error } = useChat();

	useEffect(() => {
		identify(
			{ externalId: 'usr_123', email: 'jane@acme.com', timestamp: Math.floor(Date.now() / 1000) },
			hmacSignature // computed server-side
		);
	}, []);

	if (!isIdentified) return <p>Connecting...</p>;
	return <TicketList />;
}

Tickets

import { useTickets } from '@cstar.help/react';

function TicketList() {
	const { tickets, isLoading, create, refresh, hasMore } = useTickets();

	if (isLoading) return <Spinner />;

	return (
		<ul>
			{tickets.map((t) => (
				<li key={t.id}>{t.subject}</li>
			))}
		</ul>
	);
}

Messages + Typing Indicators

import { useMessages, useTyping } from '@cstar.help/react';

function ChatWindow({ ticketId }) {
	const { messages, isLoading, send } = useMessages(ticketId);
	const { typingAgents, sendTyping } = useTyping(ticketId);
	const [text, setText] = useState('');

	const handleSend = async () => {
		await send(text); // optimistic — appears instantly
		setText('');
	};

	return (
		<>
			{messages.map((msg) => (
				<div key={msg.id}>{msg.content}</div>
			))}
			{typingAgents.map((a) => (
				<p key={a.agentId}>{a.agentName} is typing...</p>
			))}
			<input
				value={text}
				onChange={(e) => {
					setText(e.target.value);
					sendTyping(e.target.value.length > 0);
				}}
				onKeyDown={(e) => e.key === 'Enter' && handleSend()}
			/>
		</>
	);
}

Knowledge Base

Wrap in <CStarLibraryProvider> for public knowledge base access — no auth required.

Setup

import { CStarLibraryProvider } from '@cstar.help/react';

function App() {
	return (
		<CStarLibraryProvider teamSlug="acme">
			<HelpCenter />
		</CStarLibraryProvider>
	);
}

Categories + Articles

import { useCategories, useArticles, useArticle } from '@cstar.help/react';

function HelpCenter() {
	const { categories, isLoading: catsLoading } = useCategories();
	const { articles, isLoading: artsLoading } = useArticles({ categorySlug: 'getting-started' });

	return (
		<>
			<nav>
				{categories.map((cat) => (
					<a key={cat.id}>{cat.name}</a>
				))}
			</nav>
			<ul>
				{articles.map((a) => (
					<li key={a.id}>{a.title}</li>
				))}
			</ul>
		</>
	);
}

// Single article by slug
function ArticlePage({ slug }) {
	const { article, isLoading, error } = useArticle(slug);
	if (isLoading) return <Spinner />;
	if (!article) return <NotFound />;
	return <h1>{article.title}</h1>;
}

Search with Debouncing

import { useArticleSearch } from '@cstar.help/react';

function SearchBar() {
	const [query, setQuery] = useState('');
	const { results, totalCount, isLoading } = useArticleSearch(query); // 300ms debounce built-in

	return (
		<>
			<input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search..." />
			{isLoading && <Spinner />}
			{results.map((a) => (
				<a key={a.id} href={`/articles/${a.slug}`}>
					{a.title}
				</a>
			))}
		</>
	);
}

Community

Wrap in <CStarCommunityProvider> for public community forum access — no auth required.

Setup

import { CStarCommunityProvider } from '@cstar.help/react';

function App() {
	return (
		<CStarCommunityProvider teamSlug="acme">
			<CommunityForum />
		</CStarCommunityProvider>
	);
}

Topics + Posts

import { useTopics, usePosts, usePost } from '@cstar.help/react';

function CommunityForum() {
	const { topics, isLoading: topicsLoading } = useTopics();
	const { posts, count, isLoading: postsLoading } = usePosts({ sort: 'votes' });

	return (
		<>
			<nav>
				{topics.map((topic) => (
					<a key={topic.id}>{topic.name}</a>
				))}
			</nav>
			<p>{count} posts</p>
			<ul>
				{posts.map((post) => (
					<li key={post.id}>
						{post.title} — {post.voteCount} votes
					</li>
				))}
			</ul>
		</>
	);
}

// Single post with comments
function PostPage({ slug }) {
	const { data, isLoading, error } = usePost(slug);
	if (isLoading) return <Spinner />;
	if (!data) return <NotFound />;
	return (
		<>
			<h1>{data.post.title}</h1>
			{data.comments.map((c) => (
				<p key={c.id}>{c.body}</p>
			))}
		</>
	);
}
import { useCommunitySearch } from '@cstar.help/react';

function CommunitySearch() {
	const { results, isLoading, search } = useCommunitySearch();

	return (
		<>
			<input onChange={(e) => search(e.target.value)} placeholder="Search posts..." />
			{results?.data.map((post) => (
				<a key={post.id}>{post.title}</a>
			))}
		</>
	);
}

API Reference

Chat Hooks

HookReturnsDescription
useChat(){ identify, disconnect, isIdentified, isRealtimeReady, error }Identity verification and connection state
useTickets(){ tickets, isLoading, error, hasMore, refresh, create }List and create tickets
useMessages(ticketId){ messages, isLoading, error, send, refresh }Messages with real-time updates and optimistic send
useTyping(ticketId){ typingAgents, sendTyping }Agent typing indicators with auto-clear (4s timeout)

Library Hooks

HookReturnsDescription
useCategories(){ categories, isLoading, error, refresh }Knowledge base categories
useArticles(params?){ articles, isLoading, error, refresh }Articles, optionally filtered by category
useArticle(slug){ article, isLoading, error, refresh }Single article by slug
useArticleSearch(query){ results, totalCount, isLoading, error }Search with 300ms debounce

Community Hooks

HookReturnsDescription
useTopics(){ topics, isLoading, error, refresh }Community discussion topics
usePosts(params?){ posts, count, isLoading, error, refresh }Posts with optional filters (topicSlug, status, sort)
usePost(slug){ data, isLoading, error, refresh }Single post with comments
useCommunitySearch(){ results, isLoading, error, search }On-demand search across posts

Context Accessors

FunctionReturnsDescription
useChatClient()ChatClientRaw client from nearest CStarChatProvider
useLibraryClient()LibraryClientRaw client from nearest CStarLibraryProvider
useCommunityClient()CommunityClientRaw client from nearest CStarCommunityProvider

Using with Next.js App Router (RSC)

The dashboard provider (CStarDashboardProvider) wraps a CStarClient, which is a class instance — and React Server Components can't serialize class instances across the server/client boundary. The provider therefore takes one of two prop shapes:

Recommended — pass a plain config object. The provider builds (and disposes) the client inside the 'use client' boundary, so nothing class-shaped crosses the RSC boundary:

// app/providers.tsx
'use client';
import { CStarDashboardProvider } from '@cstar.help/react';

export function Providers({ children }: { children: React.ReactNode }) {
	return (
		<CStarDashboardProvider
			config={{
				apiKey: process.env.NEXT_PUBLIC_CSTAR_PUBLISHABLE_KEY!,
				teamId: process.env.NEXT_PUBLIC_CSTAR_TEAM_ID!
			}}
		>
			{children}
		</CStarDashboardProvider>
	);
}

Use the apiKey field for a publishable key (pk_live_* / pk_test_*), NOT a secret key — the bundle ships to the browser. For server-only flows (an admin route handler, a server action), construct CStarClient with the secret key inline; never thread it into a provider.

Legacy — pass a pre-built client (deprecated). If you already have a client instance you want to share, the client prop still works, but you have to construct it inside 'use client' and you take on responsibility for tearing down the realtime subscription:

'use client';
import { useMemo } from 'react';
import { CStarClient } from '@cstar.help/js';
import { CStarDashboardProvider } from '@cstar.help/react';

export function Providers({ children }) {
	const client = useMemo(
		() =>
			new CStarClient({
				apiKey: process.env.NEXT_PUBLIC_CSTAR_PUBLISHABLE_KEY!,
				teamId: process.env.NEXT_PUBLIC_CSTAR_TEAM_ID!
			}),
		[]
	);
	return <CStarDashboardProvider client={client}>{children}</CStarDashboardProvider>;
}

Either way, mark the file 'use client'. Server components can sit above the provider in the tree — only the provider boundary needs to be a client component.

Requirements

  • React 18+
  • @cstar.help/js 0.1.0+
  • Node.js 18+ (for SSR)

License

MIT

Keywords

cstar

FAQs

Package last updated on 03 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts