@cstar.help/js 0.10.3 → 0.11.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
@@ -30,7 +30,7 @@ cStar has one package with **six entry points**, each designed for a different c
30
30
 
31
31
  ### The Security Model
32
32
 
33
- cStar uses **two key types** to control access — the same pattern as Stripe and Supabase:
33
+ cStar uses **two key types** to control access — the same pattern as Stripe:
34
34
 
35
35
  ```
36
36
  Secret keys (sk_live_*, sk_test_*)
@@ -211,8 +211,8 @@ await chat.identify(
211
211
  hmacSignature
212
212
  );
213
213
 
214
- // List conversations
215
- const { conversations } = await chat.conversations.list();
214
+ // List tickets
215
+ const { tickets } = await chat.tickets.list();
216
216
 
217
217
  // Send a message
218
218
  await chat.messages.send('tkt_abc123', 'Thanks for the help!');
@@ -45,8 +45,8 @@ var RealtimeManager = class {
45
45
  this.options = options;
46
46
  }
47
47
  /**
48
- * Initialize the Supabase client and authenticate with a realtime token.
49
- * Returns true if successful, false if @supabase/supabase-js is unavailable.
48
+ * Initialize the realtime client and authenticate with a token.
49
+ * Returns true if successful, false if the realtime runtime is unavailable.
50
50
  */
51
51
  init() {
52
52
  if (this.initPromise) return this.initPromise;
@@ -55,15 +55,15 @@ var RealtimeManager = class {
55
55
  }
56
56
  async doInit() {
57
57
  try {
58
+ const tokenData = await this.options.fetchToken();
58
59
  const { createClient } = await import(
59
60
  /* webpackIgnore: true */
60
61
  "@supabase/supabase-js"
61
62
  );
62
- this.client = createClient(this.options.supabaseUrl, this.options.supabaseAnonKey, {
63
+ this.client = createClient(tokenData.realtimeUrl, tokenData.realtimeKey, {
63
64
  auth: { persistSession: false, autoRefreshToken: false },
64
65
  realtime: { params: { eventsPerSecond: 10 } }
65
66
  });
66
- const tokenData = await this.options.fetchToken();
67
67
  this.setToken(tokenData);
68
68
  return true;
69
69
  } catch {
@@ -121,7 +121,8 @@ var RealtimeManager = class {
121
121
  sender_name: row.sender_name ?? "",
122
122
  created_at: row.created_at,
123
123
  read_at: row.read_at ?? null,
124
- attachments: row.attachments ?? []
124
+ attachments: row.attachments ?? [],
125
+ payload: row.payload ?? null
125
126
  };
126
127
  callback(message);
127
128
  }
@@ -129,7 +130,7 @@ var RealtimeManager = class {
129
130
  this.channels.set(channelName, channel);
130
131
  return () => this.removeChannel(channelName);
131
132
  }
132
- /** Get the underlying Supabase client (for sharing with PresenceManager). */
133
+ /** Get the underlying realtime client (for sharing with PresenceManager). */
133
134
  getClient() {
134
135
  return this.client;
135
136
  }
@@ -171,7 +172,7 @@ var PresenceManager = class {
171
172
  this.typingClearTimers = /* @__PURE__ */ new Map();
172
173
  this.options = options;
173
174
  }
174
- /** Set the Supabase client (shared from RealtimeManager). */
175
+ /** Set the realtime client (shared from RealtimeManager). */
175
176
  setClient(client) {
176
177
  this.client = client;
177
178
  }
@@ -290,18 +291,17 @@ var ChatClient = class {
290
291
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
291
292
  this.teamSlug = config.teamSlug;
292
293
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
293
- this.supabaseUrl = config.supabaseUrl;
294
- this.supabaseAnonKey = config.supabaseAnonKey;
295
- this.conversations = new ConversationsApi(this);
294
+ this.realtimeEnabled = config.realtime !== false;
295
+ this.tickets = new TicketsApi(this);
296
296
  this.messages = new MessagesApi(this);
297
297
  this.community = new ChatCommunityApi(this);
298
298
  }
299
299
  /**
300
300
  * Identify a customer using HMAC signature verification.
301
- * Must be called before accessing conversations or messages.
301
+ * Must be called before accessing tickets or messages.
302
302
  *
303
- * If `supabaseUrl` and `supabaseAnonKey` were provided in the config,
304
- * this will also initialize real-time subscriptions (non-blocking).
303
+ * Real-time subscriptions are initialized automatically (non-blocking)
304
+ * unless `realtime: false` was passed in config.
305
305
  *
306
306
  * @param customer - Customer identity fields
307
307
  * @param signature - HMAC-SHA256 hex signature of the signed fields
@@ -323,7 +323,7 @@ var ChatClient = class {
323
323
  this.sessionToken = response.data.sessionToken;
324
324
  this.teamId = response.data.teamId;
325
325
  this.customerId = response.data.customer.id;
326
- if (this.supabaseUrl && this.supabaseAnonKey) {
326
+ if (this.realtimeEnabled) {
327
327
  this.realtimeInitPromise = this.initRealtime(
328
328
  response.data.customer.id,
329
329
  response.data.customer.name || customer.name || customer.email
@@ -332,8 +332,8 @@ var ChatClient = class {
332
332
  return response.data;
333
333
  }
334
334
  /**
335
- * Subscribe to new messages on a conversation.
336
- * Uses Supabase Realtime (Postgres Changes) when available, falls back to polling.
335
+ * Subscribe to new messages on a ticket.
336
+ * Uses real-time delivery when available, falls back to polling.
337
337
  *
338
338
  * @returns Unsubscribe function
339
339
  */
@@ -345,7 +345,7 @@ var ChatClient = class {
345
345
  }
346
346
  /**
347
347
  * Subscribe to typing indicator events.
348
- * Requires Supabase Realtime — returns a no-op if unavailable.
348
+ * Requires real-time — returns a no-op when unavailable.
349
349
  *
350
350
  * @returns Unsubscribe function
351
351
  */
@@ -357,8 +357,8 @@ var ChatClient = class {
357
357
  };
358
358
  }
359
359
  /**
360
- * Send a customer typing indicator (requires realtime).
361
- * No-op if realtime is not available.
360
+ * Send a customer typing indicator (requires real-time).
361
+ * No-op when real-time is unavailable.
362
362
  */
363
363
  async sendTyping(ticketId, isTyping) {
364
364
  if (this.presenceManager) {
@@ -422,8 +422,6 @@ var ChatClient = class {
422
422
  async initRealtime(customerId, customerName) {
423
423
  try {
424
424
  this.realtimeManager = new RealtimeManager({
425
- supabaseUrl: this.supabaseUrl,
426
- supabaseAnonKey: this.supabaseAnonKey,
427
425
  fetchToken: () => this.fetchRealtimeToken()
428
426
  });
429
427
  const ready = await this.realtimeManager.init();
@@ -490,28 +488,29 @@ var ChatClient = class {
490
488
  return qs ? `${base}?${qs}` : base;
491
489
  }
492
490
  };
493
- var ConversationsApi = class {
491
+ var TicketsApi = class {
494
492
  constructor(chat) {
495
493
  this.chat = chat;
496
494
  }
497
- /** List conversations for the identified customer. */
495
+ /** List tickets for the identified customer. */
498
496
  async list(params) {
499
497
  const teamId = this.chat.getTeamId();
500
498
  if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
501
- const response = await this.chat.fetch(
502
- "/api/widget/conversations",
503
- {
504
- method: "GET",
505
- query: {
506
- teamId,
507
- limit: params?.limit?.toString(),
508
- cursor: params?.cursor
509
- }
499
+ const response = await this.chat.fetch("/api/widget/conversations", {
500
+ method: "GET",
501
+ query: {
502
+ teamId,
503
+ limit: params?.limit?.toString(),
504
+ cursor: params?.cursor
510
505
  }
511
- );
512
- return response.data;
506
+ });
507
+ return {
508
+ tickets: response.data.tickets ?? response.data.conversations ?? [],
509
+ cursor: response.data.cursor,
510
+ hasMore: response.data.hasMore
511
+ };
513
512
  }
514
- /** Create a new conversation (ticket). */
513
+ /** Create a new ticket. */
515
514
  async create(params) {
516
515
  const teamId = this.chat.getTeamId();
517
516
  if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
@@ -669,7 +668,7 @@ var MessagesApi = class {
669
668
  constructor(chat) {
670
669
  this.chat = chat;
671
670
  }
672
- /** List messages for a conversation. */
671
+ /** List messages for a ticket. */
673
672
  async list(ticketId) {
674
673
  const teamId = this.chat.getTeamId();
675
674
  const response = await this.chat.fetch(
@@ -684,7 +683,7 @@ var MessagesApi = class {
684
683
  );
685
684
  return response.data.messages;
686
685
  }
687
- /** Send a message to a conversation. */
686
+ /** Send a message to a ticket. */
688
687
  async send(ticketId, content) {
689
688
  const teamId = this.chat.getTeamId();
690
689
  const response = await this.chat.fetch(
@@ -4,11 +4,12 @@ interface ChatConfig {
4
4
  teamSlug: string;
5
5
  /** Override the base URL (defaults to https://www.cstar.help). */
6
6
  baseUrl?: string;
7
- /** Supabase project URL for realtime subscriptions (optional). */
8
- supabaseUrl?: string;
9
- /** Supabase anon key for realtime subscriptions (optional). */
10
- supabaseAnonKey?: string;
11
- /** Polling interval in ms when Supabase Realtime is not available (defaults to 3000). */
7
+ /**
8
+ * Enable real-time messages and typing indicators. Defaults to true.
9
+ * When false, the SDK falls back to polling.
10
+ */
11
+ realtime?: boolean;
12
+ /** Polling interval in ms when realtime is disabled or unavailable (defaults to 3000). */
12
13
  pollingInterval?: number;
13
14
  }
14
15
  /** Parameters for identifying a customer via HMAC signature verification. */
@@ -43,14 +44,16 @@ interface IdentifyResult {
43
44
  /** Team UUID — used for realtime token requests. */
44
45
  teamId: string;
45
46
  }
46
- /** Response from the realtime-token endpoint. */
47
+ /** @internal Response from the realtime-token endpoint. */
47
48
  interface RealtimeTokenResponse {
48
49
  token: string;
49
50
  expiresAt: string;
50
51
  refreshAt: string;
52
+ realtimeUrl: string;
53
+ realtimeKey: string;
51
54
  }
52
- /** A customer conversation (maps to a ticket). */
53
- interface Conversation {
55
+ /** A ticket — a customer's support thread. */
56
+ interface Ticket {
54
57
  id: string;
55
58
  ticketNumber: string;
56
59
  subject: string;
@@ -60,14 +63,14 @@ interface Conversation {
60
63
  updatedAt: string;
61
64
  closedAt: string | null;
62
65
  }
63
- /** Paginated conversation list response. */
64
- interface ConversationListResponse {
65
- conversations: Conversation[];
66
+ /** Paginated ticket list response. */
67
+ interface TicketListResponse {
68
+ tickets: Ticket[];
66
69
  cursor: string | null;
67
70
  hasMore: boolean;
68
71
  }
69
- /** A message in a conversation. */
70
- interface WidgetMessage {
72
+ /** A message on a ticket. */
73
+ interface Message {
71
74
  id: string;
72
75
  content: string;
73
76
  sender: 'customer' | 'agent';
@@ -75,25 +78,30 @@ interface WidgetMessage {
75
78
  created_at: string;
76
79
  read_at: string | null;
77
80
  attachments: unknown[];
81
+ /** Raw AI SDK response payload for agent messages. Widgets can use this
82
+ * with `extractToolCallsFromPayload` to render customer-safe tool chips. */
83
+ payload?: Record<string, unknown> | null;
84
+ /** Whether this message was sent by an AI agent. */
85
+ is_bot?: boolean;
78
86
  }
79
- /** Parameters for listing conversations. */
80
- interface ConversationListParams {
87
+ /** Parameters for listing tickets. */
88
+ interface TicketListParams {
81
89
  limit?: number;
82
90
  cursor?: string;
83
91
  }
84
- /** Parameters for creating a new conversation. */
85
- interface ConversationCreateParams {
92
+ /** Parameters for creating a new ticket. */
93
+ interface TicketCreateParams {
86
94
  subject: string;
87
95
  message?: string;
88
96
  }
89
- /** Typing indicator payload from realtime subscription. */
97
+ /** Typing indicator payload. */
90
98
  interface TypingPayload {
91
99
  agent_id: string;
92
100
  agent_name: string;
93
101
  is_typing: boolean;
94
102
  }
95
103
  /** Callback for message events. */
96
- type MessageCallback = (message: WidgetMessage) => void;
104
+ type MessageCallback = (message: Message) => void;
97
105
  /** Callback for typing indicator events. */
98
106
  type TypingCallback = (payload: TypingPayload) => void;
99
107
 
@@ -183,16 +191,13 @@ interface CommunityFollowResult {
183
191
  /**
184
192
  * Customer-facing chat client for the cStar widget API.
185
193
  *
186
- * Supports real-time messages and typing indicators when `supabaseUrl`
187
- * and `supabaseAnonKey` are provided and `@supabase/supabase-js` is installed.
188
- * Falls back to polling otherwise.
194
+ * Real-time messages and typing indicators are enabled by default and
195
+ * fall back to polling automatically. No additional configuration is
196
+ * required — everything the SDK needs is fetched from the cStar API
197
+ * after `identify()`.
189
198
  *
190
199
  * ```typescript
