@cstar.help/js 0.3.3 → 0.4.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 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
- - **Four entry points** — tree-shake what you don't need
7
+ - **Five entry points** — tree-shake what you don't need
8
8
  - **ESM + CJS** — works everywhere
9
9
 
10
10
  ## Install
@@ -94,6 +94,61 @@ const results = await library.search('reset password');
94
94
  const article = await library.article('how-to-reset-password');
95
95
  ```
96
96
 
97
+ ### Public Community
98
+
99
+ Browse and search your public community forum — no authentication required.
100
+
101
+ ```typescript
102
+ import { CommunityClient } from '@cstar.help/js/community';
103
+
104
+ const community = new CommunityClient({ teamSlug: 'acme' });
105
+
106
+ // List discussion topics
107
+ const topics = await community.topics();
108
+
109
+ // List posts (with filters)
110
+ const { posts, count } = await community.posts({
111
+ topicSlug: 'feature-requests',
112
+ sort: 'votes'
113
+ });
114
+
115
+ // Get a single post with all comments
116
+ const { post, comments } = await community.post('dark-mode-support');
117
+
118
+ // Search posts
119
+ const results = await community.search('billing');
120
+ ```
121
+
122
+ ### Server-side Community (Admin)
123
+
124
+ Manage community posts with your secret API key via `CStarClient`:
125
+
126
+ ```typescript
127
+ const cstar = new CStarClient({ apiKey: 'sk_live_...', teamId: 'tm_...' });
128
+
129
+ // List all posts (including hidden/unapproved)
130
+ const { data: posts } = await cstar.community.posts.list({ status: 'open' });
131
+
132
+ // Create a post
133
+ const { data: post } = await cstar.community.posts.create({
134
+ title: 'New Feature: Dark Mode',
135
+ body: 'We just shipped dark mode!',
136
+ topicId: 'topic_abc123'
137
+ });
138
+
139
+ // Toggle vote on a post
140
+ const { voted, voteCount } = await cstar.community.posts.vote('post_id');
141
+
142
+ // Add a comment
143
+ const comment = await cstar.community.posts.createComment('post_id', {
144
+ body: 'Great idea!',
145
+ isOfficial: true
146
+ });
147
+
148
+ // List topics
149
+ const { data: topics } = await cstar.community.topics.list();
150
+ ```
151
+
97
152
  ### Webhook Verification
98
153
 
99
154
  Verify incoming webhook signatures on your server.
@@ -126,13 +181,15 @@ const event = await constructEventAsync(rawBody, signature, secret);
126
181
 
127
182
  ### CStarClient
128
183
 
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)` |
184
+ | Resource | Methods |
185
+ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
186
+ | `cstar.tickets` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
187
+ | `cstar.tickets.messages` | `.list(ticketId)` `.create(ticketId, params)` |
188
+ | `cstar.customers` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
189
+ | `cstar.articles` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.listAutoPaginating()` |
190
+ | `cstar.webhooks` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.test(id)` |
191
+ | `cstar.community.posts` | `.list()` `.get(id)` `.create(params)` `.update(id, params)` `.del(id)` `.vote(id)` `.follow(id)` `.listComments(id)` `.createComment(id, params)` |
192
+ | `cstar.community.topics` | `.list()` `.get(id)` |
136
193
 
137
194
  ### Configuration
138
195
 
