@cstar.help/js

中文文档
0.20.0发布于 2026/11/08MITTypeScriptESM + CJS近 30 天下载 2190

Official TypeScript SDK for the cStar customer support platform

原始使用文档
文档目录22 节
  1. Install
  2. Which SDK Do I Need?
  3. The Security Model
  4. Server-Side: Admin API Client
  5. Private notes and message history
  6. Full Resource Reference
  7. Usage Examples
  8. Client-Side: Chat Widget SDK
  9. HMAC
  10. Session (email/password)
  11. Session (existing customer token)
  12. Once authenticated (either mode)
  13. Typed errors
  14. Client-Side: Public Knowledge Base
  15. Client-Side: Public Community
  16. Server-Side: Webhook Verification
  17. Configuration
  18. Test Mode
  19. Error Handling
  20. Idempotency
  21. Requirements
  22. License

@cstar.help/js

Official TypeScript SDK for the cStar customer support platform.

  • Native fetch for HTTP, Supabase for realtime
  • TypeScript-first, with full type definitions included
  • Focused entry points for the part of cStar you're building with
  • ESM + CJS exports

Install

npm install @cstar.help/js

Which SDK Do I Need?

cStar has one package with separate entry points for different workflows. Start here:

ImportUse CaseRuns OnAuth RequiredKey Type
@cstar.help/jsAdmin dashboard / backend integrationServer onlyYesSecret (sk_*)
@cstar.help/js/chatCustomer chat widgetBrowserYesHMAC or customer session
@cstar.help/js/libraryPublic knowledge baseBrowser or serverNoNone
@cstar.help/js/communityPublic community forumBrowser or serverNoNone
@cstar.help/js/webhookWebhook signature verificationServer onlyNoSigning secret
@cstar.help/js/authCustomer signup and loginBrowserNoNone (teamSlug)

The Security Model

The server API and customer chat authenticate differently:

  • Secret API keys (sk_live_*, sk_test_*) authorize team API operations within the key's permissions. Keep them on your server.
  • Publishable API keys (pk_live_*, pk_test_*) are for the public SDKs (LibraryClient, CommunityClient) and GET /auth/whoami. Team API endpoints refuse them with 403: publishable_key_forbidden on reads and publishable_key_write on writes, so CStarClient needs a secret key. They do not identify a customer or authorize customer chat.
  • ChatClient takes a teamSlug, then authenticates a customer through HMAC identity verification or a customer session. It has no API-key option. Keep HMAC signing secrets on your server too.

Building a support dashboard? Use CStarClient on your backend. Adding a conversation to your website? Use ChatClient and one of the customer authentication options below.


Server-Side: Admin API Client

⚠️ Server-side only. CStarClient requires 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 apiKey = process.env.CSTAR_SECRET_KEY; // sk_live_... or sk_test_...
const teamId = process.env.CSTAR_TEAM_ID;
if (!apiKey || !teamId) throw new Error('Set CSTAR_SECRET_KEY and CSTAR_TEAM_ID.');
const cstar = new CStarClient({ apiKey, teamId });

// List open tickets
const { data: tickets } = await cstar.tickets.list({ status: 'open' });

// Create a ticket
const 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);
}

Created, retrieved and updated resources are returned directly. List methods return { data, pagination, hasMore }. Search returns { results, total, query }. Read cstar.lastMeta.requestId immediately after a call when you need its request ID.

Private notes and message history

Run message management on your server with a secret key. Internal notes stay inside the support team.

const note = await cstar.tickets.messages.create('tkt_123', {
    content: 'The customer has already tried resetting their password.',
    messageType: 'internal'
});
console.log(note.isInternal);

const page = await cstar.tickets.messages.list('tkt_123', { page: 2, pageSize: 25 });
console.log(page.data, page.pagination.hasMore);

The isInternal boolean is also accepted when creating a note. If you supply both privacy options, they must agree. Message history is paginated, so request the next page while hasMore is true.

Full Resource Reference

Core Resources: Tickets, customers, and knowledge base.

ResourceMethods
cstar.tickets.list() .get(id) .create(params) .update(id, params) .del(id) .listAutoPaginating()
cstar.tickets.messages.list(ticketId, params?) .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.