191
- * const chat = new ChatClient({
192
- * teamSlug: 'acme',
193
- * supabaseUrl: 'https://xxx.supabase.co',
194
- * supabaseAnonKey: 'eyJ...',
195
- * });
200
+ * const chat = new ChatClient({ teamSlug: 'acme' });
196
201
  * await chat.identify(
197
202
  * { externalId: 'usr_123', email: 'jane@co.com', name: 'Jane', timestamp: Date.now() / 1000 },
198
203
  * 'hmac_signature_hex'
@@ -205,8 +210,7 @@ declare class ChatClient {
205
210
  private readonly baseUrl;
206
211
  private readonly teamSlug;
207
212
  private readonly pollingInterval;
208
- private readonly supabaseUrl?;
209
- private readonly supabaseAnonKey?;
213
+ private readonly realtimeEnabled;
210
214
  private sessionToken;
211
215
  private teamId;
212
216
  private customerId;
@@ -215,8 +219,8 @@ declare class ChatClient {
215
219
  private presenceManager;
216
220
  private realtimeReady;
217
221
  private realtimeInitPromise;
218
- /** Sub-resource for managing conversations. */
219
- readonly conversations: ConversationsApi;
222
+ /** Sub-resource for managing tickets. */
223
+ readonly tickets: TicketsApi;
220
224
  /** Sub-resource for managing messages. */
221
225
  readonly messages: MessagesApi;
222
226
  /** Sub-resource for community actions (create posts, vote, comment). Uses the same session as chat. */
@@ -224,10 +228,10 @@ declare class ChatClient {
224
228
  constructor(config: ChatConfig);
225
229
  /**
226
230
  * Identify a customer using HMAC signature verification.
227
- * Must be called before accessing conversations or messages.
231
+ * Must be called before accessing tickets or messages.
228
232
  *
229
- * If `supabaseUrl` and `supabaseAnonKey` were provided in the config,
230
- * this will also initialize real-time subscriptions (non-blocking).
233
+ * Real-time subscriptions are initialized automatically (non-blocking)
234
+ * unless `realtime: false` was passed in config.
231
235
  *
232
236
  * @param customer - Customer identity fields
233
237
  * @param signature - HMAC-SHA256 hex signature of the signed fields
@@ -235,22 +239,22 @@ declare class ChatClient {
235
239
  */
236
240
  identify(customer: IdentifyParams, signature: string, testMode?: boolean): Promise<IdentifyResult>;
237
241
  /**
238
- * Subscribe to new messages on a conversation.
239
- * Uses Supabase Realtime (Postgres Changes) when available, falls back to polling.
242
+ * Subscribe to new messages on a ticket.
243
+ * Uses real-time delivery when available, falls back to polling.
240
244
  *
241
245
  * @returns Unsubscribe function
242
246
  */
243
247
  onMessage(ticketId: string, callback: MessageCallback): () => void;
244
248
  /**
245
249
  * Subscribe to typing indicator events.
246
- * Requires Supabase Realtime — returns a no-op if unavailable.
250
+ * Requires real-time — returns a no-op when unavailable.
247
251
  *
248
252
  * @returns Unsubscribe function
249
253
  */
250
254
  onTyping(ticketId: string, callback: TypingCallback): () => void;
251
255
  /**
252
- * Send a customer typing indicator (requires realtime).
253
- * No-op if realtime is not available.
256
+ * Send a customer typing indicator (requires real-time).
257
+ * No-op when real-time is unavailable.
254
258
  */
255
259
  sendTyping(ticketId: string, isTyping: boolean): Promise<void>;
256
260
  /** Disconnect all subscriptions and clean up. */
@@ -272,14 +276,14 @@ declare class ChatClient {
272
276
  private pollMessages;
273
277
  private buildUrl;
274
278
  }
275
- /** Conversations sub-resource on ChatClient. */
276
- declare class ConversationsApi {
279
+ /** Tickets sub-resource on ChatClient. */
280
+ declare class TicketsApi {
277
281
  private readonly chat;
278
282
  constructor(chat: ChatClient);
279
- /** List conversations for the identified customer. */
280
- list(params?: ConversationListParams): Promise<ConversationListResponse>;
281
- /** Create a new conversation (ticket). */
282
- create(params: ConversationCreateParams): Promise<Conversation>;
283
+ /** List tickets for the identified customer. */
284
+ list(params?: TicketListParams): Promise<TicketListResponse>;
285
+ /** Create a new ticket. */
286
+ create(params: TicketCreateParams): Promise<Ticket>;
283
287
  }
284
288
  /**
285
289
  * Community sub-resource on ChatClient.
@@ -313,10 +317,10 @@ declare class ChatCommunityApi {
313
317
  declare class MessagesApi {
314
318
  private readonly chat;
315
319
  constructor(chat: ChatClient);
316
- /** List messages for a conversation. */
317
- list(ticketId: string): Promise<WidgetMessage[]>;
318
- /** Send a message to a conversation. */
319
- send(ticketId: string, content: string): Promise<WidgetMessage>;
320
+ /** List messages for a ticket. */
321
+ list(ticketId: string): Promise<Message[]>;
322
+ /** Send a message to a ticket. */
323
+ send(ticketId: string, content: string): Promise<Message>;
320
324
  }
321
325
 
322
- export { ChatClient, type ChatConfig, type Conversation, type ConversationCreateParams, type ConversationListParams, type ConversationListResponse, type IdentifyParams, type IdentifyResult, type MessageCallback, type RealtimeTokenResponse, type TypingCallback, type TypingPayload, type WidgetMessage };
326
+ export { ChatClient, type ChatConfig, type IdentifyParams, type IdentifyResult, type Message, type MessageCallback, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
@@ -4,11 +4,12 @@ interface ChatConfig {
4
4
  teamSlug: string;
5
5
  /** Override the base URL (defaults to https://www.cstar.help). */
6
6
  baseUrl?: string;
7
- /** Supabase project URL for realtime subscriptions (optional). */
8
- supabaseUrl?: string;
9
- /** Supabase anon key for realtime subscriptions (optional). */
10
- supabaseAnonKey?: string;
11
- /** Polling interval in ms when Supabase Realtime is not available (defaults to 3000). */
7
+ /**
8
+ * Enable real-time messages and typing indicators. Defaults to true.
9
+ * When false, the SDK falls back to polling.
10
+ */
11
+ realtime?: boolean;
12
+ /** Polling interval in ms when realtime is disabled or unavailable (defaults to 3000). */
12
13
  pollingInterval?: number;
13
14
  }
14
15
  /** Parameters for identifying a customer via HMAC signature verification. */
@@ -43,14 +44,16 @@ interface IdentifyResult {
43
44
  /** Team UUID — used for realtime token requests. */
44
45
  teamId: string;
45
46
  }
46
- /** Response from the realtime-token endpoint. */
47
+ /** @internal Response from the realtime-token endpoint. */
47
48
  interface RealtimeTokenResponse {
48
49
  token: string;
49
50
  expiresAt: string;
50
51
  refreshAt: string;
52
+ realtimeUrl: string;
53
+ realtimeKey: string;
51
54
  }
52
- /** A customer conversation (maps to a ticket). */
53
- interface Conversation {
55
+ /** A ticket — a customer's support thread. */
56
+ interface Ticket {
54
57
  id: string;
55
58
  ticketNumber: string;
56
59
  subject: string;
@@ -60,14 +63,14 @@ interface Conversation {
60
63
  updatedAt: string;
61
64
  closedAt: string | null;
62
65
  }
63
- /** Paginated conversation list response. */
64
- interface ConversationListResponse {
65
- conversations: Conversation[];
66
+ /** Paginated ticket list response. */
67
+ interface TicketListResponse {
68
+ tickets: Ticket[];
66
69
  cursor: string | null;
67
70
  hasMore: boolean;
68
71
  }
69
- /** A message in a conversation. */
70
- interface WidgetMessage {
72
+ /** A message on a ticket. */
73
+ interface Message {
71
74
  id: string;
72
75
  content: string;
73
76
  sender: 'customer' | 'agent';
@@ -75,25 +78,30 @@ interface WidgetMessage {
75
78
  created_at: string;
76
79
  read_at: string | null;
77
80
  attachments: unknown[];
81
+ /** Raw AI SDK response payload for agent messages. Widgets can use this
82
+ * with `extractToolCallsFromPayload` to render customer-safe tool chips. */
83
+ payload?: Record<string, unknown> | null;
84
+ /** Whether this message was sent by an AI agent. */
85
+ is_bot?: boolean;
78
86
  }
79
- /** Parameters for listing conversations. */
80
- interface ConversationListParams {
87
+ /** Parameters for listing tickets. */
88
+ interface TicketListParams {
81
89
  limit?: number;
82
90
  cursor?: string;
83
91
  }
84
- /** Parameters for creating a new conversation. */
85
- interface ConversationCreateParams {
92
+ /** Parameters for creating a new ticket. */
93
+ interface TicketCreateParams {
86
94
  subject: string;
87
95
  message?: string;
88
96
  }
89
- /** Typing indicator payload from realtime subscription. */
97
+ /** Typing indicator payload. */
90
98
  interface TypingPayload {
91
99
  agent_id: string;
92
100
  agent_name: string;
93
101
  is_typing: boolean;
94
102
  }
95
103
  /** Callback for message events. */
96
- type MessageCallback = (message: WidgetMessage) => void;
104
+ type MessageCallback = (message: Message) => void;
97
105
  /** Callback for typing indicator events. */
98
106
  type TypingCallback = (payload: TypingPayload) => void;
99
107
 
@@ -183,16 +191,13 @@ interface CommunityFollowResult {
183
191
  /**
184
192
  * Customer-facing chat client for the cStar widget API.
185
193
  *
186
- * Supports real-time messages and typing indicators when `supabaseUrl`
187
- * and `supabaseAnonKey` are provided and `@supabase/supabase-js` is installed.
188
- * Falls back to polling otherwise.
194
+ * Real-time messages and typing indicators are enabled by default and
195
+ * fall back to polling automatically. No additional configuration is
196
+ * required — everything the SDK needs is fetched from the cStar API
197
+ * after `identify()`.
189
198
  *
190
199
  * ```typescript
191
- * const chat = new ChatClient({
192
- * teamSlug: 'acme',
193
- * supabaseUrl: 'https://xxx.supabase.co',
194
- * supabaseAnonKey: 'eyJ...',
195
- * });
200
+ * const chat = new ChatClient({ teamSlug: 'acme' });
196
201
  * await chat.identify(
197
202
  * { externalId: 'usr_123', email: 'jane@co.com', name: 'Jane', timestamp: Date.now() / 1000 },
198
203
  * 'hmac_signature_hex'
@@ -205,8 +210,7 @@ declare class ChatClient {
205
210
  private readonly baseUrl;
206
211
  private readonly teamSlug;
207
212
  private readonly pollingInterval;
208
- private readonly supabaseUrl?;
209
- private readonly supabaseAnonKey?;
213
+ private readonly realtimeEnabled;
210
214
  private sessionToken;
211
215
  private teamId;
212
216
  private customerId;
@@ -215,8 +219,8 @@ declare class ChatClient {
215
219
  private presenceManager;
216
220
  private realtimeReady;
217
221
  private realtimeInitPromise;
218
- /** Sub-resource for managing conversations. */
219
- readonly conversations: ConversationsApi;
222
+ /** Sub-resource for managing tickets. */
223
+ readonly tickets: TicketsApi;
220
224
  /** Sub-resource for managing messages. */
221
225
  readonly messages: MessagesApi;
222
226
  /** Sub-resource for community actions (create posts, vote, comment). Uses the same session as chat. */
@@ -224,10 +228,10 @@ declare class ChatClient {
224
228
  constructor(config: ChatConfig);
225
229
  /**
226
230
  * Identify a customer using HMAC signature verification.
227
- * Must be called before accessing conversations or messages.
231
+ * Must be called before accessing tickets or messages.
228
232
  *
229
- * If `supabaseUrl` and `supabaseAnonKey` were provided in the config,
230
- * this will also initialize real-time subscriptions (non-blocking).
233
+ * Real-time subscriptions are initialized automatically (non-blocking)
234
+ * unless `realtime: false` was passed in config.
231
235
  *
232
236
  * @param customer - Customer identity fields
233
237
  * @param signature - HMAC-SHA256 hex signature of the signed fields
@@ -235,22 +239,22 @@ declare class ChatClient {
235
239
  */
236
240
  identify(customer: IdentifyParams, signature: string, testMode?: boolean): Promise<IdentifyResult>;
237
241
  /**
238
- * Subscribe to new messages on a conversation.
239
- * Uses Supabase Realtime (Postgres Changes) when available, falls back to polling.
242
+ * Subscribe to new messages on a ticket.
243
+ * Uses real-time delivery when available, falls back to polling.
240
244
  *
241
245
  * @returns Unsubscribe function
242
246
  */
243
247
  onMessage(ticketId: string, callback: MessageCallback): () => void;
244
248
  /**
245
249
  * Subscribe to typing indicator events.
246
- * Requires Supabase Realtime — returns a no-op if unavailable.
250
+ * Requires real-time — returns a no-op when unavailable.
247
251
  *
248
252
  * @returns Unsubscribe function
249
253
  */
250
254
  onTyping(ticketId: string, callback: TypingCallback): () => void;
251
255
  /**
252
- * Send a customer typing indicator (requires realtime).
253
- * No-op if realtime is not available.
256
+ * Send a customer typing indicator (requires real-time).
257
+ * No-op when real-time is unavailable.
254
258
  */
255
259
  sendTyping(ticketId: string, isTyping: boolean): Promise<void>;
256
260
  /** Disconnect all subscriptions and clean up. */
@@ -272,14 +276,14 @@ declare class ChatClient {
272
276
  private pollMessages;
273
277
  private buildUrl;
274
278
  }
275
- /** Conversations sub-resource on ChatClient. */
276
- declare class ConversationsApi {
279
+ /** Tickets sub-resource on ChatClient. */
280
+ declare class TicketsApi {
277
281
  private readonly chat;
278
282
  constructor(chat: ChatClient);
279
- /** List conversations for the identified customer. */
280
- list(params?: ConversationListParams): Promise<ConversationListResponse>;
281
- /** Create a new conversation (ticket). */
282
- create(params: ConversationCreateParams): Promise<Conversation>;
283
+ /** List tickets for the identified customer. */
284
+ list(params?: TicketListParams): Promise<TicketListResponse>;
285
+ /** Create a new ticket. */
286
+ create(params: TicketCreateParams): Promise<Ticket>;
283
287
  }
284
288
  /**
285
289
  * Community sub-resource on ChatClient.
@@ -313,10 +317,10 @@ declare class ChatCommunityApi {
313
317
  declare class MessagesApi {
314
318
  private readonly chat;
315
319
  constructor(chat: ChatClient);
316
- /** List messages for a conversation. */
317
- list(ticketId: string): Promise<WidgetMessage[]>;
318
- /** Send a message to a conversation. */
319
- send(ticketId: string, content: string): Promise<WidgetMessage>;
320
+ /** List messages for a ticket. */
321
+ list(ticketId: string): Promise<Message[]>;
322
+ /** Send a message to a ticket. */
323
+ send(ticketId: string, content: string): Promise<Message>;
320
324
  }
321
325
 
322
- export { ChatClient, type ChatConfig, type Conversation, type ConversationCreateParams, type ConversationListParams, type ConversationListResponse, type IdentifyParams, type IdentifyResult, type MessageCallback, type RealtimeTokenResponse, type TypingCallback, type TypingPayload, type WidgetMessage };
326
+ export { ChatClient, type ChatConfig, type IdentifyParams, type IdentifyResult, type Message, type MessageCallback, type RealtimeTokenResponse, type Ticket, type TicketCreateParams, type TicketListParams, type TicketListResponse, type TypingCallback, type TypingPayload };
@@ -9,8 +9,8 @@ var RealtimeManager = class {
9
9
  this.options = options;
10
10
  }
11
11
  /**
12
- * Initialize the Supabase client and authenticate with a realtime token.
13
- * Returns true if successful, false if @supabase/supabase-js is unavailable.
12
+ * Initialize the realtime client and authenticate with a token.
13
+ * Returns true if successful, false if the realtime runtime is unavailable.
14
14
  */
15
15
  init() {
16
16
  if (this.initPromise) return this.initPromise;
@@ -19,15 +19,15 @@ var RealtimeManager = class {
19
19
  }
20
20
  async doInit() {
21
21
  try {
22
+ const tokenData = await this.options.fetchToken();
22
23
  const { createClient } = await import(
23
24
  /* webpackIgnore: true */
24
25
  "@supabase/supabase-js"
25
26
  );
26
- this.client = createClient(this.options.supabaseUrl, this.options.supabaseAnonKey, {
27
+ this.client = createClient(tokenData.realtimeUrl, tokenData.realtimeKey, {
27
28
  auth: { persistSession: false, autoRefreshToken: false },
28
29
  realtime: { params: { eventsPerSecond: 10 } }
29
30
  });
30
- const tokenData = await this.options.fetchToken();
31
31
  this.setToken(tokenData);
32
32
  return true;
33
33
  } catch {
@@ -85,7 +85,8 @@ var RealtimeManager = class {
85
85
  sender_name: row.sender_name ?? "",
86
86
  created_at: row.created_at,
87
87
  read_at: row.read_at ?? null,
88
- attachments: row.attachments ?? []
88
+ attachments: row.attachments ?? [],
89
+ payload: row.payload ?? null
89
90
  };
90
91
  callback(message);
91
92
  }
@@ -93,7 +94,7 @@ var RealtimeManager = class {
93
94
  this.channels.set(channelName, channel);
94
95
  return () => this.removeChannel(channelName);
95
96
  }
96
- /** Get the underlying Supabase client (for sharing with PresenceManager). */
97
+ /** Get the underlying realtime client (for sharing with PresenceManager). */
97
98
  getClient() {
98
99
  return this.client;
99
100
  }
@@ -135,7 +136,7 @@ var PresenceManager = class {
135
136
  this.typingClearTimers = /* @__PURE__ */ new Map();
136
137
  this.options = options;
137
138
  }
138
- /** Set the Supabase client (shared from RealtimeManager). */
139
+ /** Set the realtime client (shared from RealtimeManager). */
139
140
  setClient(client) {
140
141
  this.client = client;
141
142
  }
@@ -254,18 +255,17 @@ var ChatClient = class {
254
255
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
255
256
  this.teamSlug = config.teamSlug;
256
257
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
257
- this.supabaseUrl = config.supabaseUrl;
258
- this.supabaseAnonKey = config.supabaseAnonKey;
259
- this.conversations = new ConversationsApi(this);
258
+ this.realtimeEnabled = config.realtime !== false;
259
+ this.tickets = new TicketsApi(this);
260
260
  this.messages = new MessagesApi(this);
261
261
  this.community = new ChatCommunityApi(this);
262
262
  }
263
263
  /**
264
264
  * Identify a customer using HMAC signature verification.
265
- * Must be called before accessing conversations or messages.
265
+ * Must be called before accessing tickets or messages.
266
266
  *
267
- * If `supabaseUrl` and `supabaseAnonKey` were provided in the config,
268
- * this will also initialize real-time subscriptions (non-blocking).
267
+ * Real-time subscriptions are initialized automatically (non-blocking)
268
+ * unless `realtime: false` was passed in config.
269
269
  *
270
270
  * @param customer - Customer identity fields
271
271
  * @param signature - HMAC-SHA256 hex signature of the signed fields
@@ -287,7 +287,7 @@ var ChatClient = class {
287
287
  this.sessionToken = response.data.sessionToken;
288
288
  this.teamId = response.data.teamId;
289
289
  this.customerId = response.data.customer.id;
290
- if (this.supabaseUrl && this.supabaseAnonKey) {
290
+ if (this.realtimeEnabled) {
291
291
  this.realtimeInitPromise = this.initRealtime(
292
292
  response.data.customer.id,
293
293
  response.data.customer.name || customer.name || customer.email
@@ -296,8 +296,8 @@ var ChatClient = class {
296
296
  return response.data;
297
297
  }
298
298
  /**
299
- * Subscribe to new messages on a conversation.
300
- * Uses Supabase Realtime (Postgres Changes) when available, falls back to polling.
299
+ * Subscribe to new messages on a ticket.
300
+ * Uses real-time delivery when available, falls back to polling.
301
301
  *
302
302
  * @returns Unsubscribe function
303
303
  */
@@ -309,7 +309,7 @@ var ChatClient = class {
309
309
  }
310
310
  /**
311
311
  * Subscribe to typing indicator events.
312
- * Requires Supabase Realtime — returns a no-op if unavailable.
312
+ * Requires real-time — returns a no-op when unavailable.
313
313
  *
314
314
  * @returns Unsubscribe function
315
315
  */
@@ -321,8 +321,8 @@ var ChatClient = class {
321
321
  };
322
322
  }
323
323
  /**
324
- * Send a customer typing indicator (requires realtime).
325
- * No-op if realtime is not available.
324
+ * Send a customer typing indicator (requires real-time).
325
+ * No-op when real-time is unavailable.
326
326
  */
327
327
  async sendTyping(ticketId, isTyping) {
328
328
  if (this.presenceManager) {
@@ -386,8 +386,6 @@ var ChatClient = class {
386
386
  async initRealtime(customerId, customerName) {
387
387
  try {
388
388
  this.realtimeManager = new RealtimeManager({
389
- supabaseUrl: this.supabaseUrl,
390
- supabaseAnonKey: this.supabaseAnonKey,
391
389
  fetchToken: () => this.fetchRealtimeToken()
392
390
  });
393
391
  const ready = await this.realtimeManager.init();
@@ -454,28 +452,29 @@ var ChatClient = class {
454
452
  return qs ? `${base}?${qs}` : base;
455
453
  }
456
454
  };
457
- var ConversationsApi = class {
455
+ var TicketsApi = class {
458
456
  constructor(chat) {
459
457
  this.chat = chat;
460
458
  }
461
- /** List conversations for the identified customer. */
459
+ /** List tickets for the identified customer. */
462
460
  async list(params) {
463
461
  const teamId = this.chat.getTeamId();
464
462
  if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
465
- const response = await this.chat.fetch(
466
- "/api/widget/conversations",
467
- {
468
- method: "GET",
469
- query: {
470
- teamId,
471
- limit: params?.limit?.toString(),
472
- cursor: params?.cursor
473
- }
463
+ const response = await this.chat.fetch("/api/widget/conversations", {
464
+ method: "GET",
465
+ query: {
466
+ teamId,
467
+ limit: params?.limit?.toString(),
468
+ cursor: params?.cursor
474
469
  }
475
- );
476
- return response.data;
470
+ });
471
+ return {
472
+ tickets: response.data.tickets ?? response.data.conversations ?? [],
473
+ cursor: response.data.cursor,
474
+ hasMore: response.data.hasMore
475
+ };
477
476
  }
478
- /** Create a new conversation (ticket). */
477
+ /** Create a new ticket. */
479
478
  async create(params) {
480
479
  const teamId = this.chat.getTeamId();
481
480
  if (!teamId) throw new Error("Not identified. Call chat.identify() first.");
@@ -633,7 +632,7 @@ var MessagesApi = class {
633
632
  constructor(chat) {
634
633
  this.chat = chat;
635
634
  }
636
- /** List messages for a conversation. */
635
+ /** List messages for a ticket. */
637
636
  async list(ticketId) {
638
637
  const teamId = this.chat.getTeamId();
639
638
  const response = await this.chat.fetch(
@@ -648,7 +647,7 @@ var MessagesApi = class {
648
647
  );
649
648
  return response.data.messages;
650
649
  }
651
- /** Send a message to a conversation. */
650
+ /** Send a message to a ticket. */
652
651
  async send(ticketId, content) {
653
652
  const teamId = this.chat.getTeamId();
654
653
  const response = await this.chat.fetch(
package/dist/index.cjs CHANGED
@@ -140,6 +140,16 @@ var DEFAULT_MAX_RETRIES = 3;
140
140
  var DEFAULT_TIMEOUT = 3e4;
141
141
  var HttpClient = class {
142
142
  constructor(config) {
143
+ if (!config || typeof config.apiKey !== "string" || config.apiKey.length === 0) {
144
+ throw new Error(
145
+ "[cStar] CStarClient: apiKey is required. Pass a secret key (sk_live_... / sk_test_...) or a publishable key (pk_live_... / pk_test_...). See https://cstar.help/developers/quickstart"
146
+ );
147
+ }
148
+ if (typeof config.teamId !== "string" || config.teamId.length === 0) {
149
+ throw new Error(
150
+ "[cStar] CStarClient: teamId is required. Find your team ID in Settings \u2192 General or via `cstar status`."
151
+ );
152
+ }
143
153
  this.config = {
144
154
  apiKey: config.apiKey,
145
155
  teamId: config.teamId,
@@ -1956,10 +1966,12 @@ var GameResource = class {
1956
1966
  subscribeLeaderboard(realtime, params) {
1957
1967
  const fetchFn = async () => {
1958
1968
  const res = await this.leaderboard(params);
1969
+ const envelope = res.data;
1970
+ const entries = Array.isArray(envelope) ? envelope : envelope?.entries ?? [];
1959
1971
  return {
1960
1972
  success: true,
1961
- data: res.data,
1962
- pagination: { total: res.data.length, page: 1, pageSize: 100, hasMore: false },
1973
+ data: entries,
1974
+ pagination: { total: entries.length, page: 1, pageSize: 100, hasMore: false },
1963
1975
  meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
1964
1976
  };
1965
1977
  };
package/dist/index.js CHANGED
@@ -102,6 +102,16 @@ var DEFAULT_MAX_RETRIES = 3;
102
102
  var DEFAULT_TIMEOUT = 3e4;
103
103
  var HttpClient = class {
104
104
  constructor(config) {
105
+ if (!config || typeof config.apiKey !== "string" || config.apiKey.length === 0) {
106
+ throw new Error(
107
+ "[cStar] CStarClient: apiKey is required. Pass a secret key (sk_live_... / sk_test_...) or a publishable key (pk_live_... / pk_test_...). See https://cstar.help/developers/quickstart"
108
+ );
109
+ }
110
+ if (typeof config.teamId !== "string" || config.teamId.length === 0) {
111
+ throw new Error(
112
+ "[cStar] CStarClient: teamId is required. Find your team ID in Settings \u2192 General or via `cstar status`."
113
+ );
114
+ }
105
115
  this.config = {
106
116
  apiKey: config.apiKey,
107
117
  teamId: config.teamId,
@@ -1918,10 +1928,12 @@ var GameResource = class {
1918
1928
  subscribeLeaderboard(realtime, params) {
1919
1929
  const fetchFn = async () => {
1920
1930
  const res = await this.leaderboard(params);
1931
+ const envelope = res.data;
1932
+ const entries = Array.isArray(envelope) ? envelope : envelope?.entries ?? [];
1921
1933
  return {
1922
1934
  success: true,
1923
- data: res.data,
1924
- pagination: { total: res.data.length, page: 1, pageSize: 100, hasMore: false },
1935
+ data: entries,
1936
+ pagination: { total: entries.length, page: 1, pageSize: 100, hasMore: false },
1925
1937
  meta: { requestId: "", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
1926
1938
  };
1927
1939
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cstar.help/js",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "description": "Official TypeScript SDK for the cStar customer support platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -108,13 +108,8 @@
108
108
  "engines": {
109
109
  "node": ">=18.0.0"
110
110
  },
111
- "peerDependencies": {
112
- "@supabase/supabase-js": ">=2.0.0"
113
- },
114
- "peerDependenciesMeta": {
115
- "@supabase/supabase-js": {
116
- "optional": true
117
- }
111
+ "dependencies": {
112
+ "@supabase/supabase-js": "^2.0.0"
118
113
  },
119
114
  "devDependencies": {
120
115
  "tsup": "^8.0.0",