@@ -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 };
@@ -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 };
@@ -0,0 +1,69 @@
1
+ // src/community/index.ts
2
+ var DEFAULT_BASE_URL = "https://www.cstar.help";
3
+ var CommunityClient = class {
4
+ constructor(config) {
5
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
6
+ this.teamSlug = config.teamSlug;
7
+ }
8
+ /** List all public community topics. */
9
+ async topics() {
10
+ const response = await this.fetch(
11
+ `/api/community/${this.teamSlug}/topics`
12
+ );
13
+ return response.data;
14
+ }
15
+ /** List public posts, optionally filtered by topic, status, or sort order. */
16
+ async posts(params) {
17
+ const query = {};
18
+ if (params?.topicSlug) query.topicSlug = params.topicSlug;
19
+ if (params?.status) query.status = params.status;
20
+ if (params?.sort) query.sort = params.sort;
21
+ if (params?.limit) query.limit = String(params.limit);
22
+ if (params?.offset) query.offset = String(params.offset);
23
+ const response = await this.fetch(
24
+ `/api/community/${this.teamSlug}/posts`,
25
+ query
26
+ );
27
+ return { posts: response.data, count: response.count };
28
+ }
29
+ /** Get a single post by slug, including all comments. */
30
+ async post(slug) {
31
+ const response = await this.fetch(
32
+ `/api/community/${this.teamSlug}/posts/${slug}`
33
+ );
34
+ return response.data;
35
+ }
36
+ /**
37
+ * Full-text search across post titles and bodies.
38
+ * Returns matching posts with relevance ranking.
39
+ */
40
+ async search(query) {
41
+ return this.fetch(`/api/community/${this.teamSlug}/search`, {
42
+ q: query
43
+ });
44
+ }
45
+ async fetch(path, query) {
46
+ let url = `${this.baseUrl}${path}`;
47
+ if (query) {
48
+ const params = new URLSearchParams();
49
+ for (const [key, value] of Object.entries(query)) {
50
+ if (value !== void 0) params.set(key, value);
51
+ }
52
+ const qs = params.toString();
53
+ if (qs) url += `?${qs}`;
54
+ }
55
+ const response = await globalThis.fetch(url, {
56
+ method: "GET",
57
+ headers: { "Content-Type": "application/json" }
58
+ });
59
+ if (!response.ok) {
60
+ const errorBody = await response.json().catch(() => ({ error: { message: "Request failed" } }));
61
+ const message = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message ?? `Community API error: ${response.status}`;
62
+ throw new Error(message);
63
+ }
64
+ return response.json();
65
+ }
66
+ };
67
+ export {
68
+ CommunityClient
69
+ };
package/dist/index.cjs CHANGED
@@ -137,7 +137,13 @@ var HttpClient = class {
137
137
  signal: AbortSignal.timeout(this.config.timeout)
138
138
  });
139
139
  } catch (err) {
140
- lastError = err instanceof Error ? err : new Error(String(err));
140
+ const networkErr = err instanceof Error ? err : new Error(String(err));
141
+ lastError = new CStarError(0, {
142
+ type: "connection_error",
143
+ code: "network_error",
144
+ message: `Network request failed: ${networkErr.message}`,
145
+ doc_url: "https://www.cstar.help/developers/errors#connection-errors"
146
+ });
141
147
  if (attempt < this.config.maxRetries) continue;
142
148
  throw lastError;
143
149
  }
@@ -335,6 +341,49 @@ var CategoriesResource = class extends BaseResource {
335
341
  }
336
342
  };
337
343
 
344
+ // src/resources/communityPosts.ts
345
+ var CommunityPostsResource = class extends BaseResource {
346
+ constructor(client) {
347
+ super(client, "/community/posts");
348
+ }
349
+ /** Toggle vote on a post. Returns new vote state and count. */
350
+ async vote(postId) {
351
+ return this.client.request(
352
+ "POST",
353
+ `${this.basePath}/${postId}/vote`
354
+ );
355
+ }
356
+ /** Toggle follow on a post. Returns new follow state. */
357
+ async follow(postId) {
358
+ return this.client.request(
359
+ "POST",
360
+ `${this.basePath}/${postId}/follow`
361
+ );
362
+ }
363
+ /** List all comments on a post. */
364
+ async listComments(postId) {
365
+ return this.client.request(
366
+ "GET",
367
+ `${this.basePath}/${postId}/comments`
368
+ );
369
+ }
370
+ /** Add a comment to a post. */
371
+ async createComment(postId, params) {
372
+ return this.client.request(
373
+ "POST",
374
+ `${this.basePath}/${postId}/comments`,
375
+ { body: params }
376
+ );
377
+ }
378
+ };
379
+
380
+ // src/resources/communityTopics.ts
381
+ var CommunityTopicsResource = class extends BaseResource {
382
+ constructor(client) {
383
+ super(client, "/community/topics");
384
+ }
385
+ };
386
+
338
387
  // src/index.ts