ResourceMethods
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() .create(params) .update(id, params) .del(id) .reorder(ids)
cstar.notifications.list({ userId }) .unreadCount(userId) .markRead(id, userId) .markAllRead(userId)

Operations: Analytics, bulk actions, and data management.

ResourceMethods
cstar.analytics.overview(params?) .performance(params?) .library(params?) .csatStats(params?)
cstar.sla.list() .create(params) .update(id, params) .del(id) .reorder(ids) .metrics(params?)
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() .merge(params) .remove(tag) .del(tag)
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.

ResourceMethods
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(params?) .current() .stats(seasonId, params)
cstar.game.skills.get(params) .allocate(params) .reset(params)

Game writes belong on your server with a secret API key. Use user and team UUIDs from cStar. One-ups and high fives default their sender to the key creator. Puzzle scoreboards require a puzzleId; streak boards use { type: 'streaks' }. Cosmetic lists require a userId.

Cosmetic and season lists return { data, pagination, hasMore }. One-up and high-five lists return { object: 'list', data }. Today's quests return { quests, completedToday, totalQuests, allComplete, resetsAt } (each quest pays its own xpReward and goldReward; there is no all-quests bonus). Single resources return bare objects.

Advanced: AI, automations, views, billing, webhooks.

ResourceMethods
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.upload(file, params) .list(params?) .get(id) .del(id)

Usage Examples

// Team analytics
const overview = await cstar.analytics.overview({ period: 'week' });
console.log(`${overview.tickets?.open ?? 0} open tickets this week`);

// SLA rules
const { data: rules } = await cstar.sla.list();

// Cheer on another team. The sender defaults to your API key's creator.
const highFive = await cstar.game.highFives.send({
    recipientTeamId: '550e8400-e29b-41d4-a716-446655440003',
    message: 'Amazing work!'
});
console.log(`A high five from ${highFive.senderTeam.name}`);

// AI-powered reply suggestion
const 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 closed tickets as JSON with raw rows and per-resource counts
const exported = await cstar.export.create({
    resources: ['tickets'],
    filters: { status: 'closed' },
    format: 'json'
});
console.log(exported.summary.tickets);

// CSV is text and supports one resource at a time
const csv = await cstar.export.create({ resources: ['tickets'], format: 'csv' });

// Saved views
const view = await cstar.views.create({
    name: 'Critical Unresolved',
    entityType: 'tickets',
    filters: { priority: 'critical', status: 'open' }
});
const { data: results } = await cstar.views.execute(view.id);

// Search across everything
const { results: searchResults } = await cstar.search.query({
    query: 'billing issue',
    types: ['tickets', 'customers']
});

Client-Side: Chat Widget SDK

Build a chat experience that feels at home on your site. ChatClient handles customer conversations in the browser without a team API key.

The chat client supports two authentication modes:

  • HMAC: your authenticated backend signs the customer's identity with the team's signing secret. Use this when your site already knows who's signed in.
  • Session: sign in with cStar customer credentials, or provide an existing cStar customer access token. Use this for a standalone widget or customer portal.

Choose the flow supported by your team's widget configuration. chat.getAuthMode() returns 'hmac', 'session', or null before authentication or after disconnecting. A session login sets the session mode; the SDK also reads the server's X-Cstar-Auth-Mode response header.

HMAC

Create /api/support/identity on your own backend. It must derive the customer from the authenticated user and return { customer, signature } using your team's signing secret. Send that exact payload to cStar; generating a new timestamp in the browser changes the signed data. The identity guide shows the signing contract.

import { ChatClient, type IdentifyParams } from '@cstar.help/js/chat';

const chat = new ChatClient({ teamSlug: 'acme' });
const response = await fetch('/api/support/identity', { credentials: 'same-origin' });
if (!response.ok) throw new Error('Could not verify your support identity');

const { customer, signature } = (await response.json()) as {
    customer: IdentifyParams;
    signature: string;
};
await chat.identify(customer, signature);

Session (email/password)

import { ChatClient } from '@cstar.help/js/chat';

const chat = new ChatClient({ teamSlug: 'acme' });

// Use the values from your customer's sign-in form.
const { customer, teamId } = await chat.loginWithCredentials({
    email: '[email protected]',
    password: 'your-customer-password'
});
console.log(`Hello, ${customer.name ?? customer.email}!`, teamId);

