@ermis-network/ermis-chat-sdk 1.0.3 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ermis-network/ermis-chat-sdk",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Ermis Chat SDK",
5
5
  "author": "Ermis",
6
6
  "homepage": "https://ermis.network/",
package/src/channel.ts CHANGED
@@ -37,6 +37,11 @@ import {
37
37
  EditMessage,
38
38
  ForwardMessage,
39
39
  } from './types';
40
+ /**
41
+ * Represents a Channel in the Ermis Network.
42
+ * Channels handle chat sessions, livestream messages, teams, or video calls.
43
+ * This class abstracts and exposes all API operations you can perform on a specific channel instance.
44
+ */
40
45
  export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics> {
41
46
  _client: ErmisChat<ErmisChatGenerics>;
42
47
  type: string;
@@ -53,6 +58,15 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
53
58
  isTyping: boolean;
54
59
  disconnected: boolean;
55
60
 
61
+ /**
62
+ * Initializes a new Channel class instance.
63
+ * Normally you should not call this directly; use `client.channel(type, id)` instead.
64
+ *
65
+ * @param client - The shared ErmisChat client instance initializing this channel.
66
+ * @param type - The type of channel (`messaging`, `team`, `livestream`, etc.).
67
+ * @param id - The unique ID of the channel.
68
+ * @param data - Initial arbitrary metadata stored within this channel.
69
+ */
56
70
  constructor(
57
71
  client: ErmisChat<ErmisChatGenerics>,
58
72
  type: string,
@@ -88,6 +102,13 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
88
102
  return this._client;
89
103
  }
90
104
 
105
+ /**
106
+ * Sends a message to this channel.
107
+ * By default, it pushes the message eagerly (optimistically) to the local UI state before the server replies.
108
+ *
109
+ * @param message - The constructed text/attachment object payload representing the message.
110
+ * @returns A Promise resolving to the exact API response encompassing message details.
111
+ */
91
112
  async sendMessage(message: Message<ErmisChatGenerics>) {
92
113
  // 1. Generate ID upfront
93
114
  if (!message.id) {
@@ -391,6 +412,11 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
391
412
  return this.getClient().post<APIResponse>(url);
392
413
  }
393
414
 
415
+ /**
416
+ * Directly invites or adds registered users into this channel.
417
+ *
418
+ * @param members - Array of user IDs explicitly selected to be added.
419
+ */
394
420
  async addMembers(members: string[]) {
395
421
  return await this._update({ add_members: members });
396
422
  }
@@ -469,6 +495,11 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
469
495
  };
470
496
  }
471
497
 
498
+ /**
499
+ * Expels specified currently participating users out of the channel.
500
+ *
501
+ * @param members - Array of user IDs to strictly remove from this chat.
502
+ */
472
503
  async removeMembers(members: string[]) {
473
504
  return await this._update({ remove_members: members });
474
505
  }
@@ -569,6 +600,10 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
569
600
  return messageSlice[0];
570
601
  }
571
602
 
603
+ /**
604
+ * Emits a mark-read event, updating the backend that the authenticated user has viewed up to the latest known message.
605
+ * @returns Successful acknowledgement from the server.
606
+ */
572
607
  async markRead() {
573
608
  return await this.getClient().post(this._channelURL() + '/read');
574
609
  }
@@ -585,6 +620,13 @@ export class Channel<ErmisChatGenerics extends ExtendableGenerics = DefaultGener
585
620
  this.state.clean();
586
621
  }
587
622
 