339
388
  var CStarClient = class {
340
389
  constructor(config) {
@@ -344,6 +393,10 @@ var CStarClient = class {
344
393
  this.articles = new ArticlesResource(this.client);
345
394
  this.webhooks = new WebhooksResource(this.client);
346
395
  this.categories = new CategoriesResource(this.client);
396
+ this.community = {
397
+ posts: new CommunityPostsResource(this.client),
398
+ topics: new CommunityTopicsResource(this.client)
399
+ };
347
400
  }
348
401
  /** Whether this client is using test mode keys (sk_test_* or pk_test_*). */
349
402
  get isTestMode() {
package/dist/index.d.cts CHANGED
@@ -471,6 +471,107 @@ declare class CategoriesResource extends BaseResource<Category, CategoryListPara
471
471
  constructor(client: HttpClient);
472
472
  }
473
473
 
474
+ /** A community discussion topic (category/board). */
475
+ interface CommunityTopic {
476
+ id: string;
477
+ name: string;
478
+ slug: string;
479
+ description: string | null;
480
+ icon: string;
481
+ visibility: 'public' | 'members_only';
482
+ sortOrder: number;
483
+ postCount: number;
484
+ createdAt: string;
485
+ }
486
+ /** A community discussion post. */
487
+ interface CommunityPost {
488
+ id: string;
489
+ topicId: string;
490
+ topicName: string;
491
+ title: string;
492
+ slug: string;
493
+ body: string | null;
494
+ status: 'open' | 'answered' | 'officially_answered' | 'planned' | 'not_planned' | 'completed' | 'under_review';
495
+ visibility: 'public' | 'members_only';
496
+ voteCount: number;
497
+ commentCount: number;
498
+ isPinned: boolean;
499
+ isFeatured: boolean;
500
+ isLocked: boolean;
501
+ commentsEnabled: boolean;
502
+ authorName: string;
503
+ lastActivityAt: string;
504
+ createdAt: string;
505
+ updatedAt: string;
506
+ }
507
+ /** A comment on a community post. */
508
+ interface CommunityComment {
509
+ id: string;
510
+ postId: string;
511
+ body: string;
512
+ isOfficial: boolean;
513
+ voteScore: number;
514
+ authorName: string;
515
+ parentCommentId: string | null;
516
+ createdAt: string;
517
+ }
518
+ /** Query parameters for listing community posts. */
519
+ interface CommunityPostListParams {
520
+ topicId?: string;
521
+ status?: string;
522
+ sort?: 'recent' | 'votes' | 'comments';
523
+ page?: number;
524
+ pageSize?: number;
525
+ }
526
+ /** Parameters for creating a community post. */
527
+ interface CommunityPostCreateParams {
528
+ title: string;
529
+ body?: string;
530
+ topicId: string;
531
+ visibility?: 'public' | 'members_only';
532
+ }
533
+ /** Parameters for updating a community post. */
534
+ interface CommunityPostUpdateParams {
535
+ title?: string;
536
+ body?: string;
537
+ topicId?: string;
538
+ status?: string;
539
+ visibility?: string;
540
+ isPinned?: boolean;
541
+ isLocked?: boolean;
542
+ isHidden?: boolean;
543
+ commentsEnabled?: boolean;
544
+ }
545
+ /** Parameters for creating a comment on a community post. */
546
+ interface CommunityCommentCreateParams {
547
+ body: string;
548
+ parentCommentId?: string;
549
+ isOfficial?: boolean;
550
+ }
551
+
552
+ /** Manage community discussion posts. */
553
+ declare class CommunityPostsResource extends BaseResource<CommunityPost, CommunityPostListParams, CommunityPostCreateParams, CommunityPostUpdateParams> {
554
+ constructor(client: HttpClient);
555
+ /** Toggle vote on a post. Returns new vote state and count. */
556
+ vote(postId: string): Promise<ApiResponse<{
557
+ voted: boolean;
558
+ voteCount: number;
559
+ }>>;
560
+ /** Toggle follow on a post. Returns new follow state. */
561
+ follow(postId: string): Promise<ApiResponse<{
562
+ following: boolean;
563
+ }>>;
564
+ /** List all comments on a post. */
565
+ listComments(postId: string): Promise<ApiResponse<CommunityComment[]>>;
566
+ /** Add a comment to a post. */
567
+ createComment(postId: string, params: CommunityCommentCreateParams): Promise<ApiResponse<CommunityComment>>;
568
+ }
569
+
570
+ /** Manage community discussion topics. */
571
+ declare class CommunityTopicsResource extends BaseResource<CommunityTopic, Record<string, never>, never, never> {
572
+ constructor(client: HttpClient);
573
+ }
574
+
474
575
  /** Error type constants matching the cStar API. */
475
576
  declare const ErrorType: {
476
577
  readonly AUTHENTICATION_ERROR: "authentication_error";
@@ -554,10 +655,15 @@ declare class CStarClient {
554
655
  readonly webhooks: WebhooksResource;
555
656
  /** Manage article categories. */
556
657
  readonly categories: CategoriesResource;
658
+ /** Manage community posts and topics. */
659
+ readonly community: {
660
+ readonly posts: CommunityPostsResource;
661
+ readonly topics: CommunityTopicsResource;
662
+ };
557
663
  private readonly client;
558
664
  constructor(config: CStarClientConfig);
559
665
  /** Whether this client is using test mode keys (sk_test_* or pk_test_*). */
560
666
  get isTestMode(): boolean;
561
667
  }
562
668
 
563
- export { type ApiErrorBody, type ApiResponse, type Article, type ArticleCreateParams, type ArticleListParams, type ArticleUpdateParams, CStarAuthenticationError, CStarClient, type CStarClientConfig, CStarError, CStarNotFoundError, CStarRateLimitError, CStarValidationError, type Category, type CategoryCreateParams, type CategoryListParams, type CategoryUpdateParams, type Customer, type CustomerCreateParams, type CustomerListParams, type CustomerUpdateParams, type DeleteResponse, ErrorType, type ListResponse, type Message, type MessageCreateParams, type Metadata, type PaginationInfo, type PaginationParams, type RequestOptions, type Ticket, type TicketCreateParams, type TicketCustomerSummary, type TicketListParams, type TicketUpdateParams, type Webhook, type WebhookCreateParams, type WebhookEvent, type WebhookEventData, type WebhookEventType, type WebhookListParams, type WebhookTestResult, type WebhookUpdateParams };
669
+ export { type ApiErrorBody, type ApiResponse, type Article, type ArticleCreateParams, type ArticleListParams, type ArticleUpdateParams, CStarAuthenticationError, CStarClient, type CStarClientConfig, CStarError, CStarNotFoundError, CStarRateLimitError, CStarValidationError, type Category, type CategoryCreateParams, type CategoryListParams, type CategoryUpdateParams, type CommunityComment, type CommunityCommentCreateParams, type CommunityPost, type CommunityPostCreateParams, type CommunityPostListParams, type CommunityPostUpdateParams, type CommunityTopic, type Customer, type CustomerCreateParams, type CustomerListParams, type CustomerUpdateParams, type DeleteResponse, ErrorType, type ListResponse, type Message, type MessageCreateParams, type Metadata, type PaginationInfo, type PaginationParams, type RequestOptions, type Ticket, type TicketCreateParams, type TicketCustomerSummary, type TicketListParams, type TicketUpdateParams, type Webhook, type WebhookCreateParams, type WebhookEvent, type WebhookEventData, type WebhookEventType, type WebhookListParams, type WebhookTestResult, type WebhookUpdateParams };
package/dist/index.d.ts CHANGED
@@ -471,6 +471,107 @@ declare class CategoriesResource extends BaseResource<Category, CategoryListPara
471
471
  constructor(client: HttpClient);
472
472
  }
473
473
 
474
+ /** A community discussion topic (category/board). */
475
+ interface CommunityTopic {
476
+ id: string;
477
+ name: string;
478
+ slug: string;
479
+ description: string | null;
480
+ icon: string;
481
+ visibility: 'public' | 'members_only';
482
+ sortOrder: number;
483
+ postCount: number;
484
+ createdAt: string;
485
+ }
486
+ /** A community discussion post. */
487
+ interface CommunityPost {
488
+ id: string;
489
+ topicId: string;
490
+ topicName: string;
491
+ title: string;
492
+ slug: string;
493
+ body: string | null;
494
+ status: 'open' | 'answered' | 'officially_answered' | 'planned' | 'not_planned' | 'completed' | 'under_review';
495
+ visibility: 'public' | 'members_only';
496
+ voteCount: number;
497
+ commentCount: number;
498
+ isPinned: boolean;
499
+ isFeatured: boolean;
500
+ isLocked: boolean;
501
+ commentsEnabled: boolean;
502
+ authorName: string;
503
+ lastActivityAt: string;
504
+ createdAt: string;
505
+ updatedAt: string;
506
+ }
507
+ /** A comment on a community post. */
508
+ interface CommunityComment {
509
+ id: string;
510
+ postId: string;
511
+ body: string;
512
+ isOfficial: boolean;
513
+ voteScore: number;
514
+ authorName: string;
515
+ parentCommentId: string | null;
516
+ createdAt: string;
517
+ }
518
+ /** Query parameters for listing community posts. */
519
+ interface CommunityPostListParams {
520
+ topicId?: string;
521
+ status?: string;
522
+ sort?: 'recent' | 'votes' | 'comments';
523
+ page?: number;
524
+ pageSize?: number;
525
+ }
526
+ /** Parameters for creating a community post. */
527
+ interface CommunityPostCreateParams {
528
+ title: string;
529
+ body?: string;
530
+ topicId: string;
531
+ visibility?: 'public' | 'members_only';
532
+ }
533
+ /** Parameters for updating a community post. */
534
+ interface CommunityPostUpdateParams {
535
+ title?: string;
536
+ body?: string;
537
+ topicId?: string;
538
+ status?: string;
539
+ visibility?: string;
540
+ isPinned?: boolean;
541
+ isLocked?: boolean;
542
+ isHidden?: boolean;
543
+ commentsEnabled?: boolean;
544
+ }
545
+ /** Parameters for creating a comment on a community post. */
546
+ interface CommunityCommentCreateParams {
547
+ body: string;
548
+ parentCommentId?: string;
549
+ isOfficial?: boolean;
550
+ }
551
+
552
+ /** Manage community discussion posts. */
553
+ declare class CommunityPostsResource extends BaseResource<CommunityPost, CommunityPostListParams, CommunityPostCreateParams, CommunityPostUpdateParams> {
554
+ constructor(client: HttpClient);
555
+ /** Toggle vote on a post. Returns new vote state and count. */
556
+ vote(postId: string): Promise<ApiResponse<{
557
+ voted: boolean;
558
+ voteCount: number;
559
+ }>>;
560
+ /** Toggle follow on a post. Returns new follow state. */
561
+ follow(postId: string): Promise<ApiResponse<{
562
+ following: boolean;
563
+ }>>;
564
+ /** List all comments on a post. */
565
+ listComments(postId: string): Promise<ApiResponse<CommunityComment[]>>;
566
+ /** Add a comment to a post. */
567
+ createComment(postId: string, params: CommunityCommentCreateParams): Promise<ApiResponse<CommunityComment>>;
568
+ }
569
+
570
+ /** Manage community discussion topics. */
571
+ declare class CommunityTopicsResource extends BaseResource<CommunityTopic, Record<string, never>, never, never> {
572
+ constructor(client: HttpClient);
573
+ }
574
+
474
575
  /** Error type constants matching the cStar API. */
475
576
  declare const ErrorType: {
476
577
  readonly AUTHENTICATION_ERROR: "authentication_error";
@@ -554,10 +655,15 @@ declare class CStarClient {
554
655
  readonly webhooks: WebhooksResource;
555
656
  /** Manage article categories. */
556
657
  readonly categories: CategoriesResource;
658
+ /** Manage community posts and topics. */
659
+ readonly community: {
660
+ readonly posts: CommunityPostsResource;
661
+ readonly topics: CommunityTopicsResource;
662
+ };
557
663
  private readonly client;
558
664
  constructor(config: CStarClientConfig);
559
665
  /** Whether this client is using test mode keys (sk_test_* or pk_test_*). */
560
666
  get isTestMode(): boolean;
561
667
  }
562
668
 
563
- export { type ApiErrorBody, type ApiResponse, type Article, type ArticleCreateParams, type ArticleListParams, type ArticleUpdateParams, CStarAuthenticationError, CStarClient, type CStarClientConfig, CStarError, CStarNotFoundError, CStarRateLimitError, CStarValidationError, type Category, type CategoryCreateParams, type CategoryListParams, type CategoryUpdateParams, type Customer, type CustomerCreateParams, type CustomerListParams, type CustomerUpdateParams, type DeleteResponse, ErrorType, type ListResponse, type Message, type MessageCreateParams, type Metadata, type PaginationInfo, type PaginationParams, type RequestOptions, type Ticket, type TicketCreateParams, type TicketCustomerSummary, type TicketListParams, type TicketUpdateParams, type Webhook, type WebhookCreateParams, type WebhookEvent, type WebhookEventData, type WebhookEventType, type WebhookListParams, type WebhookTestResult, type WebhookUpdateParams };
669
+ export { type ApiErrorBody, type ApiResponse, type Article, type ArticleCreateParams, type ArticleListParams, type ArticleUpdateParams, CStarAuthenticationError, CStarClient, type CStarClientConfig, CStarError, CStarNotFoundError, CStarRateLimitError, CStarValidationError, type Category, type CategoryCreateParams, type CategoryListParams, type CategoryUpdateParams, type CommunityComment, type CommunityCommentCreateParams, type CommunityPost, type CommunityPostCreateParams, type CommunityPostListParams, type CommunityPostUpdateParams, type CommunityTopic, type Customer, type CustomerCreateParams, type CustomerListParams, type CustomerUpdateParams, type DeleteResponse, ErrorType, type ListResponse, type Message, type MessageCreateParams, type Metadata, type PaginationInfo, type PaginationParams, type RequestOptions, type Ticket, type TicketCreateParams, type TicketCustomerSummary, type TicketListParams, type TicketUpdateParams, type Webhook, type WebhookCreateParams, type WebhookEvent, type WebhookEventData, type WebhookEventType, type WebhookListParams, type WebhookTestResult, type WebhookUpdateParams };
package/dist/index.js CHANGED
@@ -105,7 +105,13 @@ var HttpClient = class {
105
105
  signal: AbortSignal.timeout(this.config.timeout)
106
106
  });
107
107
  } catch (err) {
108
- lastError = err instanceof Error ? err : new Error(String(err));
108
+ const networkErr = err instanceof Error ? err : new Error(String(err));
109
+ lastError = new CStarError(0, {
110
+ type: "connection_error",
111
+ code: "network_error",
112
+ message: `Network request failed: ${networkErr.message}`,
113
+ doc_url: "https://www.cstar.help/developers/errors#connection-errors"
114
+ });
109
115
  if (attempt < this.config.maxRetries) continue;
110
116
  throw lastError;
111
117
  }
@@ -303,6 +309,49 @@ var CategoriesResource = class extends BaseResource {
303
309
  }
304
310
  };