The client keeps the access token internally. The public result contains customer and teamId, not access or refresh tokens. This signs in an existing customer; it does not create an account.

Session (existing customer token)

Pass an existing cStar customer token as an object. A token from an unrelated Supabase project does not establish a cStar customer session. Include the cStar team UUID when your application has it. Otherwise the client resolves its configured team slug before message, community and realtime requests.

import { ChatClient, type LoginWithSessionParams } from '@cstar.help/js/chat';

async function connectCustomerSession(session: LoginWithSessionParams) {
    const chat = new ChatClient({ teamSlug: 'acme' });
    await chat.loginWithSession(session); // { accessToken, teamId?, customerName? }
    return chat;
}

Once authenticated (either mode)

const { data: tickets, pagination } = await chat.tickets.list();
console.log(`${tickets.length} conversations`, pagination.hasMore);

// Use a ticket ID returned by the customer API.
const ticket = tickets[0];
let unsubscribe = () => {};
if (ticket) {
    const history = await chat.messages.list(ticket.id);
    console.log(history); // Message[]
    await chat.messages.send(ticket.id, 'Thanks for the help!');

    unsubscribe = chat.onMessage(ticket.id, (message) => {
        console.log(`${message.sender_name}: ${message.content}`);
    });
}

// Wire this to your UI's close/unmount handler and account-change cleanup.
function closeChat() {
    unsubscribe();
    chat.disconnect();
}

Typed errors

HTTP and network failures use typed subclasses of ChatClientError. A server response may provide a requestId through the X-Request-Id header; it is null when unavailable. Other failures, such as malformed response JSON, can still throw ordinary errors.

Customer message sends generate a new retry key for each intentional reply and retry network or server failures at most twice. Each retry uses the same key and returns the original saved reply. A terminal ChatClientError retains that key in error.idempotencyKey. Reuse it with chat.messages.send(ticketId, content, { idempotencyKey }) for a manual retry of the same reply. Keep the draft and key together; use a new key when the message or ticket changes. Receipts last 24 hours and stay scoped to the customer, team and live/test mode.

Pass { signal } to cancel a send or its retry delay. For a cancellable UI, generate and retain your own idempotencyKey before sending. A cancelled request may already have been saved. Conversation history includes client_request_key so your UI can reconcile a pending bubble with its confirmed reply. Separate sends with identical text remain separate messages. These message retries do not apply to ticket creation or other customer writes.

import {
    ChatClientError,
    ChatClientAuthError,
    ChatClientRateLimitError,
    ChatClientServerError,
    ChatClientNetworkError
} from '@cstar.help/js/chat';

try {
    await chat.identify(customer, signature);
} catch (err) {
    if (err instanceof ChatClientAuthError) {
        // Authentication failed or the active customer session changed.
    } else if (err instanceof ChatClientRateLimitError) {
        // 429: respect err.retryAfter when the server supplies it.
    } else if (err instanceof ChatClientServerError) {
        // Server failure: keep the draft and check the conversation.
    } else if (err instanceof ChatClientNetworkError) {
        // Network failure: err.originalError has the underlying cause.
    } else if (err instanceof ChatClientError) {
        console.log('Error', err.code, err.statusCode, 'requestId:', err.requestId);
    } else {
        throw err;
    }
}

Client-Side: Public Knowledge Base

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');

Client-Side: Public Community

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');

Server-Side: Webhook Verification

Verify incoming webhook signatures on your server.

import { constructEvent } from '@cstar.help/js/webhook/node';

// In your webhook handler (Node). It throws if the signature is invalid.
const event = constructEvent(rawBody, signature, 'whsec_your_secret');