623
+ /**
624
+ * Subscribes to realtime events (WebSocket) for this channel, grabs the latest available metadata,
625
+ * loads the most recent messages, and initializes the local state.
626
+ *
627
+ * @param options - Pagination limits like `{ watch: true, presence: true, state: true }`.
628
+ * @returns The synchronized comprehensive channel state.
629
+ */
588
630
  async watch(options?: ChannelQueryOptions) {
589
631
  // Make sure we wait for the connect promise if there is a pending one
590
632
  await this.getClient().wsPromise;
@@ -26,18 +26,30 @@ type ChannelReadStatus<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
26
26
 
27
27
  /**
28
28
  * ChannelState - A container class for the channel state.
29
+ * This class synchronously binds to a `Channel` and holds the single source of truth for
30
+ * messages, read status, watchers, and typing indicators locally on the client.
29
31
  */
30
32
  export class ChannelState<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics> {
31
33
  _channel: Channel<ErmisChatGenerics>;
34
+ /** The current count of users actively watching (having an open WebSocket) this channel. */
32
35
  watcher_count: number;
36
+ /** A dictionary of active typing events gracefully keyed by the user's ID. */
33
37
  typing: Record<string, Event<ErmisChatGenerics>>;
38
+ /** A dictionary of read states mapped per user's ID detailing the last viewed message. */
34
39
  read: ChannelReadStatus<ErmisChatGenerics>;
40
+ /** The locally cached array of pinned messages across the channel. */
35
41
  pinnedMessages: Array<ReturnType<ChannelState<ErmisChatGenerics>['formatMessage']>>;
42
+ /** A directory of users actively watching the channel, keyed by User ID. */
36
43
  watchers: Record<string, UserResponse<ErmisChatGenerics>>;
44
+ /** A comprehensive directory mapping user IDs to their member status in the channel. */
37
45
  members: Record<string, ChannelMemberResponse<ErmisChatGenerics>>;
46
+ /** The count of messages not yet read by the currently authenticated user. */
38
47
  unreadCount: number;
48
+ /** Information detailing the authenticated user's own membership relation to this channel. */
39
49
  membership: ChannelMembership<ErmisChatGenerics>;
50
+ /** Timestamp indicating when the very last message was created in this chat. */
40
51
  last_message_at: Date | null;
52
+ /** Designates if the local channel state is entirely synchronized with the backend history. */
41
53
  isUpToDate: boolean;
42
54
  messageSets: {
43
55
  isCurrent: boolean;
@@ -78,6 +90,15 @@ export class ChannelState<ErmisChatGenerics extends ExtendableGenerics = Default
78
90
  this.messageSets[index].messages = messages;
79
91
  }
80
92
 
93
+ /**
94
+ * Pushes a new message directly into the sorted array of the local tracking state.
95
+ * Useful to achieve optimistic UI updates locally.
96
+ *
97
+ * @param newMessage - The message context payload to insert.
98
+ * @param timestampChanged - Specifies if the underlying `created_at` timestamp mutated.
99
+ * @param addIfDoesNotExist - Append it strictly if its ID doesn't already exist.
100
+ * @param messageSetToAddToIfDoesNotExist - Specifies which message set scope to manipulate.
101
+ */
81
102
  addMessageSorted(
82
103
  newMessage: MessageResponse<ErmisChatGenerics>,
83
104
  timestampChanged = false,
@@ -356,6 +377,12 @@ export class ChannelState<ErmisChatGenerics extends ExtendableGenerics = Default
356
377
  return { removed: result.length < msgArray.length, result };
357
378
  };
358
379
 
380
+ /**
381
+ * Refreshes internal user references cascading across all presently active messages.
382
+ * Invoked instantly whenever an underlying user's profile metadata updates (e.g. name or avatar changes).
383
+ *
384
+ * @param user - The newly formatted and populated User details object.
385
+ */
359
386
  updateUserMessages = (user: UserResponse<ErmisChatGenerics>) => {
360
387
  const _updateUserMessages = (
361
388
  messages: Array<ReturnType<ChannelState<ErmisChatGenerics>['formatMessage']>>,
package/src/client.ts CHANGED
@@ -53,39 +53,69 @@ import {
53
53
  function isString(x: unknown): x is string {
54
54
  return typeof x === 'string' || x instanceof String;
55
55
  }
56
+ /**
57
+ * The ErmisChat Client represents the connection securely established between your application
58
+ * and the Ermis core servers. It acts as the primary access point for real-time messaging,
59
+ * presence updates, call management, and channel querying.
60
+ *
61
+ * It is highly recommended to instantiate this class as a Singleton via `ErmisChat.getInstance()`.
62
+ */
56
63
  export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics> {
57
64
  private static _instance?: unknown | ErmisChat; // type is undefined|ErmisChat, unknown is due to TS limitations with statics
58
65
 
66
+ /** A map of active channels currently tracked by the client, keyed by Channel ID. */
59
67
  activeChannels: {
60
68
  [key: string]: Channel<ErmisChatGenerics>;
61
69
  };
70
+ /** The internal configured Axios instance used for REST API requests. */
62
71
  axiosInstance: AxiosInstance;
72
+ /** The primary base URL for REST API communication. */
63
73
  baseURL?: string;
74
+ /** The specific base URL for standard user-focused REST calls. */
64
75
  userBaseURL?: string;
76
+ /** True when the SDK is executed inside a browser environment. */
65
77
  browser: boolean;
66
78
  cleaningIntervalRef?: NodeJS.Timeout;
67
79
  clientID?: string;
68
80
  apiKey: string;
69
81
  projectId: string;
82
+ /** Internal mapped registry of event listeners. */
70
83
  listeners: Record<string, Array<(event: Event<ErmisChatGenerics>) => void>>;
71
84
  logger: Logger;
85
+ /** Whether the client should automatically fetch missing messages upon unexpected disconnects. */
72
86
  recoverStateOnReconnect?: boolean;
87
+ /** True when the SDK is executed in a NodeJS environment constraint. */
73
88
  node: boolean;
89
+ /** Custom options passed during client initialization. */
74
90
  options: ErmisChatOptions;
75
91
  setUserPromise: ConnectAPIResponse<ErmisChatGenerics> | null;
92
+ /** Centralized global state orchestrating user and client metadata. */
76
93
  state: ClientState<ErmisChatGenerics>;
77
94
  tokenManager: TokenManager<ErmisChatGenerics>;
95
+ /** The globally authenticated current user object. */
78
96
  user?: UserResponse<ErmisChatGenerics>;
79
97
  userAgent?: string;
98
+ /** The unique ID of the current authenticated user. */
80
99
  userID?: string;
100
+ /** The configured WebSocket endpoint base URL for realtime subscriptions. */
81
101
  wsBaseURL?: string;
102
+ /** The active WebSocket connection controller. */
82
103
  wsConnection: StableWSConnection<ErmisChatGenerics> | null;
83
104
  wsPromise: ConnectAPIResponse<ErmisChatGenerics> | null;
105
+ /** Tracks consecutive REST API failures for exponential backoff purposes. */
84
106
  consecutiveFailures: number;
85
107
  defaultWSTimeout: number;
86
108
 
87
109
  private eventSource: EventSourcePolyfill | null = null;
88
110
 
111
+ /**
112
+ * Initializes a new Ermis Chat Client instance.
113
+ *
114
+ * @param apiKey - Your public Ermis Network API Key.
115
+ * @param projectId - Your specific Project UUID pointing to the app config.
116
+ * @param baseURL - The API base endpoint assigned to your project.
117
+ * @param options - Additional connection rules and configuration options.
118
+ */
89
119
  constructor(apiKey: string, projectId: string, baseURL: string, options?: ErmisChatOptions) {
90
120
  this.apiKey = apiKey;
91
121
  this.projectId = projectId;
@@ -132,6 +162,16 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
132
162
  this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
133
163
  }
134
164
 
165
+ /**
166
+ * Retrieves the globally registered Singleton instance of the ErmisChat client.
167
+ * If the instance lacks existence, it initializes a new one.
168
+ *
169
+ * @param key - Your public Ermis Network API Key.
170
+ * @param projectId - Your specific Project UUID.
171
+ * @param baseURL - The API base endpoint.
172
+ * @param options - Connection options.
173
+ * @returns The shared ErmisChat client instance.
174
+ */
135
175
  public static getInstance<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>(
136
176
  key: string,
137
177
  projectId: string,
@@ -190,6 +230,15 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
190
230
  return await response.json();
191
231
  }
192
232
 
233
+ /**
234
+ * Connects a user to the Ermis network and establishes the WebSocket connection.
235
+ * This is the primary method to authenticate your client application.
236
+ *
237
+ * @param user - The User object containing `id`, `name`, and optional `avatar`.
238
+ * @param userTokenOrProvider - The JWT token or an async token provider function.
239
+ * @param extenal_auth - Set to `true` to use your custom backend external authentication flow.
240
+ * @returns A promise resolving to the API connection response once authenticated.
241
+ */
193
242
  connectUser = async (
194
243
  user: UserResponse<ErmisChatGenerics>,
195
244
  userTokenOrProvider: string | null,
@@ -305,6 +354,12 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
305
354
 
306
355
  _setupConnection = this.openConnection;
307
356
 
357
+ /**
358
+ * Gracefully disconnects the current user, terminates the WebSocket connection,
359
+ * cleans up listeners, and resets the client's internal references.
360
+ *
361
+ * @param timeout - Optional timeout in milliseconds before forcing the disconnect.
362
+ */
308
363
  disconnectUser = async (timeout?: number) => {
309
364
  this.logger('info', 'client:disconnect() - Disconnecting the client', {
310
365
  tags: ['connection', 'client'],
@@ -332,7 +387,21 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
332
387
 
333
388
  disconnect = this.disconnectUser;
334
389
 
390
+ /**
391
+ * Attaches an event listener to the client connection.
392
+ * Listeners can be scoped to specific event types (e.g. `message.new`) or listen to `all` events.
393
+ *
394
+ * @param callback - The handler invoked when the event is emitted.
395
+ * @returns An object containing an `unsubscribe` method to detach the listener.
396
+ */
335
397
  on(callback: EventHandler<ErmisChatGenerics>): { unsubscribe: () => void };
398
+ /**
399
+ * Attaches an event listener filtered by a specific event type.
400
+ *
401
+ * @param eventType - The specific event name to listen for (e.g., `'notification.message_new'`).
402
+ * @param callback - The handler invoked when the event is emitted.
403
+ * @returns An object containing an `unsubscribe` method to detach the listener.
404
+ */
336
405
  on(eventType: string, callback: EventHandler<ErmisChatGenerics>): { unsubscribe: () => void };
337
406
  on(
338
407
  callbackOrString: EventHandler<ErmisChatGenerics> | string,
@@ -357,7 +426,16 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
357
426
  };
358
427
  }
359
428
 
429
+ /**
430
+ * Detaches a previously registered general event listener.
431
+ * @param callback - The original handler reference to remove.
432
+ */
360
433
  off(callback: EventHandler<ErmisChatGenerics>): void;
434
+ /**
435
+ * Detaches a previously registered event listener scoped to a specific event type.
436
+ * @param eventType - The specific event name.
437
+ * @param callback - The original handler reference to remove.
438
+ */
361
439
  off(eventType: string, callback: EventHandler<ErmisChatGenerics>): void;
362
440
  off(callbackOrString: EventHandler<ErmisChatGenerics> | string, callbackOrNothing?: EventHandler<ErmisChatGenerics>) {
363
441
  const key = callbackOrNothing ? (callbackOrString as string) : 'all';
@@ -1035,6 +1113,16 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
1035
1113
  return response;
1036
1114
  }
1037
1115
 
1116
+ /**
1117
+ * Queries the API for a list of channels based on provided search filters and sort conditions.
1118
+ * Also hydrates these channels into the local SDK state memory.
1119
+ *
1120
+ * @param filterConditions - Specific criteria to filter channels (e.g. `{ type: 'messaging', members: { $in: ['user1'] } }`).
1121
+ * @param sort - The sorting hierarchy applied to the channel results.
1122
+ * @param options - Pagination and message limit parameters.
1123
+ * @param stateOptions - Defines whether to skip state initialization or offline usage.
1124
+ * @returns An array of hydrated and locally manageable `Channel` objects.
1125
+ */
1038
1126
  async queryChannels(
1039
1127
  filterConditions: ChannelFilters,
1040
1128
  sort: ChannelSort = [],
@@ -1192,7 +1280,23 @@ export class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGen
1192
1280
  return await this.post<APIResponse>(this.baseURL + `/channels/${channelType}/${channelId}/unpin`);
1193
1281
  }
1194
1282
 
1283
+ /**
1284
+ * Creates or instantiates an interactive `Channel` object locally based on type and custom data.
1285
+ * This does NOT immediately ping the API unless `channel.watch()` or `channel.create()` is subsequently called.
1286
+ *
1287
+ * @param type - The strict channel type descriptor (e.g., `'messaging'`, `'team'`, `'livestream'`).
1288
+ * @param custom - Initial metadata or specific members to include in the channel.
1289
+ * @returns A newly instantiated `Channel` object.
1290
+ */
1195
1291
  channel(type: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1292
+ /**
1293
+ * Creates or instantiates an interactive `Channel` object locally using a specific ID.
1294
+ *
1295
+ * @param type - The strict channel type descriptor.
1296
+ * @param id - The unique identifer (UUID / slug) for the channel.
1297
+ * @param custom - Initial metadata or specific members to include in the channel.
1298
+ * @returns A newly instantiated `Channel` object.
1299
+ */
1196
1300
  channel(type: string, id: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1197
1301
  channel(
1198
1302
  channelType: string,