
Research
/Security News
Coruna Respawned: Compromised art-template npm Package Leads to iOS Browser Exploit Kit
Compromised npm package art-template delivered a Coruna-like iOS Safari exploit framework through a watering-hole attack.
@cstar.help/js
Advanced tools
Official TypeScript SDK for the cStar customer support platform.
fetchnpm install @cstar.help/js
cStar has one package with six entry points, each designed for a different context:
| Import | Use Case | Runs On | Auth Required | Key Type |
|---|---|---|---|---|
@cstar.help/js | Admin dashboard / backend integration | Server only | Yes | Secret (sk_*) |
@cstar.help/js/chat | Customer chat widget | Browser | Yes | Publishable (pk_*) |
@cstar.help/js/library | Public knowledge base | Browser or server | No | None |
@cstar.help/js/community | Public community forum | Browser or server | No | None |
@cstar.help/js/webhook | Webhook signature verification | Server only | No | Signing secret |
@cstar.help/js/auth | Authentication utilities | Server only | Yes | Secret (sk_*) |
cStar uses two key types to control access — the same pattern as Stripe:
Secret keys (sk_live_*, sk_test_*)
├── Full CRUD on all resources
├── Settings, billing, analytics, game system
├── Team member management, audit log
├── AI actions, automations, SLA rules
└── NEVER expose in client-side code
Publishable keys (pk_live_*, pk_test_*)
├── Read-only on public data (tickets, customers, articles)
├── Used by the chat widget for customer-facing features
├── Safe to include in browser bundles
└── Cannot write, delete, or access sensitive endpoints
Rule of thumb: If you're building a custom support dashboard for your team, use
CStarClientwith a secret key on your backend. If you're adding chat to your website, useChatClientwith a publishable key in the browser.
⚠️ Server-side only.
CStarClientrequires a secret key (sk_*) and must never be used in browser code. The SDK will warn you if it detects a browser environment.
Manage tickets, customers, articles, team members, settings, game system, and everything else.
import { CStarClient } from '@cstar.help/js';
const cstar = new CStarClient({
apiKey: process.env.CSTAR_SECRET_KEY, // sk_live_... or sk_test_...
teamId: process.env.CSTAR_TEAM_ID
});
// List open tickets
const { data: tickets } = await cstar.tickets.list({ status: 'open' });
// Create a ticket
const { data: ticket } = await cstar.tickets.create({
title: 'Help with billing',
customerId: 'cus_abc123'
});
// Auto-paginate through all tickets
for await (const ticket of cstar.tickets.listAutoPaginating({ status: 'open' })) {
console.log(ticket.title);
}
Core Resources — Tickets, customers, and knowledge base.
| Resource | Methods |
|---|---|
cstar.tickets | .list() .get(id) .create(params) .update(id, params) .del(id) .listAutoPaginating() |
cstar.tickets.messages | .list(ticketId) .create(ticketId, params) |
cstar.customers | .list() .get(id) .create(params) .update(id, params) .del(id) .listAutoPaginating() |
cstar.articles | .list() .get(id) .create(params) .update(id, params) .del(id) .listAutoPaginating() |
cstar.categories | .list() .get(id) .create(params) .update(id, params) .del(id) |
Team & Configuration — Members, settings, and customization.
| Resource | Methods |
|---|---|
cstar.members | .list() .get(id) .update(id, params) .del(id) |
cstar.members.invites | .list() .create(params) .del(id) |
cstar.settings | .get() .update(params) .getBusinessHours() .updateBusinessHours(params) .getWidget() .updateWidget(params) |
cstar.settings.statuses | .list() .create(params) .update(key, params) .del(key) .reorder(keys) |
cstar.settings.quickReplies | .list() .create(params) .update(id, params) .del(id) .reorder(ids) |
cstar.customFields | .list() .get(id) .create(params) .update(id, params) .del(id) .reorder(ids) |
cstar.notifications | .list() .unreadCount() .markRead(id) .markAllRead() |
Operations — Analytics, bulk actions, and data management.
| Resource | Methods |
|---|---|
cstar.analytics | .overview(params?) .agents(params?) .csatStats(params?) .csatResponses(params?) |
cstar.sla | .list() .get(id) .create(params) .update(id, params) .del(id) |
cstar.bulk | .update(params) .del(params) |
cstar.export | .create(params) |
cstar.import | .create(params) .logs(params?) .getLog(id) |
cstar.search | .query(params) |
cstar.tags | .list() .create(name) .del(name) |
cstar.activity | .list(params?) |
cstar.auditLog | .list(params?) |
cstar.customerGroups | .list() .get(id) .create(params) .update(id, params) .del(id) |
Gamification — The full game system.
| Resource | Methods |
|---|---|
cstar.game | .player(params?) .getPlayer(memberId) .leaderboard(params?) .myRank(params?) |
cstar.game.boss | .current() .isActive() .spawn(params?) .damage(params) .defeats(params?) .getDefeat(id) |
cstar.game.achievements | .list(params?) .unlocked(params) .get(id, params?) |
cstar.game.quests | .today(params?) .history(params?) |
cstar.game.puzzles | .today(params?) .complete(params) .streak(params) .leaderboard(params?) |
cstar.game.oneUps | .list(params?) .send(params) .remaining(params) |
cstar.game.highFives | .list(params?) .send(params) .canSend(teamId, params) |
cstar.game.cosmetics | .list(params?) .getPreferences(params) .updatePreferences(params) |
cstar.game.seasons | .list() .current() .stats(seasonId, params) |
cstar.game.skills | .get(params) .allocate(params) .reset(params) |
Advanced — AI, automations, views, billing, webhooks.
| Resource | Methods |
|---|---|
cstar.ai | .run(params) .autoTag(ticketId) .suggestReply(ticketId) .summarize(ticketId) .improve(text) |
cstar.automations | .list() .get(id) .create(params) .update(id, params) .del(id) .toggle(id) .reorder(ids) .test(id, params) .executions(id) .allExecutions() .evaluate(params) |
cstar.views | .list() .get(id) .create(params) .update(id, params) .del(id) .execute(id, params?) |
cstar.billing | .subscription() .portal(params?) |
cstar.webhooks | .list() .get(id) .create(params) .update(id, params) .del(id) .test(id) |
cstar.community.posts | .list() .get(id) .create(params) .update(id, params) .del(id) |
cstar.community.topics | .list() .get(id) |
cstar.attachments | .list(params?) .get(id) .del(id) |
// Team analytics
const { data: overview } = await cstar.analytics.overview({ period: 'week' });
console.log(`${overview.tickets.open} open tickets this week`);
// SLA rules
const { data: rules } = await cstar.sla.list();
// Boss battle
const { data: boss } = await cstar.game.boss.current();
if (boss.active) {
console.log(`${boss.name} — ${boss.health}/${boss.maxHealth} HP`);
}
// AI-powered reply suggestion
const { data: suggestion } = await cstar.ai.suggestReply('tkt_abc123');
// Bulk close resolved tickets
await cstar.bulk.update({
resource: 'tickets',
ids: ['tkt_1', 'tkt_2', 'tkt_3'],
data: { status: 'closed' }
});
// Export data
const { data: exportResult } = await cstar.export.create({
resources: [{ type: 'tickets', filters: { status: 'closed' } }],
format: 'csv'
});
// Saved views
const { data: view } = await cstar.views.create({
name: 'Urgent Unresolved',
entityType: 'tickets',
filters: { priority: 'urgent', status: 'open' }
});
const { data: results } = await cstar.views.execute(view.id);
// Search across everything
const { data: searchResults } = await cstar.search.query({
query: 'billing issue',
types: ['tickets', 'customers']
});
Build custom chat experiences in the browser. Uses a publishable key — safe for frontend code.
The chat client supports two authentication modes:
You don't have to pick the mode up-front. The first response from any cstar endpoint includes an X-Cstar-Auth-Mode header, which the SDK caches; chat.getAuthMode() returns 'hmac', 'session', or null after the first call.
import { ChatClient } from '@cstar.help/js/chat';
const chat = new ChatClient({ teamSlug: 'acme' });
await chat.identify(
{ externalId: 'usr_123', email: 'jane@example.com', name: 'Jane', timestamp: Date.now() / 1000 },
hmacSignature
);
const chat = new ChatClient({ teamSlug: 'acme' });
// Login with credentials — returns the customer + tokens
const { customer, accessToken, refreshToken } = await chat.loginWithCredentials(
'jane@example.com',
'hunter2'
);
// Or rehydrate from previously stored tokens
await chat.loginWithSession(accessToken, refreshToken);
const { tickets } = await chat.tickets.list();
await chat.messages.send('tkt_abc123', 'Thanks for the help!');
const unsubscribe = chat.onMessage('tkt_abc123', (message) => {
console.log(`${message.sender_name}: ${message.content}`);
});
chat.disconnect();
Every ChatClient request throws a typed subclass of ChatClientError on failure. Each carries a requestId (from the X-Request-Id response header) so customer support can correlate against server logs.
import {
ChatClientError,
ChatClientAuthError,
ChatClientRateLimitError,
ChatClientServerError,
ChatClientNetworkError
} from '@cstar.help/js/chat';
try {
await chat.identify(customer, signature);
} catch (err) {
if (err instanceof ChatClientAuthError) {
// 401 / 403 — bad signature, expired token, wrong team
} else if (err instanceof ChatClientRateLimitError) {
// 429 — back off for err.retryAfter seconds
} else if (err instanceof ChatClientServerError) {
// 5xx — usually transient, retry with backoff
} else if (err instanceof ChatClientNetworkError) {
// fetch() itself failed — DNS, offline, CORS — see err.originalError
} else if (err instanceof ChatClientError) {
console.log('Error', err.code, err.statusCode, 'requestId:', err.requestId);
}
}
Search and browse your public help center — no authentication required.
import { LibraryClient } from '@cstar.help/js/library';
const library = new LibraryClient({ teamSlug: 'acme' });
const categories = await library.categories();
const results = await library.search('reset password');
const article = await library.article('how-to-reset-password');
Browse your public community forum — no authentication required.
import { CommunityClient } from '@cstar.help/js/community';
const community = new CommunityClient({ teamSlug: 'acme' });
const topics = await community.topics();
const { posts } = await community.posts({ topicSlug: 'feature-requests', sort: 'votes' });
const { post, comments } = await community.post('dark-mode-support');
Verify incoming webhook signatures on your server.
import { constructEvent } from '@cstar.help/js/webhook';
// In your webhook handler
const event = constructEvent(rawBody, signature, 'whsec_your_secret');
switch (event.type) {
case 'ticket.created':
console.log('New ticket:', event.data.title);
break;
case 'customer.created':
console.log('New customer:', event.data.email);
break;
}
For edge runtimes (Cloudflare Workers, Deno), use the async variant:
import { constructEventAsync } from '@cstar.help/js/webhook';
const event = await constructEventAsync(rawBody, signature, secret);
const cstar = new CStarClient({
apiKey: 'sk_live_...', // Required — must be a secret key (sk_*)
teamId: 'tm_...', // Required — your team ID
baseUrl: 'https://...', // Optional — defaults to https://www.cstar.help
version: '2026-03-01', // Optional — API version header
maxRetries: 3, // Optional — retry attempts for 5xx/429
timeout: 30000 // Optional — request timeout in ms
});
Test mode is auto-detected from your API key prefix:
const cstar = new CStarClient({
apiKey: 'sk_test_abc123...',
teamId: 'tm_your_team_id'
});
console.log(cstar.isTestMode); // true
// All operations use test data — no real customers affected
All API errors throw typed exceptions:
import {
CStarError,
CStarAuthenticationError,
CStarRateLimitError,
CStarNotFoundError,
CStarValidationError
} from '@cstar.help/js';
try {
await cstar.tickets.get('tkt_nonexistent');
} catch (err) {
if (err instanceof CStarNotFoundError) {
console.log('Ticket not found:', err.message);
} else if (err instanceof CStarValidationError) {
console.log('Invalid param:', err.param);
} else if (err instanceof CStarRateLimitError) {
console.log('Rate limited, retry after:', err.retryAfter, 'seconds');
} else if (err instanceof CStarAuthenticationError) {
console.log('Bad API key');
} else if (err instanceof CStarError) {
console.log('API error:', err.code, err.statusCode);
}
}
Safely retry create/update operations:
const { data: ticket } = await cstar.tickets.create(
{ title: 'Billing issue', customerId: 'cus_abc' },
{ idempotencyKey: 'create-billing-issue-usr123' }
);
fetch and AbortSignal.timeout)MIT
FAQs
Official TypeScript SDK for the cStar customer support platform
The npm package @cstar.help/js receives a total of 97 weekly downloads. As such, @cstar.help/js popularity was classified as not popular.
We found that @cstar.help/js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Research
/Security News
Compromised npm package art-template delivered a Coruna-like iOS Safari exploit framework through a watering-hole attack.

Company News
As AI accelerates how code is written and shipped, Socket is scaling to protect the software supply chain from the growing wave of attacks targeting open source dependencies.

Company News
Socket is scaling to defend open source against supply chain attacks as AI accelerates software development.