switch (event.type) {
    case 'ticket.created':
        console.log('New ticket:', event.data.ticket.title);
        break;
    case 'customer.created':
        console.log('New customer:', event.data.customer.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);

Configuration

const cstar = new CStarClient({
    apiKey: 'sk_live_...', // Required: must be a secret key (sk_*)
    teamId: '8f14e45f-ea2b-4c8b-9f1e-2a6b3c4d5e6f', // Required: your team ID (a UUID; GET /api/v1/auth/whoami returns it)
    baseUrl: 'https://...', // Optional: defaults to https://www.cstar.help
    version: '2026-03-01', // Optional: API version header
    maxRetries: 3, // Optional: retry attempts for retry-safe failures and 429
    timeout: 30000, // Optional: request timeout in ms
    fetch: myFetch, // Optional: send requests through this instead of the global fetch
    realtime: { types: ['ticket.created', 'message.created'] } // Optional: realtime stream options (types, eventSource polyfill, autoReconnect, maxRetries)
});

Reads retry network errors and server errors automatically. POST and PATCH requests retry those failures only when you pass idempotencyKey in the existing request options. A lost response may follow a successful write, so the SDK otherwise surfaces the error without repeating the mutation. Rate-limited requests still retry because the API rejects them before executing the operation.

await cstar.tickets.create(
    { title: 'Cannot reset password', customerId: 'cus_...' },
    { idempotencyKey: 'support-issue-123' }
);

Test Mode

Test mode is auto-detected from your API key prefix:

const cstar = new CStarClient({
    apiKey: 'sk_test_abc123...',
    teamId: process.env.CSTAR_TEAM_ID! // a UUID
});

console.log(cstar.isTestMode); // true
// All operations use test data, so no real customers are affected

Error Handling

All API errors throw typed exceptions:

import {
    CStarError,
    CStarAuthenticationError,
    CStarConflictError,
    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 CStarConflictError) {
        // A unique-key conflict, an Idempotency-Key still in use, or the team's
        // webhook limit (code 'webhook_limit_reached': delete unused webhooks first).
        console.log('Conflict:', err.code);
    } else if (err instanceof CStarAuthenticationError) {
        console.log('Bad API key');
    } else if (err instanceof CStarError) {
        console.log('API error:', err.code, err.statusCode);
    }
}

Idempotency

Safely retry create/update operations:

const ticket = await cstar.tickets.create(
    { title: 'Billing issue', customerId: 'cus_abc' },
    { idempotencyKey: 'create-billing-issue-usr123' }
);

For 24 hours, the same request with the same key returns the first successful response. The same key with a different body throws CStarValidationError (idempotency_key_reused, 422). While the first request is still running, the API answers 409 idempotency_key_in_use with Retry-After. From 0.18.1, the client waits and retries within maxRetries; 0.18.0 throws CStarConflictError.

The API ignores the key on webhooks.create, webhooks.listen and export.create, so a key does not make their retries safe. From 0.18.2 the client does not send the key on those calls and does not retry a network error or 5xx; 0.18.1 and earlier still retry them, so there leave the key off (without one the client does not retry them) or use a client with maxRetries: 0. Check webhooks.list() before you retry webhooks.create. A repeated export.create only reads your data again (nothing is stored). A repeated webhooks.listen is a second CLI listener: remove it with webhooks.unlisten(id), or it is swept after 5 minutes without a heartbeat.

Requirements

  • Node.js 22+ (matching the supported Supabase dependency)
  • TypeScript 5.0+ (for type definitions)

License

MIT

版本与发布记录

@cstar.help/js 共发布 44 个版本,首次发布于 2026/03/02;过去 12 个月发布了 44 个版本。

版本发布日期距今
0.20.0latest2026/11/083 天前
0.19.02026/11/065 天前
0.18.52026/11/056 天前
0.18.42026/11/029 天前
0.18.22026/10/2121 天前
0.18.12026/10/2121 天前

关于 @cstar.help/js 的常见问题

@cstar.help/js 是什么?

Official TypeScript SDK for the cStar customer support platform

如何安装 @cstar.help/js?

在项目目录运行 npm install @cstar.help/js,或使用 pnpm add / yarn add / bun add。

@cstar.help/js 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cstar.help/js 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cstar.help/js 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cstar.help/js 可以商用吗?

@cstar.help/js 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cstar.help/js 的下载量有多少?

根据 npm 官方下载统计,@cstar.help/js 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,190 次,日均约 73 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cstar.help/js 还在维护吗?

最新版本 0.20.0 发布于 2026/11/08(3 天前);至今共发布 44 个版本,其中过去 12 个月发布了 44 个;首次发布于 2026/03/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。