@cstar.help/js 0.3.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -42
- package/dist/community/index.cjs +94 -0
- package/dist/community/index.d.cts +115 -0
- package/dist/community/index.d.ts +115 -0
- package/dist/community/index.js +69 -0
- package/dist/index.cjs +903 -0
- package/dist/index.d.cts +1572 -1
- package/dist/index.d.ts +1572 -1
- package/dist/index.js +903 -0
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Official TypeScript SDK for the [cStar](https://cstar.help) customer support pla
|
|
|
4
4
|
|
|
5
5
|
- **Zero dependencies** — works with Node.js 18+ native `fetch`
|
|
6
6
|
- **TypeScript-first** — full type definitions included
|
|
7
|
-
- **
|
|
7
|
+
- **Six entry points** — tree-shake what you don't need
|
|
8
8
|
- **ESM + CJS** — works everywhere
|
|
9
9
|
|
|
10
10
|
## Install
|
|
@@ -13,18 +13,56 @@ Official TypeScript SDK for the [cStar](https://cstar.help) customer support pla
|
|
|
13
13
|
npm install @cstar.help/js
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
---
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
## Which SDK Do I Need?
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
cStar has one package with **six entry points**, each designed for a different context:
|
|
21
|
+
|
|
22
|
+
| Import | Use Case | Runs On | Auth Required | Key Type |
|
|
23
|
+
| -------------------------- | ----------------------------------------- | ----------------- | ------------- | -------------------- |
|
|
24
|
+
| `@cstar.help/js` | **Admin dashboard / backend integration** | Server only | Yes | Secret (`sk_*`) |
|
|
25
|
+
| `@cstar.help/js/chat` | Customer chat widget | Browser | Yes | Publishable (`pk_*`) |
|
|
26
|
+
| `@cstar.help/js/library` | Public knowledge base | Browser or server | No | None |
|
|
27
|
+
| `@cstar.help/js/community` | Public community forum | Browser or server | No | None |
|
|
28
|
+
| `@cstar.help/js/webhook` | Webhook signature verification | Server only | No | Signing secret |
|
|
29
|
+
| `@cstar.help/js/auth` | Authentication utilities | Server only | Yes | Secret (`sk_*`) |
|
|
30
|
+
|
|
31
|
+
### The Security Model
|
|
32
|
+
|
|
33
|
+
cStar uses **two key types** to control access — the same pattern as Stripe and Supabase:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Secret keys (sk_live_*, sk_test_*)
|
|
37
|
+
├── Full CRUD on all resources
|
|
38
|
+
├── Settings, billing, analytics, game system
|
|
39
|
+
├── Team member management, audit log
|
|
40
|
+
├── AI actions, automations, SLA rules
|
|
41
|
+
└── NEVER expose in client-side code
|
|
42
|
+
|
|
43
|
+
Publishable keys (pk_live_*, pk_test_*)
|
|
44
|
+
├── Read-only on public data (tickets, customers, articles)
|
|
45
|
+
├── Used by the chat widget for customer-facing features
|
|
46
|
+
├── Safe to include in browser bundles
|
|
47
|
+
└── Cannot write, delete, or access sensitive endpoints
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> **Rule of thumb**: If you're building a custom support dashboard for your team, use `CStarClient` with a secret key on your backend. If you're adding chat to your website, use `ChatClient` with a publishable key in the browser.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Server-Side: Admin API Client
|
|
55
|
+
|
|
56
|
+
> **⚠️ 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.
|
|
57
|
+
|
|
58
|
+
Manage tickets, customers, articles, team members, settings, game system, and everything else.
|
|
21
59
|
|
|
22
60
|
```typescript
|
|
23
61
|
import { CStarClient } from '@cstar.help/js';
|
|
24
62
|
|
|
25
63
|
const cstar = new CStarClient({
|
|
26
|
-
apiKey:
|
|
27
|
-
teamId:
|
|
64
|
+
apiKey: process.env.CSTAR_SECRET_KEY, // sk_live_... or sk_test_...
|
|
65
|
+
teamId: process.env.CSTAR_TEAM_ID
|
|
28
66
|
});
|
|
29
67
|
|
|
30
68
|
// List open tickets
|
|
@@ -36,18 +74,131 @@ const { data: ticket } = await cstar.tickets.create({
|
|
|
36
74
|
customerId: 'cus_abc123'
|
|
37
75
|
});
|
|
38
76
|
|
|
39
|
-
// Get a customer with expanded fields
|
|
40
|
-
const { data: customer } = await cstar.customers.get('cus_abc123');
|
|
41
|
-
|
|
42
77
|
// Auto-paginate through all tickets
|
|
43
78
|
for await (const ticket of cstar.tickets.listAutoPaginating({ status: 'open' })) {
|
|
44
79
|
console.log(ticket.title);
|
|
45
80
|
}
|
|
46
81
|
```
|
|
47
82
|
|
|
48
|
-
###
|
|
83
|
+
### Full Resource Reference
|
|
84
|
+
|
|
85
|
+
**Core Resources** — Tickets, customers, and knowledge base.
|
|
49
86
|
|
|
50
|
-
|
|
87
|
+
| Resource | Methods |
|
|
88
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `cstar.tickets` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
90
|
+
| `cstar.tickets.messages` | `.list(ticketId)` `.create(ticketId, params)` |
|
|
91
|
+
| `cstar.customers` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
92
|
+
| `cstar.articles` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
93
|
+
| `cstar.categories` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` |
|
|
94
|
+
|
|
95
|
+
**Team & Configuration** — Members, settings, and customization.
|
|
96
|
+
|
|
97
|
+
| Resource | Methods |
|
|
98
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| `cstar.members` | `.list()` `.get(id)` `.update(id, params)` `.del(id)` |
|
|
100
|
+
| `cstar.members.invites` | `.list()` `.create(params)` `.del(id)` |
|
|
101
|
+
| `cstar.settings` | `.get()` `.update(params)` `.getBusinessHours()` `.updateBusinessHours(params)` `.getWidget()` `.updateWidget(params)` |
|
|
102
|
+
| `cstar.settings.statuses` | `.list()` `.create(params)` `.update(key, params)` `.del(key)` `.reorder(keys)` |
|
|
103
|
+
| `cstar.settings.quickReplies` | `.list()` `.create(params)` `.update(id, params)` `.del(id)` `.reorder(ids)` |
|
|
104
|
+
| `cstar.customFields` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.reorder(ids)` |
|
|
105
|
+
| `cstar.notifications` | `.list()` `.unreadCount()` `.markRead(id)` `.markAllRead()` |
|
|
106
|
+
|
|
107
|
+
**Operations** — Analytics, bulk actions, and data management.
|
|
108
|
+
|
|
109
|
+
| Resource | Methods |
|
|
110
|
+
| ---------------------- | --------------------------------------------------------------------------------------- |
|
|
111
|
+
| `cstar.analytics` | `.overview(params?)` `.agents(params?)` `.csatStats(params?)` `.csatResponses(params?)` |
|
|
112
|
+
| `cstar.sla` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` |
|
|
113
|
+
| `cstar.bulk` | `.update(params)` `.del(params)` |
|
|
114
|
+
| `cstar.export` | `.create(params)` |
|
|
115
|
+
| `cstar.import` | `.create(params)` `.logs(params?)` `.getLog(id)` |
|
|
116
|
+
| `cstar.search` | `.query(params)` |
|
|
117
|
+
| `cstar.tags` | `.list()` `.create(name)` `.del(name)` |
|
|
118
|
+
| `cstar.activity` | `.list(params?)` |
|
|
119
|
+
| `cstar.auditLog` | `.list(params?)` |
|
|
120
|
+
| `cstar.customerGroups` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` |
|
|
121
|
+
|
|
122
|
+
**Gamification** — The full game system.
|
|
123
|
+
|
|
124
|
+
| Resource | Methods |
|
|
125
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
126
|
+
| `cstar.game` | `.player(params?)` `.getPlayer(memberId)` `.leaderboard(params?)` `.myRank(params?)` |
|
|
127
|
+
| `cstar.game.boss` | `.current()` `.isActive()` `.spawn(params?)` `.damage(params)` `.defeats(params?)` `.getDefeat(id)` |
|
|
128
|
+
| `cstar.game.achievements` | `.list(params?)` `.unlocked(params)` `.get(id, params?)` |
|
|
129
|
+
| `cstar.game.quests` | `.today(params?)` `.history(params?)` |
|
|
130
|
+
| `cstar.game.puzzles` | `.today(params?)` `.complete(params)` `.streak(params)` `.leaderboard(params?)` |
|
|
131
|
+
| `cstar.game.oneUps` | `.list(params?)` `.send(params)` `.remaining(params)` |
|
|
132
|
+
| `cstar.game.highFives` | `.list(params?)` `.send(params)` `.canSend(teamId, params)` |
|
|
133
|
+
| `cstar.game.cosmetics` | `.list(params?)` `.getPreferences(params)` `.updatePreferences(params)` |
|
|
134
|
+
| `cstar.game.seasons` | `.list()` `.current()` `.stats(seasonId, params)` |
|
|
135
|
+
| `cstar.game.skills` | `.get(params)` `.allocate(params)` `.reset(params)` |
|
|
136
|
+
|
|
137
|
+
**Advanced** — AI, automations, views, billing, webhooks.
|
|
138
|
+
|
|
139
|
+
| Resource | Methods |
|
|
140
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| `cstar.ai` | `.run(params)` `.autoTag(ticketId)` `.suggestReply(ticketId)` `.summarize(ticketId)` `.improve(text)` |
|
|
142
|
+
| `cstar.automations` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.toggle(id)` `.reorder(ids)` `.test(id, params)` `.executions(id)` `.allExecutions()` `.evaluate(params)` |
|
|
143
|
+
| `cstar.views` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.execute(id, params?)` |
|
|
144
|
+
| `cstar.billing` | `.subscription()` `.portal(params?)` |
|
|
145
|
+
| `cstar.webhooks` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.test(id)` |
|
|
146
|
+
| `cstar.community.posts` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` |
|
|
147
|
+
| `cstar.community.topics` | `.list()` `.get(id)` |
|
|
148
|
+
| `cstar.attachments` | `.list(params?)` `.get(id)` `.del(id)` |
|
|
149
|
+
|
|
150
|
+
### Usage Examples
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Team analytics
|
|
154
|
+
const { data: overview } = await cstar.analytics.overview({ period: 'week' });
|
|
155
|
+
console.log(`${overview.tickets.open} open tickets this week`);
|
|
156
|
+
|
|
157
|
+
// SLA rules
|
|
158
|
+
const { data: rules } = await cstar.sla.list();
|
|
159
|
+
|
|
160
|
+
// Boss battle
|
|
161
|
+
const { data: boss } = await cstar.game.boss.current();
|
|
162
|
+
if (boss.active) {
|
|
163
|
+
console.log(`${boss.name} — ${boss.health}/${boss.maxHealth} HP`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// AI-powered reply suggestion
|
|
167
|
+
const { data: suggestion } = await cstar.ai.suggestReply('tkt_abc123');
|
|
168
|
+
|
|
169
|
+
// Bulk close resolved tickets
|
|
170
|
+
await cstar.bulk.update({
|
|
171
|
+
resource: 'tickets',
|
|
172
|
+
ids: ['tkt_1', 'tkt_2', 'tkt_3'],
|
|
173
|
+
data: { status: 'closed' }
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Export data
|
|
177
|
+
const { data: exportResult } = await cstar.export.create({
|
|
178
|
+
resources: [{ type: 'tickets', filters: { status: 'closed' } }],
|
|
179
|
+
format: 'csv'
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Saved views
|
|
183
|
+
const { data: view } = await cstar.views.create({
|
|
184
|
+
name: 'Urgent Unresolved',
|
|
185
|
+
entityType: 'tickets',
|
|
186
|
+
filters: { priority: 'urgent', status: 'open' }
|
|
187
|
+
});
|
|
188
|
+
const { data: results } = await cstar.views.execute(view.id);
|
|
189
|
+
|
|
190
|
+
// Search across everything
|
|
191
|
+
const { data: searchResults } = await cstar.search.query({
|
|
192
|
+
query: 'billing issue',
|
|
193
|
+
types: ['tickets', 'customers']
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Client-Side: Chat Widget SDK
|
|
200
|
+
|
|
201
|
+
Build custom chat experiences in the browser. Uses a publishable key — safe for frontend code.
|
|
51
202
|
|
|
52
203
|
```typescript
|
|
53
204
|
import { ChatClient } from '@cstar.help/js/chat';
|
|
@@ -66,7 +217,7 @@ const { conversations } = await chat.conversations.list();
|
|
|
66
217
|
// Send a message
|
|
67
218
|
await chat.messages.send('tkt_abc123', 'Thanks for the help!');
|
|
68
219
|
|
|
69
|
-
// Subscribe to new messages
|
|
220
|
+
// Subscribe to new messages
|
|
70
221
|
const unsubscribe = chat.onMessage('tkt_abc123', (message) => {
|
|
71
222
|
console.log(`${message.sender_name}: ${message.content}`);
|
|
72
223
|
});
|
|
@@ -75,33 +226,48 @@ const unsubscribe = chat.onMessage('tkt_abc123', (message) => {
|
|
|
75
226
|
chat.disconnect();
|
|
76
227
|
```
|
|
77
228
|
|
|
78
|
-
|
|
229
|
+
---
|
|
79
230
|
|
|
80
|
-
|
|
231
|
+
## Client-Side: Public Knowledge Base
|
|
232
|
+
|
|
233
|
+
Search and browse your public help center — **no authentication required**.
|
|
81
234
|
|
|
82
235
|
```typescript
|
|
83
236
|
import { LibraryClient } from '@cstar.help/js/library';
|
|
84
237
|
|
|
85
238
|
const library = new LibraryClient({ teamSlug: 'acme' });
|
|
86
239
|
|
|
87
|
-
// List categories
|
|
88
240
|
const categories = await library.categories();
|
|
89
|
-
|
|
90
|
-
// Search articles
|
|
91
241
|
const results = await library.search('reset password');
|
|
92
|
-
|
|
93
|
-
// Get a specific article
|
|
94
242
|
const article = await library.article('how-to-reset-password');
|
|
95
243
|
```
|
|
96
244
|
|
|
97
|
-
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Client-Side: Public Community
|
|
248
|
+
|
|
249
|
+
Browse your public community forum — **no authentication required**.
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { CommunityClient } from '@cstar.help/js/community';
|
|
253
|
+
|
|
254
|
+
const community = new CommunityClient({ teamSlug: 'acme' });
|
|
255
|
+
|
|
256
|
+
const topics = await community.topics();
|
|
257
|
+
const { posts } = await community.posts({ topicSlug: 'feature-requests', sort: 'votes' });
|
|
258
|
+
const { post, comments } = await community.post('dark-mode-support');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Server-Side: Webhook Verification
|
|
98
264
|
|
|
99
265
|
Verify incoming webhook signatures on your server.
|
|
100
266
|
|
|
101
267
|
```typescript
|
|
102
268
|
import { constructEvent } from '@cstar.help/js/webhook';
|
|
103
269
|
|
|
104
|
-
// In your webhook handler
|
|
270
|
+
// In your webhook handler
|
|
105
271
|
const event = constructEvent(rawBody, signature, 'whsec_your_secret');
|
|
106
272
|
|
|
107
273
|
switch (event.type) {
|
|
@@ -114,31 +280,20 @@ switch (event.type) {
|
|
|
114
280
|
}
|
|
115
281
|
```
|
|
116
282
|
|
|
117
|
-
For edge
|
|
283
|
+
For edge runtimes (Cloudflare Workers, Deno), use the async variant:
|
|
118
284
|
|
|
119
285
|
```typescript
|
|
120
286
|
import { constructEventAsync } from '@cstar.help/js/webhook';
|
|
121
|
-
|
|
122
287
|
const event = await constructEventAsync(rawBody, signature, secret);
|
|
123
288
|
```
|
|
124
289
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
### CStarClient
|
|
128
|
-
|
|
129
|
-
| Resource | Methods |
|
|
130
|
-
| ------------------------ | ----------------------------------------------------------------------------------------------- |
|
|
131
|
-
| `cstar.tickets` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
132
|
-
| `cstar.tickets.messages` | `.list(ticketId)` `.create(ticketId, params)` |
|
|
133
|
-
| `cstar.customers` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
134
|
-
| `cstar.articles` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
|
|
135
|
-
| `cstar.webhooks` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.test(id)` |
|
|
290
|
+
---
|
|
136
291
|
|
|
137
|
-
|
|
292
|
+
## Configuration
|
|
138
293
|
|
|
139
294
|
```typescript
|
|
140
295
|
const cstar = new CStarClient({
|
|
141
|
-
apiKey: 'sk_live_...', // Required —
|
|
296
|
+
apiKey: 'sk_live_...', // Required — must be a secret key (sk_*)
|
|
142
297
|
teamId: 'tm_...', // Required — your team ID
|
|
143
298
|
baseUrl: 'https://...', // Optional — defaults to https://www.cstar.help
|
|
144
299
|
version: '2026-03-01', // Optional — API version header
|
|
@@ -147,26 +302,32 @@ const cstar = new CStarClient({
|
|
|
147
302
|
});
|
|
148
303
|
```
|
|
149
304
|
|
|
150
|
-
|
|
305
|
+
## Test Mode
|
|
151
306
|
|
|
152
307
|
Test mode is auto-detected from your API key prefix:
|
|
153
308
|
|
|
154
309
|
```typescript
|
|
155
|
-
// Uses test data — no real customers affected
|
|
156
310
|
const cstar = new CStarClient({
|
|
157
311
|
apiKey: 'sk_test_abc123...',
|
|
158
312
|
teamId: 'tm_your_team_id'
|
|
159
313
|
});
|
|
160
314
|
|
|
161
315
|
console.log(cstar.isTestMode); // true
|
|
316
|
+
// All operations use test data — no real customers affected
|
|
162
317
|
```
|
|
163
318
|
|
|
164
|
-
|
|
319
|
+
## Error Handling
|
|
165
320
|
|
|
166
321
|
All API errors throw typed exceptions:
|
|
167
322
|
|
|
168
323
|
```typescript
|
|
169
|
-
import {
|
|
324
|
+
import {
|
|
325
|
+
CStarError,
|
|
326
|
+
CStarAuthenticationError,
|
|
327
|
+
CStarRateLimitError,
|
|
328
|
+
CStarNotFoundError,
|
|
329
|
+
CStarValidationError
|
|
330
|
+
} from '@cstar.help/js';
|
|
170
331
|
|
|
171
332
|
try {
|
|
172
333
|
await cstar.tickets.get('tkt_nonexistent');
|
|
@@ -175,15 +336,19 @@ try {
|
|
|
175
336
|
console.log('Ticket not found:', err.message);
|
|
176
337
|
} else if (err instanceof CStarValidationError) {
|
|
177
338
|
console.log('Invalid param:', err.param);
|
|
339
|
+
} else if (err instanceof CStarRateLimitError) {
|
|
340
|
+
console.log('Rate limited, retry after:', err.retryAfter, 'seconds');
|
|
341
|
+
} else if (err instanceof CStarAuthenticationError) {
|
|
342
|
+
console.log('Bad API key');
|
|
178
343
|
} else if (err instanceof CStarError) {
|
|
179
344
|
console.log('API error:', err.code, err.statusCode);
|
|
180
345
|
}
|
|
181
346
|
}
|
|
182
347
|
```
|
|
183
348
|
|
|
184
|
-
|
|
349
|
+
## Idempotency
|
|
185
350
|
|
|
186
|
-
Safely retry create operations:
|
|
351
|
+
Safely retry create/update operations:
|
|
187
352
|
|
|
188
353
|
```typescript
|
|
189
354
|
const { data: ticket } = await cstar.tickets.create(
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/community/index.ts
|
|
21
|
+
var community_exports = {};
|
|
22
|
+
__export(community_exports, {
|
|
23
|
+
CommunityClient: () => CommunityClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(community_exports);
|
|
26
|
+
var DEFAULT_BASE_URL = "https://www.cstar.help";
|
|
27
|
+
var CommunityClient = class {
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
30
|
+
this.teamSlug = config.teamSlug;
|
|
31
|
+
}
|
|
32
|
+
/** List all public community topics. */
|
|
33
|
+
async topics() {
|
|
34
|
+
const response = await this.fetch(
|
|
35
|
+
`/api/community/${this.teamSlug}/topics`
|
|
36
|
+
);
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
/** List public posts, optionally filtered by topic, status, or sort order. */
|
|
40
|
+
async posts(params) {
|
|
41
|
+
const query = {};
|
|
42
|
+
if (params?.topicSlug) query.topicSlug = params.topicSlug;
|
|
43
|
+
if (params?.status) query.status = params.status;
|
|
44
|
+
if (params?.sort) query.sort = params.sort;
|
|
45
|
+
if (params?.limit) query.limit = String(params.limit);
|
|
46
|
+
if (params?.offset) query.offset = String(params.offset);
|
|
47
|
+
const response = await this.fetch(
|
|
48
|
+
`/api/community/${this.teamSlug}/posts`,
|
|
49
|
+
query
|
|
50
|
+
);
|
|
51
|
+
return { posts: response.data, count: response.count };
|
|
52
|
+
}
|
|
53
|
+
/** Get a single post by slug, including all comments. */
|
|
54
|
+
async post(slug) {
|
|
55
|
+
const response = await this.fetch(
|
|
56
|
+
`/api/community/${this.teamSlug}/posts/${slug}`
|
|
57
|
+
);
|
|
58
|
+
return response.data;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Full-text search across post titles and bodies.
|
|
62
|
+
* Returns matching posts with relevance ranking.
|
|
63
|
+
*/
|
|
64
|
+
async search(query) {
|
|
65
|
+
return this.fetch(`/api/community/${this.teamSlug}/search`, {
|
|
66
|
+
q: query
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async fetch(path, query) {
|
|
70
|
+
let url = `${this.baseUrl}${path}`;
|
|
71
|
+
if (query) {
|
|
72
|
+
const params = new URLSearchParams();
|
|
73
|
+
for (const [key, value] of Object.entries(query)) {
|
|
74
|
+
if (value !== void 0) params.set(key, value);
|
|
75
|
+
}
|
|
76
|
+
const qs = params.toString();
|
|
77
|
+
if (qs) url += `?${qs}`;
|
|
78
|
+
}
|
|
79
|
+
const response = await globalThis.fetch(url, {
|
|
80
|
+
method: "GET",
|
|
81
|
+
headers: { "Content-Type": "application/json" }
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const errorBody = await response.json().catch(() => ({ error: { message: "Request failed" } }));
|
|
85
|
+
const message = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message ?? `Community API error: ${response.status}`;
|
|
86
|
+
throw new Error(message);
|
|
87
|
+
}
|
|
88
|
+
return response.json();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
92
|
+
0 && (module.exports = {
|
|
93
|
+
CommunityClient
|
|
94
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** Configuration for the CommunityClient. */
|
|
2
|
+
interface CommunityConfig {
|
|
3
|
+
/** Team slug (e.g., 'acme'). Identifies the community to query. */
|
|
4
|
+
teamSlug: string;
|
|
5
|
+
/** Override the base URL (defaults to https://www.cstar.help). */
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
/** A discussion topic/category in the community. */
|
|
9
|
+
interface CommunityTopic {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
slug: string;
|
|
13
|
+
description: string | null;
|
|
14
|
+
icon: string;
|
|
15
|
+
visibility: 'public' | 'members_only';
|
|
16
|
+
sort_order: number;
|
|
17
|
+
}
|
|
18
|
+
/** A public community post. */
|
|
19
|
+
interface CommunityPost {
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
body: string;
|
|
24
|
+
status: 'open' | 'answered' | 'officially_answered' | 'planned' | 'not_planned' | 'completed' | 'under_review';
|
|
25
|
+
visibility: 'public' | 'members_only';
|
|
26
|
+
voteCount: number;
|
|
27
|
+
commentCount: number;
|
|
28
|
+
isPinned: boolean;
|
|
29
|
+
isFeatured: boolean;
|
|
30
|
+
isLocked: boolean;
|
|
31
|
+
commentsEnabled: boolean;
|
|
32
|
+
topicName: string;
|
|
33
|
+
topicSlug: string;
|
|
34
|
+
authorName: string;
|
|
35
|
+
authorAvatar: string;
|
|
36
|
+
authorBio: string;
|
|
37
|
+
authorPostCount: number;
|
|
38
|
+
authorCommentCount: number;
|
|
39
|
+
isTeamMember: boolean;
|
|
40
|
+
lastActivityAt: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
}
|
|
43
|
+
/** A comment on a community post. */
|
|
44
|
+
interface CommunityComment {
|
|
45
|
+
id: string;
|
|
46
|
+
body: string;
|
|
47
|
+
isOfficial: boolean;
|
|
48
|
+
voteScore: number;
|
|
49
|
+
parentCommentId: string | null;
|
|
50
|
+
authorName: string;
|
|
51
|
+
authorAvatar: string;
|
|
52
|
+
authorBio: string;
|
|
53
|
+
authorPostCount: number;
|
|
54
|
+
authorCommentCount: number;
|
|
55
|
+
isTeamMember: boolean;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
}
|
|
58
|
+
/** Parameters for listing posts. */
|
|
59
|
+
interface CommunityPostListParams {
|
|
60
|
+
/** Filter by topic slug. */
|
|
61
|
+
topicSlug?: string;
|
|
62
|
+
/** Filter by status. */
|
|
63
|
+
status?: string;
|
|
64
|
+
/** Sort order (default: 'recent'). */
|
|
65
|
+
sort?: 'recent' | 'votes' | 'comments';
|
|
66
|
+
/** Max results per page. */
|
|
67
|
+
limit?: number;
|
|
68
|
+
/** Pagination offset. */
|
|
69
|
+
offset?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Search results. */
|
|
72
|
+
interface CommunitySearchResult {
|
|
73
|
+
data: CommunityPost[];
|
|
74
|
+
count: number;
|
|
75
|
+
query: string;
|
|
76
|
+
}
|
|
77
|
+
/** A single post with its comments. */
|
|
78
|
+
interface CommunityPostDetail {
|
|
79
|
+
post: CommunityPost;
|
|
80
|
+
comments: CommunityComment[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Public community client. No authentication required.
|
|
85
|
+
*
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const community = new CommunityClient({ teamSlug: 'acme' });
|
|
88
|
+
* const topics = await community.topics();
|
|
89
|
+
* const posts = await community.posts({ topicSlug: 'feedback', sort: 'votes' });
|
|
90
|
+
* const post = await community.post('my-feature-request');
|
|
91
|
+
* const results = await community.search('dark mode');
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare class CommunityClient {
|
|
95
|
+
private readonly baseUrl;
|
|
96
|
+
private readonly teamSlug;
|
|
97
|
+
constructor(config: CommunityConfig);
|
|
98
|
+
/** List all public community topics. */
|
|
99
|
+
topics(): Promise<CommunityTopic[]>;
|
|
100
|
+
/** List public posts, optionally filtered by topic, status, or sort order. */
|
|
101
|
+
posts(params?: CommunityPostListParams): Promise<{
|
|
102
|
+
posts: CommunityPost[];
|
|
103
|
+
count: number;
|
|
104
|
+
}>;
|
|
105
|
+
/** Get a single post by slug, including all comments. */
|
|
106
|
+
post(slug: string): Promise<CommunityPostDetail>;
|
|
107
|
+
/**
|
|
108
|
+
* Full-text search across post titles and bodies.
|
|
109
|
+
* Returns matching posts with relevance ranking.
|
|
110
|
+
*/
|
|
111
|
+
search(query: string): Promise<CommunitySearchResult>;
|
|
112
|
+
private fetch;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { CommunityClient, type CommunityComment, type CommunityConfig, type CommunityPost, type CommunityPostDetail, type CommunityPostListParams, type CommunitySearchResult, type CommunityTopic };
|