305
311
 
312
+ // src/resources/communityPosts.ts
313
+ var CommunityPostsResource = class extends BaseResource {
314
+ constructor(client) {
315
+ super(client, "/community/posts");
316
+ }
317
+ /** Toggle vote on a post. Returns new vote state and count. */
318
+ async vote(postId) {
319
+ return this.client.request(
320
+ "POST",
321
+ `${this.basePath}/${postId}/vote`
322
+ );
323
+ }
324
+ /** Toggle follow on a post. Returns new follow state. */
325
+ async follow(postId) {
326
+ return this.client.request(
327
+ "POST",
328
+ `${this.basePath}/${postId}/follow`
329
+ );
330
+ }
331
+ /** List all comments on a post. */
332
+ async listComments(postId) {
333
+ return this.client.request(
334
+ "GET",
335
+ `${this.basePath}/${postId}/comments`
336
+ );
337
+ }
338
+ /** Add a comment to a post. */
339
+ async createComment(postId, params) {
340
+ return this.client.request(
341
+ "POST",
342
+ `${this.basePath}/${postId}/comments`,
343
+ { body: params }
344
+ );
345
+ }
346
+ };
347
+
348
+ // src/resources/communityTopics.ts
349
+ var CommunityTopicsResource = class extends BaseResource {
350
+ constructor(client) {
351
+ super(client, "/community/topics");
352
+ }
353
+ };
354
+
306
355
  // src/index.ts
307
356
  var CStarClient = class {
308
357
  constructor(config) {
@@ -312,6 +361,10 @@ var CStarClient = class {
312
361
  this.articles = new ArticlesResource(this.client);
313
362
  this.webhooks = new WebhooksResource(this.client);
314
363
  this.categories = new CategoriesResource(this.client);
364
+ this.community = {
365
+ posts: new CommunityPostsResource(this.client),
366
+ topics: new CommunityTopicsResource(this.client)
367
+ };
315
368
  }
316
369
  /** Whether this client is using test mode keys (sk_test_* or pk_test_*). */
317
370
  get isTestMode() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cstar.help/js",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Official TypeScript SDK for the cStar customer support platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -47,6 +47,16 @@
47
47
  "default": "./dist/webhook/index.cjs"
48
48
  }
49
49
  },
50
+ "./community": {
51
+ "import": {
52
+ "types": "./dist/community/index.d.ts",
53
+ "default": "./dist/community/index.js"
54
+ },
55
+ "require": {
56
+ "types": "./dist/community/index.d.cts",
57
+ "default": "./dist/community/index.cjs"
58
+ }
59
+ },
50
60
  "./auth": {
51
61
  "import": {
52
62
  "types": "./dist/auth/index.d.ts",