@cstar.help/js 0.5.0 → 0.5.1
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/dist/chat/index.cjs +79 -0
- package/dist/chat/index.d.cts +77 -0
- package/dist/chat/index.d.ts +77 -0
- package/dist/chat/index.js +79 -0
- package/dist/community/index.cjs +149 -0
- package/dist/community/index.js +149 -0
- package/dist/index.cjs +217 -27
- package/dist/index.d.cts +360 -72
- package/dist/index.d.ts +360 -72
- package/dist/index.js +217 -27
- package/package.json +1 -1
- package/dist/community/index.d.cts +0 -115
- package/dist/community/index.d.ts +0 -115
package/dist/chat/index.cjs
CHANGED
|
@@ -294,6 +294,7 @@ var ChatClient = class {
|
|
|
294
294
|
this.supabaseAnonKey = config.supabaseAnonKey;
|
|
295
295
|
this.conversations = new ConversationsApi(this);
|
|
296
296
|
this.messages = new MessagesApi(this);
|
|
297
|
+
this.community = new ChatCommunityApi(this);
|
|
297
298
|
}
|
|
298
299
|
/**
|
|
299
300
|
* Identify a customer using HMAC signature verification.
|
|
@@ -532,6 +533,84 @@ var ConversationsApi = class {
|
|
|
532
533
|
};
|
|
533
534
|
}
|
|
534
535
|
};
|
|
536
|
+
var ChatCommunityApi = class {
|
|
537
|
+
constructor(chat) {
|
|
538
|
+
this.chat = chat;
|
|
539
|
+
}
|
|
540
|
+
/** Create a new community post as the identified customer. */
|
|
541
|
+
async createPost(params) {
|
|
542
|
+
const teamId = this.chat.getTeamId();
|
|
543
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
544
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
545
|
+
method: "POST",
|
|
546
|
+
body: {
|
|
547
|
+
teamId,
|
|
548
|
+
action: "createPost",
|
|
549
|
+
title: params.title,
|
|
550
|
+
body: params.body,
|
|
551
|
+
topicId: params.topicId
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
return response.data.post;
|
|
555
|
+
}
|
|
556
|
+
/** Toggle vote on a post. Returns new vote state and count. */
|
|
557
|
+
async vote(postId) {
|
|
558
|
+
const teamId = this.chat.getTeamId();
|
|
559
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
560
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
561
|
+
method: "POST",
|
|
562
|
+
body: { teamId, action: "vote", postId }
|
|
563
|
+
});
|
|
564
|
+
return response.data;
|
|
565
|
+
}
|
|
566
|
+
/** Add a comment to a post. Supports 1-level nesting via parentCommentId. */
|
|
567
|
+
async comment(postId, params) {
|
|
568
|
+
const teamId = this.chat.getTeamId();
|
|
569
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
570
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
571
|
+
method: "POST",
|
|
572
|
+
body: {
|
|
573
|
+
teamId,
|
|
574
|
+
action: "createComment",
|
|
575
|
+
postId,
|
|
576
|
+
commentBody: params.body,
|
|
577
|
+
parentCommentId: params.parentCommentId ?? null
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
return response.data.comment;
|
|
581
|
+
}
|
|
582
|
+
/** Toggle follow on a post. */
|
|
583
|
+
async follow(postId) {
|
|
584
|
+
const teamId = this.chat.getTeamId();
|
|
585
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
586
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
587
|
+
method: "POST",
|
|
588
|
+
body: { teamId, action: "follow", postId }
|
|
589
|
+
});
|
|
590
|
+
return response.data;
|
|
591
|
+
}
|
|
592
|
+
/** Check if the current user has voted on a post. */
|
|
593
|
+
async getVoteStatus(postId) {
|
|
594
|
+
const teamId = this.chat.getTeamId();
|
|
595
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
596
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
597
|
+
method: "GET",
|
|
598
|
+
query: { teamId, postId }
|
|
599
|
+
});
|
|
600
|
+
return response.data.voted;
|
|
601
|
+
}
|
|
602
|
+
/** Check vote status for multiple posts in one request. */
|
|
603
|
+
async bulkVoteStatus(postIds) {
|
|
604
|
+
if (postIds.length === 0) return {};
|
|
605
|
+
const teamId = this.chat.getTeamId();
|
|
606
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
607
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
608
|
+
method: "GET",
|
|
609
|
+
query: { teamId, postIds: postIds.join(",") }
|
|
610
|
+
});
|
|
611
|
+
return response.data;
|
|
612
|
+
}
|
|
613
|
+
};
|
|
535
614
|
var MessagesApi = class {
|
|
536
615
|
constructor(chat) {
|
|
537
616
|
this.chat = chat;
|
package/dist/chat/index.d.cts
CHANGED
|
@@ -97,6 +97,61 @@ type MessageCallback = (message: WidgetMessage) => void;
|
|
|
97
97
|
/** Callback for typing indicator events. */
|
|
98
98
|
type TypingCallback = (payload: TypingPayload) => void;
|
|
99
99
|
|
|
100
|
+
/** Parameters for creating a post as an identified customer. */
|
|
101
|
+
interface CommunityCreatePostParams {
|
|
102
|
+
/** Post title. */
|
|
103
|
+
title: string;
|
|
104
|
+
/** Post body/content (optional). */
|
|
105
|
+
body?: string;
|
|
106
|
+
/** Topic UUID to post in. */
|
|
107
|
+
topicId: string;
|
|
108
|
+
}
|
|
109
|
+
/** Parameters for creating a comment as an identified customer. */
|
|
110
|
+
interface CommunityCreateCommentParams {
|
|
111
|
+
/** Comment body text. */
|
|
112
|
+
body: string;
|
|
113
|
+
/** Parent comment ID for replies (optional, 1-level nesting). */
|
|
114
|
+
parentCommentId?: string | null;
|
|
115
|
+
}
|
|
116
|
+
/** Response from creating a post. */
|
|
117
|
+
interface CommunityCreatedPost {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
slug: string;
|
|
121
|
+
body: string;
|
|
122
|
+
status: string;
|
|
123
|
+
visibility: string;
|
|
124
|
+
voteCount: number;
|
|
125
|
+
commentCount: number;
|
|
126
|
+
topicName: string;
|
|
127
|
+
topicSlug: string;
|
|
128
|
+
authorName: string;
|
|
129
|
+
authorAvatar: string;
|
|
130
|
+
isTeamMember: boolean;
|
|
131
|
+
createdAt: string;
|
|
132
|
+
}
|
|
133
|
+
/** Response from creating a comment. */
|
|
134
|
+
interface CommunityCreatedComment {
|
|
135
|
+
id: string;
|
|
136
|
+
body: string;
|
|
137
|
+
isOfficial: boolean;
|
|
138
|
+
voteScore: number;
|
|
139
|
+
parentCommentId: string | null;
|
|
140
|
+
authorName: string;
|
|
141
|
+
authorAvatar: string;
|
|
142
|
+
isTeamMember: boolean;
|
|
143
|
+
createdAt: string;
|
|
144
|
+
}
|
|
145
|
+
/** Response from toggling a vote. */
|
|
146
|
+
interface CommunityVoteResult {
|
|
147
|
+
voted: boolean;
|
|
148
|
+
voteCount: number;
|
|
149
|
+
}
|
|
150
|
+
/** Response from toggling a follow. */
|
|
151
|
+
interface CommunityFollowResult {
|
|
152
|
+
following: boolean;
|
|
153
|
+
}
|
|
154
|
+
|
|
100
155
|
/**
|
|
101
156
|
* Customer-facing chat client for the cStar widget API.
|
|
102
157
|
*
|
|
@@ -136,6 +191,8 @@ declare class ChatClient {
|
|
|
136
191
|
readonly conversations: ConversationsApi;
|
|
137
192
|
/** Sub-resource for managing messages. */
|
|
138
193
|
readonly messages: MessagesApi;
|
|
194
|
+
/** Sub-resource for community actions (create posts, vote, comment). Uses the same session as chat. */
|
|
195
|
+
readonly community: ChatCommunityApi;
|
|
139
196
|
constructor(config: ChatConfig);
|
|
140
197
|
/**
|
|
141
198
|
* Identify a customer using HMAC signature verification.
|
|
@@ -196,6 +253,26 @@ declare class ConversationsApi {
|
|
|
196
253
|
/** Create a new conversation (ticket). */
|
|
197
254
|
create(params: ConversationCreateParams): Promise<Conversation>;
|
|
198
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Community sub-resource on ChatClient.
|
|
258
|
+
* Uses the same session token from `identify()` to authenticate community actions.
|
|
259
|
+
*/
|
|
260
|
+
declare class ChatCommunityApi {
|
|
261
|
+
private readonly chat;
|
|
262
|
+
constructor(chat: ChatClient);
|
|
263
|
+
/** Create a new community post as the identified customer. */
|
|
264
|
+
createPost(params: CommunityCreatePostParams): Promise<CommunityCreatedPost>;
|
|
265
|
+
/** Toggle vote on a post. Returns new vote state and count. */
|
|
266
|
+
vote(postId: string): Promise<CommunityVoteResult>;
|
|
267
|
+
/** Add a comment to a post. Supports 1-level nesting via parentCommentId. */
|
|
268
|
+
comment(postId: string, params: CommunityCreateCommentParams): Promise<CommunityCreatedComment>;
|
|
269
|
+
/** Toggle follow on a post. */
|
|
270
|
+
follow(postId: string): Promise<CommunityFollowResult>;
|
|
271
|
+
/** Check if the current user has voted on a post. */
|
|
272
|
+
getVoteStatus(postId: string): Promise<boolean>;
|
|
273
|
+
/** Check vote status for multiple posts in one request. */
|
|
274
|
+
bulkVoteStatus(postIds: string[]): Promise<Record<string, boolean>>;
|
|
275
|
+
}
|
|
199
276
|
/** Messages sub-resource on ChatClient. */
|
|
200
277
|
declare class MessagesApi {
|
|
201
278
|
private readonly chat;
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -97,6 +97,61 @@ type MessageCallback = (message: WidgetMessage) => void;
|
|
|
97
97
|
/** Callback for typing indicator events. */
|
|
98
98
|
type TypingCallback = (payload: TypingPayload) => void;
|
|
99
99
|
|
|
100
|
+
/** Parameters for creating a post as an identified customer. */
|
|
101
|
+
interface CommunityCreatePostParams {
|
|
102
|
+
/** Post title. */
|
|
103
|
+
title: string;
|
|
104
|
+
/** Post body/content (optional). */
|
|
105
|
+
body?: string;
|
|
106
|
+
/** Topic UUID to post in. */
|
|
107
|
+
topicId: string;
|
|
108
|
+
}
|
|
109
|
+
/** Parameters for creating a comment as an identified customer. */
|
|
110
|
+
interface CommunityCreateCommentParams {
|
|
111
|
+
/** Comment body text. */
|
|
112
|
+
body: string;
|
|
113
|
+
/** Parent comment ID for replies (optional, 1-level nesting). */
|
|
114
|
+
parentCommentId?: string | null;
|
|
115
|
+
}
|
|
116
|
+
/** Response from creating a post. */
|
|
117
|
+
interface CommunityCreatedPost {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
slug: string;
|
|
121
|
+
body: string;
|
|
122
|
+
status: string;
|
|
123
|
+
visibility: string;
|
|
124
|
+
voteCount: number;
|
|
125
|
+
commentCount: number;
|
|
126
|
+
topicName: string;
|
|
127
|
+
topicSlug: string;
|
|
128
|
+
authorName: string;
|
|
129
|
+
authorAvatar: string;
|
|
130
|
+
isTeamMember: boolean;
|
|
131
|
+
createdAt: string;
|
|
132
|
+
}
|
|
133
|
+
/** Response from creating a comment. */
|
|
134
|
+
interface CommunityCreatedComment {
|
|
135
|
+
id: string;
|
|
136
|
+
body: string;
|
|
137
|
+
isOfficial: boolean;
|
|
138
|
+
voteScore: number;
|
|
139
|
+
parentCommentId: string | null;
|
|
140
|
+
authorName: string;
|
|
141
|
+
authorAvatar: string;
|
|
142
|
+
isTeamMember: boolean;
|
|
143
|
+
createdAt: string;
|
|
144
|
+
}
|
|
145
|
+
/** Response from toggling a vote. */
|
|
146
|
+
interface CommunityVoteResult {
|
|
147
|
+
voted: boolean;
|
|
148
|
+
voteCount: number;
|
|
149
|
+
}
|
|
150
|
+
/** Response from toggling a follow. */
|
|
151
|
+
interface CommunityFollowResult {
|
|
152
|
+
following: boolean;
|
|
153
|
+
}
|
|
154
|
+
|
|
100
155
|
/**
|
|
101
156
|
* Customer-facing chat client for the cStar widget API.
|
|
102
157
|
*
|
|
@@ -136,6 +191,8 @@ declare class ChatClient {
|
|
|
136
191
|
readonly conversations: ConversationsApi;
|
|
137
192
|
/** Sub-resource for managing messages. */
|
|
138
193
|
readonly messages: MessagesApi;
|
|
194
|
+
/** Sub-resource for community actions (create posts, vote, comment). Uses the same session as chat. */
|
|
195
|
+
readonly community: ChatCommunityApi;
|
|
139
196
|
constructor(config: ChatConfig);
|
|
140
197
|
/**
|
|
141
198
|
* Identify a customer using HMAC signature verification.
|
|
@@ -196,6 +253,26 @@ declare class ConversationsApi {
|
|
|
196
253
|
/** Create a new conversation (ticket). */
|
|
197
254
|
create(params: ConversationCreateParams): Promise<Conversation>;
|
|
198
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Community sub-resource on ChatClient.
|
|
258
|
+
* Uses the same session token from `identify()` to authenticate community actions.
|
|
259
|
+
*/
|
|
260
|
+
declare class ChatCommunityApi {
|
|
261
|
+
private readonly chat;
|
|
262
|
+
constructor(chat: ChatClient);
|
|
263
|
+
/** Create a new community post as the identified customer. */
|
|
264
|
+
createPost(params: CommunityCreatePostParams): Promise<CommunityCreatedPost>;
|
|
265
|
+
/** Toggle vote on a post. Returns new vote state and count. */
|
|
266
|
+
vote(postId: string): Promise<CommunityVoteResult>;
|
|
267
|
+
/** Add a comment to a post. Supports 1-level nesting via parentCommentId. */
|
|
268
|
+
comment(postId: string, params: CommunityCreateCommentParams): Promise<CommunityCreatedComment>;
|
|
269
|
+
/** Toggle follow on a post. */
|
|
270
|
+
follow(postId: string): Promise<CommunityFollowResult>;
|
|
271
|
+
/** Check if the current user has voted on a post. */
|
|
272
|
+
getVoteStatus(postId: string): Promise<boolean>;
|
|
273
|
+
/** Check vote status for multiple posts in one request. */
|
|
274
|
+
bulkVoteStatus(postIds: string[]): Promise<Record<string, boolean>>;
|
|
275
|
+
}
|
|
199
276
|
/** Messages sub-resource on ChatClient. */
|
|
200
277
|
declare class MessagesApi {
|
|
201
278
|
private readonly chat;
|
package/dist/chat/index.js
CHANGED
|
@@ -258,6 +258,7 @@ var ChatClient = class {
|
|
|
258
258
|
this.supabaseAnonKey = config.supabaseAnonKey;
|
|
259
259
|
this.conversations = new ConversationsApi(this);
|
|
260
260
|
this.messages = new MessagesApi(this);
|
|
261
|
+
this.community = new ChatCommunityApi(this);
|
|
261
262
|
}
|
|
262
263
|
/**
|
|
263
264
|
* Identify a customer using HMAC signature verification.
|
|
@@ -496,6 +497,84 @@ var ConversationsApi = class {
|
|
|
496
497
|
};
|
|
497
498
|
}
|
|
498
499
|
};
|
|
500
|
+
var ChatCommunityApi = class {
|
|
501
|
+
constructor(chat) {
|
|
502
|
+
this.chat = chat;
|
|
503
|
+
}
|
|
504
|
+
/** Create a new community post as the identified customer. */
|
|
505
|
+
async createPost(params) {
|
|
506
|
+
const teamId = this.chat.getTeamId();
|
|
507
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
508
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
509
|
+
method: "POST",
|
|
510
|
+
body: {
|
|
511
|
+
teamId,
|
|
512
|
+
action: "createPost",
|
|
513
|
+
title: params.title,
|
|
514
|
+
body: params.body,
|
|
515
|
+
topicId: params.topicId
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
return response.data.post;
|
|
519
|
+
}
|
|
520
|
+
/** Toggle vote on a post. Returns new vote state and count. */
|
|
521
|
+
async vote(postId) {
|
|
522
|
+
const teamId = this.chat.getTeamId();
|
|
523
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
524
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
525
|
+
method: "POST",
|
|
526
|
+
body: { teamId, action: "vote", postId }
|
|
527
|
+
});
|
|
528
|
+
return response.data;
|
|
529
|
+
}
|
|
530
|
+
/** Add a comment to a post. Supports 1-level nesting via parentCommentId. */
|
|
531
|
+
async comment(postId, params) {
|
|
532
|
+
const teamId = this.chat.getTeamId();
|
|
533
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
534
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
535
|
+
method: "POST",
|
|
536
|
+
body: {
|
|
537
|
+
teamId,
|
|
538
|
+
action: "createComment",
|
|
539
|
+
postId,
|
|
540
|
+
commentBody: params.body,
|
|
541
|
+
parentCommentId: params.parentCommentId ?? null
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
return response.data.comment;
|
|
545
|
+
}
|
|
546
|
+
/** Toggle follow on a post. */
|
|
547
|
+
async follow(postId) {
|
|
548
|
+
const teamId = this.chat.getTeamId();
|
|
549
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
550
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
551
|
+
method: "POST",
|
|
552
|
+
body: { teamId, action: "follow", postId }
|
|
553
|
+
});
|
|
554
|
+
return response.data;
|
|
555
|
+
}
|
|
556
|
+
/** Check if the current user has voted on a post. */
|
|
557
|
+
async getVoteStatus(postId) {
|
|
558
|
+
const teamId = this.chat.getTeamId();
|
|
559
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
560
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
561
|
+
method: "GET",
|
|
562
|
+
query: { teamId, postId }
|
|
563
|
+
});
|
|
564
|
+
return response.data.voted;
|
|
565
|
+
}
|
|
566
|
+
/** Check vote status for multiple posts in one request. */
|
|
567
|
+
async bulkVoteStatus(postIds) {
|
|
568
|
+
if (postIds.length === 0) return {};
|
|
569
|
+
const teamId = this.chat.getTeamId();
|
|
570
|
+
if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
|
|
571
|
+
const response = await this.chat.fetch("/api/widget/community", {
|
|
572
|
+
method: "GET",
|
|
573
|
+
query: { teamId, postIds: postIds.join(",") }
|
|
574
|
+
});
|
|
575
|
+
return response.data;
|
|
576
|
+
}
|
|
577
|
+
};
|
|
499
578
|
var MessagesApi = class {
|
|
500
579
|
constructor(chat) {
|
|
501
580
|
this.chat = chat;
|
package/dist/community/index.cjs
CHANGED
|
@@ -26,9 +26,30 @@ module.exports = __toCommonJS(community_exports);
|
|
|
26
26
|
var DEFAULT_BASE_URL = "https://www.cstar.help";
|
|
27
27
|
var CommunityClient = class {
|
|
28
28
|
constructor(config) {
|
|
29
|
+
this.sessionToken = null;
|
|
30
|
+
this.teamId = null;
|
|
29
31
|
this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
30
32
|
this.teamSlug = config.teamSlug;
|
|
31
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Set a session token from identity verification.
|
|
36
|
+
* This enables authenticated operations (create posts, vote, comment).
|
|
37
|
+
*
|
|
38
|
+
* The token is the same `sessionToken` returned by `ChatClient.identify()`.
|
|
39
|
+
*/
|
|
40
|
+
setSessionToken(token, teamId) {
|
|
41
|
+
this.sessionToken = token;
|
|
42
|
+
if (teamId) this.teamId = teamId;
|
|
43
|
+
}
|
|
44
|
+
/** Clear the session token and return to read-only mode. */
|
|
45
|
+
clearSession() {
|
|
46
|
+
this.sessionToken = null;
|
|
47
|
+
this.teamId = null;
|
|
48
|
+
}
|
|
49
|
+
/** Whether the client has an active session token. */
|
|
50
|
+
get isAuthenticated() {
|
|
51
|
+
return this.sessionToken !== null;
|
|
52
|
+
}
|
|
32
53
|
/** List all public community topics. */
|
|
33
54
|
async topics() {
|
|
34
55
|
const response = await this.fetch(
|
|
@@ -66,6 +87,134 @@ var CommunityClient = class {
|
|
|
66
87
|
q: query
|
|
67
88
|
});
|
|
68
89
|
}
|
|
90
|
+
// ── Authenticated Actions (require setSessionToken) ──
|
|
91
|
+
/**
|
|
92
|
+
* Create a new community post. Requires an active session token.
|
|
93
|
+
*
|
|
94
|
+
* @throws Error if no session token is set or the request fails
|
|
95
|
+
*/
|
|
96
|
+
async createPost(params) {
|
|
97
|
+
const teamId = this.resolveTeamId();
|
|
98
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
99
|
+
method: "POST",
|
|
100
|
+
body: {
|
|
101
|
+
teamId,
|
|
102
|
+
action: "createPost",
|
|
103
|
+
title: params.title,
|
|
104
|
+
body: params.body,
|
|
105
|
+
topicId: params.topicId
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return response.data.post;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Toggle vote on a post. Returns new vote state and count.
|
|
112
|
+
* Requires an active session token.
|
|
113
|
+
*/
|
|
114
|
+
async vote(postId) {
|
|
115
|
+
const teamId = this.resolveTeamId();
|
|
116
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
117
|
+
method: "POST",
|
|
118
|
+
body: { teamId, action: "vote", postId }
|
|
119
|
+
});
|
|
120
|
+
return response.data;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Add a comment to a post. Requires an active session token.
|
|
124
|
+
*/
|
|
125
|
+
async comment(postId, params) {
|
|
126
|
+
const teamId = this.resolveTeamId();
|
|
127
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
128
|
+
method: "POST",
|
|
129
|
+
body: {
|
|
130
|
+
teamId,
|
|
131
|
+
action: "createComment",
|
|
132
|
+
postId,
|
|
133
|
+
commentBody: params.body,
|
|
134
|
+
parentCommentId: params.parentCommentId ?? null
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return response.data.comment;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Toggle follow on a post. Requires an active session token.
|
|
141
|
+
*/
|
|
142
|
+
async follow(postId) {
|
|
143
|
+
const teamId = this.resolveTeamId();
|
|
144
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
145
|
+
method: "POST",
|
|
146
|
+
body: { teamId, action: "follow", postId }
|
|
147
|
+
});
|
|
148
|
+
return response.data;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if the current user has voted on a specific post.
|
|
152
|
+
* Requires an active session token.
|
|
153
|
+
*/
|
|
154
|
+
async getVoteStatus(postId) {
|
|
155
|
+
const teamId = this.resolveTeamId();
|
|
156
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
157
|
+
method: "GET",
|
|
158
|
+
query: { teamId, postId }
|
|
159
|
+
});
|
|
160
|
+
return response.data.voted;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check vote status for multiple posts in a single request.
|
|
164
|
+
* Returns a map of postId → voted boolean.
|
|
165
|
+
* Requires an active session token.
|
|
166
|
+
*/
|
|
167
|
+
async bulkVoteStatus(postIds) {
|
|
168
|
+
if (postIds.length === 0) return {};
|
|
169
|
+
const teamId = this.resolveTeamId();
|
|
170
|
+
const response = await this.authenticatedFetch("/api/widget/community", {
|
|
171
|
+
method: "GET",
|
|
172
|
+
query: { teamId, postIds: postIds.join(",") }
|
|
173
|
+
});
|
|
174
|
+
return response.data;
|
|
175
|
+
}
|
|
176
|
+
// ── Internal Helpers ──
|
|
177
|
+
/**
|
|
178
|
+
* Resolve team slug to team ID (cached after first call).
|
|
179
|
+
* For authenticated operations that require teamId.
|
|
180
|
+
*/
|
|
181
|
+
resolveTeamId() {
|
|
182
|
+
if (this.teamId) return this.teamId;
|
|
183
|
+
throw new Error(
|
|
184
|
+
"Team ID is required for authenticated operations. Pass it via setSessionToken(token, teamId) or use ChatClient.identify() which provides it automatically."
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
async authenticatedFetch(path, options) {
|
|
188
|
+
if (!this.sessionToken) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
"Session token required. Call setSessionToken() or use ChatClient.identify() first."
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
let url = `${this.baseUrl}${path}`;
|
|
194
|
+
if (options.query) {
|
|
195
|
+
const params = new URLSearchParams();
|
|
196
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
197
|
+
if (value !== void 0) params.set(key, value);
|
|
198
|
+
}
|
|
199
|
+
const qs = params.toString();
|
|
200
|
+
if (qs) url += `?${qs}`;
|
|
201
|
+
}
|
|
202
|
+
const headers = {
|
|
203
|
+
"Content-Type": "application/json",
|
|
204
|
+
Authorization: `Bearer ${this.sessionToken}`
|
|
205
|
+
};
|
|
206
|
+
const response = await globalThis.fetch(url, {
|
|
207
|
+
method: options.method,
|
|
208
|
+
headers,
|
|
209
|
+
body: options.body ? JSON.stringify(options.body) : void 0
|
|
210
|
+
});
|
|
211
|
+
if (!response.ok) {
|
|
212
|
+
const errorBody = await response.json().catch(() => ({ error: { message: "Request failed" } }));
|
|
213
|
+
const message = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message ?? `Community API error: ${response.status}`;
|
|
214
|
+
throw new Error(message);
|
|
215
|
+
}
|
|
216
|
+
return response.json();
|
|
217
|
+
}
|
|
69
218
|
async fetch(path, query) {
|
|
70
219
|
let url = `${this.baseUrl}${path}`;
|
|
71
220
|
if (query) {
|