@ermis-network/ermis-chat-sdk 1.0.2 → 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.
@@ -356,15 +356,25 @@ var createForwardMessagePayload = (message, targetCid, activeCid) => {
356
356
  // src/channel_state.ts
357
357
  var ChannelState = class {
358
358
  _channel;
359
+ /** The current count of users actively watching (having an open WebSocket) this channel. */
359
360
  watcher_count;
361
+ /** A dictionary of active typing events gracefully keyed by the user's ID. */
360
362
  typing;
363
+ /** A dictionary of read states mapped per user's ID detailing the last viewed message. */
361
364
  read;
365
+ /** The locally cached array of pinned messages across the channel. */
362
366
  pinnedMessages;
367
+ /** A directory of users actively watching the channel, keyed by User ID. */
363
368
  watchers;
369
+ /** A comprehensive directory mapping user IDs to their member status in the channel. */
364
370
  members;
371
+ /** The count of messages not yet read by the currently authenticated user. */
365
372
  unreadCount;
373
+ /** Information detailing the authenticated user's own membership relation to this channel. */
366
374
  membership;
375
+ /** Timestamp indicating when the very last message was created in this chat. */
367
376
  last_message_at;
377
+ /** Designates if the local channel state is entirely synchronized with the backend history. */
368
378
  isUpToDate;
369
379
  messageSets = [];
370
380
  topics = [];
@@ -396,6 +406,15 @@ var ChannelState = class {
396
406
  const index = this.messageSets.findIndex((s) => s.isLatest);
397
407
  this.messageSets[index].messages = messages;
398
408
  }
409
+ /**
410
+ * Pushes a new message directly into the sorted array of the local tracking state.
411
+ * Useful to achieve optimistic UI updates locally.
412
+ *
413
+ * @param newMessage - The message context payload to insert.
414
+ * @param timestampChanged - Specifies if the underlying `created_at` timestamp mutated.
415
+ * @param addIfDoesNotExist - Append it strictly if its ID doesn't already exist.
416
+ * @param messageSetToAddToIfDoesNotExist - Specifies which message set scope to manipulate.
417
+ */
399
418
  addMessageSorted(newMessage, timestampChanged = false, addIfDoesNotExist = true, messageSetToAddToIfDoesNotExist = "latest") {
400
419
  return this.addMessagesSorted(
401
420
  [newMessage],
@@ -583,6 +602,12 @@ var ChannelState = class {
583
602
  const result = msgArray.filter((message) => !(!!message.id && !!msg.id && message.id === msg.id));
584
603
  return { removed: result.length < msgArray.length, result };
585
604
  };
605
+ /**
606
+ * Refreshes internal user references cascading across all presently active messages.
607
+ * Invoked instantly whenever an underlying user's profile metadata updates (e.g. name or avatar changes).
608
+ *
609
+ * @param user - The newly formatted and populated User details object.
610
+ */
586
611
  updateUserMessages = (user) => {
587
612
  const _updateUserMessages = (messages, user2) => {
588
613
  for (let i = 0; i < messages.length; i++) {
@@ -854,6 +879,15 @@ var Channel = class {
854
879
  lastTypingEvent;
855
880
  isTyping;
856
881
  disconnected;
882
+ /**
883
+ * Initializes a new Channel class instance.
884
+ * Normally you should not call this directly; use `client.channel(type, id)` instead.
885
+ *
886
+ * @param client - The shared ErmisChat client instance initializing this channel.
887
+ * @param type - The type of channel (`messaging`, `team`, `livestream`, etc.).
888
+ * @param id - The unique ID of the channel.
889
+ * @param data - Initial arbitrary metadata stored within this channel.
890
+ */
857
891
  constructor(client, type, id, data) {
858
892
  const validTypeRe = /^[\w_-]+$/;
859
893
  const validIDRe = /^[\w!:_-]+$/;
@@ -880,6 +914,13 @@ var Channel = class {
880
914
  getClient() {
881
915
  return this._client;
882
916
  }
917
+ /**
918
+ * Sends a message to this channel.
919
+ * By default, it pushes the message eagerly (optimistically) to the local UI state before the server replies.
920
+ *
921
+ * @param message - The constructed text/attachment object payload representing the message.
922
+ * @returns A Promise resolving to the exact API response encompassing message details.
923
+ */
883
924
  async sendMessage(message) {
884
925
  if (!message.id) {
885
926
  message = { ...message, id: randomId() };
@@ -1109,6 +1150,11 @@ var Channel = class {
1109
1150
  const url = this.getClient().baseURL + `/invites/${this.type}/${this.id}/skip`;
1110
1151
  return this.getClient().post(url);
1111
1152
  }
1153
+ /**
1154
+ * Directly invites or adds registered users into this channel.
1155
+ *
1156
+ * @param members - Array of user IDs explicitly selected to be added.
1157
+ */
1112
1158
  async addMembers(members) {
1113
1159
  return await this._update({ add_members: members });
1114
1160
  }
@@ -1174,6 +1220,11 @@ var Channel = class {
1174
1220
  })
1175
1221
  };
1176
1222
  }
1223
+ /**
1224
+ * Expels specified currently participating users out of the channel.
1225
+ *
1226
+ * @param members - Array of user IDs to strictly remove from this chat.
1227
+ */
1177
1228
  async removeMembers(members) {
1178
1229
  return await this._update({ remove_members: members });
1179
1230
  }
@@ -1253,6 +1304,10 @@ var Channel = class {
1253
1304
  messageSlice.sort((a, b) => b.created_at.getTime() - a.created_at.getTime());
1254
1305
  return messageSlice[0];
1255
1306
  }
1307
+ /**
1308
+ * Emits a mark-read event, updating the backend that the authenticated user has viewed up to the latest known message.
1309
+ * @returns Successful acknowledgement from the server.
1310
+ */
1256
1311
  async markRead() {
1257
1312
  return await this.getClient().post(this._channelURL() + "/read");
1258
1313
  }
@@ -1266,6 +1321,13 @@ var Channel = class {
1266
1321
  }
1267
1322
  this.state.clean();
1268
1323
  }
1324
+ /**
1325
+ * Subscribes to realtime events (WebSocket) for this channel, grabs the latest available metadata,
1326
+ * loads the most recent messages, and initializes the local state.
1327
+ *
1328
+ * @param options - Pagination limits like `{ watch: true, presence: true, state: true }`.
1329
+ * @returns The synchronized comprehensive channel state.
1330
+ */
1269
1331
  async watch(options) {
1270
1332
  await this.getClient().wsPromise;
1271
1333
  const combined = { ...options };
@@ -2703,32 +2765,55 @@ function isString(x) {
2703
2765
  var ErmisChat = class _ErmisChat {
2704
2766
  static _instance;
2705
2767
  // type is undefined|ErmisChat, unknown is due to TS limitations with statics
2768
+ /** A map of active channels currently tracked by the client, keyed by Channel ID. */
2706
2769
  activeChannels;
2770
+ /** The internal configured Axios instance used for REST API requests. */
2707
2771
  axiosInstance;
2772
+ /** The primary base URL for REST API communication. */
2708
2773
  baseURL;
2774
+ /** The specific base URL for standard user-focused REST calls. */
2709
2775
  userBaseURL;
2776
+ /** True when the SDK is executed inside a browser environment. */
2710
2777
  browser;
2711
2778
  cleaningIntervalRef;
2712
2779
  clientID;
2713
2780
  apiKey;
2714
2781
  projectId;
2782
+ /** Internal mapped registry of event listeners. */
2715
2783
  listeners;
2716
2784
  logger;
2785
+ /** Whether the client should automatically fetch missing messages upon unexpected disconnects. */
2717
2786
  recoverStateOnReconnect;
2787
+ /** True when the SDK is executed in a NodeJS environment constraint. */
2718
2788
  node;
2789
+ /** Custom options passed during client initialization. */
2719
2790
  options;
2720
2791
  setUserPromise;
2792
+ /** Centralized global state orchestrating user and client metadata. */
2721
2793
  state;
2722
2794
  tokenManager;
2795
+ /** The globally authenticated current user object. */
2723
2796
  user;
2724
2797
  userAgent;
2798
+ /** The unique ID of the current authenticated user. */
2725
2799
  userID;
2800
+ /** The configured WebSocket endpoint base URL for realtime subscriptions. */
2726
2801
  wsBaseURL;
2802
+ /** The active WebSocket connection controller. */
2727
2803
  wsConnection;
2728
2804
  wsPromise;
2805
+ /** Tracks consecutive REST API failures for exponential backoff purposes. */
2729
2806
  consecutiveFailures;
2730
2807
  defaultWSTimeout;
2731
2808
  eventSource = null;
2809
+ /**
2810
+ * Initializes a new Ermis Chat Client instance.
2811
+ *
2812
+ * @param apiKey - Your public Ermis Network API Key.
2813
+ * @param projectId - Your specific Project UUID pointing to the app config.
2814
+ * @param baseURL - The API base endpoint assigned to your project.
2815
+ * @param options - Additional connection rules and configuration options.
2816
+ */
2732
2817
  constructor(apiKey, projectId, baseURL, options) {
2733
2818
  this.apiKey = apiKey;
2734
2819
  this.projectId = projectId;
@@ -2762,6 +2847,16 @@ var ErmisChat = class _ErmisChat {
2762
2847
  this.logger = isFunction(inputOptions.logger) ? inputOptions.logger : () => null;
2763
2848
  this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
2764
2849
  }
2850
+ /**
2851
+ * Retrieves the globally registered Singleton instance of the ErmisChat client.
2852
+ * If the instance lacks existence, it initializes a new one.
2853
+ *
2854
+ * @param key - Your public Ermis Network API Key.
2855
+ * @param projectId - Your specific Project UUID.
2856
+ * @param baseURL - The API base endpoint.
2857
+ * @param options - Connection options.
2858
+ * @returns The shared ErmisChat client instance.
2859
+ */
2765
2860
  static getInstance(key, projectId, baseURL, options) {
2766
2861
  if (!_ErmisChat._instance) {
2767
2862
  _ErmisChat._instance = new _ErmisChat(key, projectId, baseURL, options);
@@ -2809,6 +2904,15 @@ var ErmisChat = class _ErmisChat {
2809
2904
  }
2810
2905
  return await response.json();
2811
2906
  }
2907
+ /**
2908
+ * Connects a user to the Ermis network and establishes the WebSocket connection.
2909
+ * This is the primary method to authenticate your client application.
2910
+ *
2911
+ * @param user - The User object containing `id`, `name`, and optional `avatar`.
2912
+ * @param userTokenOrProvider - The JWT token or an async token provider function.
2913
+ * @param extenal_auth - Set to `true` to use your custom backend external authentication flow.
2914
+ * @returns A promise resolving to the API connection response once authenticated.
2915
+ */
2812
2916
  connectUser = async (user, userTokenOrProvider, extenal_auth) => {
2813
2917
  this.logger("info", "client:connectUser() - started", {
2814
2918
  tags: ["connection", "client"]
@@ -2891,6 +2995,12 @@ var ErmisChat = class _ErmisChat {
2891
2995
  return this.wsPromise;
2892
2996
  };
2893
2997
  _setupConnection = this.openConnection;
2998
+ /**
2999
+ * Gracefully disconnects the current user, terminates the WebSocket connection,
3000
+ * cleans up listeners, and resets the client's internal references.
3001
+ *
3002
+ * @param timeout - Optional timeout in milliseconds before forcing the disconnect.
3003
+ */
2894
3004
  disconnectUser = async (timeout) => {
2895
3005
  this.logger("info", "client:disconnect() - Disconnecting the client", {
2896
3006
  tags: ["connection", "client"]
@@ -3456,6 +3566,16 @@ var ErmisChat = class _ErmisChat {
3456
3566
  this.state.updateUser(response);
3457
3567
  return response;
3458
3568
  }
3569
+ /**
3570
+ * Queries the API for a list of channels based on provided search filters and sort conditions.
3571
+ * Also hydrates these channels into the local SDK state memory.
3572
+ *
3573
+ * @param filterConditions - Specific criteria to filter channels (e.g. `{ type: 'messaging', members: { $in: ['user1'] } }`).
3574
+ * @param sort - The sorting hierarchy applied to the channel results.
3575
+ * @param options - Pagination and message limit parameters.
3576
+ * @param stateOptions - Defines whether to skip state initialization or offline usage.
3577
+ * @returns An array of hydrated and locally manageable `Channel` objects.
3578
+ */
3459
3579
  async queryChannels(filterConditions, sort = [], options = {}, stateOptions = {}) {
3460
3580
  await this.wsPromise;
3461
3581
  let project_id = this.projectId;
@@ -3607,7 +3727,7 @@ var ErmisChat = class _ErmisChat {
3607
3727
  return pinExpires;
3608
3728
  }
3609
3729
  getUserAgent() {
3610
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.2"}`;
3730
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.4"}`;
3611
3731
  }
3612
3732
  setUserAgent(userAgent) {
3613
3733
  this.userAgent = userAgent;
@@ -6316,21 +6436,38 @@ var ErmisCallNode = class {
6316
6436
  const mediaConstraints = await this.getMediaConstraints();
6317
6437
  try {
6318
6438
  const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6319
- if (this.callStatus === "ended" /* ENDED */) {
6320
- stream.getTracks().forEach((track) => track.stop());
6321
- this.destroy();
6322
- return;
6439
+ return this.applyLocalStream(stream);
6440
+ } catch (error) {
6441
+ console.warn("Error getting user media:", error?.message);
6442
+ if (this.callType === "video" && mediaConstraints.video) {
6443
+ try {
6444
+ const audioOnlyStream = await navigator.mediaDevices.getUserMedia({
6445
+ audio: mediaConstraints.audio,
6446
+ video: false
6447
+ });
6448
+ this.setConnectionMessage("Camera not available, using audio only");
6449
+ return this.applyLocalStream(audioOnlyStream);
6450
+ } catch {
6451
+ }
6323
6452
  }
6324
- if (this.onLocalStream) {
6325
- this.onLocalStream(stream);
6453
+ if (typeof this.onError === "function") {
6454
+ this.onError("No microphone or camera found. Please check your device.");
6326
6455
  }
6327
- this.localStream = stream;
6328
- return stream;
6329
- } catch (error) {
6330
- console.error("Error getting user media:", error);
6331
6456
  return null;
6332
6457
  }
6333
6458
  }
6459
+ applyLocalStream(stream) {
6460
+ if (this.callStatus === "ended" /* ENDED */) {
6461
+ stream.getTracks().forEach((track) => track.stop());
6462
+ this.destroy();
6463
+ return;
6464
+ }
6465
+ if (this.onLocalStream) {
6466
+ this.onLocalStream(stream);
6467
+ }
6468
+ this.localStream = stream;
6469
+ return stream;
6470
+ }
6334
6471
  setConnectionMessage(message) {
6335
6472
  if (typeof this.onConnectionMessageChange === "function") {
6336
6473
  this.onConnectionMessageChange(message);
@@ -6375,20 +6512,10 @@ var ErmisCallNode = class {
6375
6512
  this.isDestroyed = false;
6376
6513
  this.callStatus = "";
6377
6514
  this.callType = is_video ? "video" : "audio";
6378
- await this.startLocalStream();
6379
- if (this.callStatus === "ended" /* ENDED */) return;
6380
6515
  this.setUserInfo(cid, eventUserId);
6381
6516
  this.setCallStatus("ringing" /* RINGING */);
6382
6517
  this.cid = cid || "";
6383
6518
  this.metadata = metadata || {};
6384
- console.log("----metadata---", metadata);
6385
- if (eventUserId !== this.userID) {
6386
- await this.initialize();
6387
- }
6388
- if (this.localStream && this.mediaSender && this.mediaReceiver) {
6389
- this.mediaSender?.initEncoders(this.localStream);
6390
- this.mediaReceiver?.initDecoders(this.callType);
6391
- }
6392
6519
  if (typeof this.onCallEvent === "function") {
6393
6520
  this.onCallEvent({
6394
6521
  type: eventUserId !== this.userID ? "incoming" : "outgoing",
@@ -6399,6 +6526,15 @@ var ErmisCallNode = class {
6399
6526
  metadata: this.metadata
6400
6527
  });
6401
6528
  }
6529
+ await this.startLocalStream();
6530
+ if (this.callStatus === "ended" /* ENDED */) return;
6531
+ if (eventUserId !== this.userID) {
6532
+ await this.initialize();
6533
+ }
6534
+ if (this.localStream && this.mediaSender && this.mediaReceiver) {
6535
+ this.mediaSender?.initEncoders(this.localStream);
6536
+ this.mediaReceiver?.initDecoders(this.callType);
6537
+ }
6402
6538
  if (eventUserId === this.userID) {
6403
6539
  if (this.missCallTimeout) clearTimeout(this.missCallTimeout);
6404
6540
  this.missCallTimeout = setTimeout(async () => {
@@ -6659,21 +6795,30 @@ var ErmisCallNode = class {
6659
6795
  }
6660
6796
  async stopScreenShare() {
6661
6797
  const mediaConstraints = await this.getMediaConstraints();
6662
- const cameraStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6663
- const cameraTrack = cameraStream.getVideoTracks()[0];
6664
- if (this.localStream) {
6665
- this.localStream.getVideoTracks().forEach((track) => track.stop());
6666
- this.localStream.removeTrack(this.localStream.getVideoTracks()[0]);
6667
- this.localStream.addTrack(cameraTrack);
6668
- } else {
6669
- this.localStream = cameraStream;
6670
- }
6671
- if (this.onLocalStream) {
6672
- this.onLocalStream(this.localStream);
6673
- this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6674
- }
6675
- if (typeof this.onScreenShareChange === "function") {
6676
- this.onScreenShareChange(false);
6798
+ try {
6799
+ const cameraStream = await navigator.mediaDevices.getUserMedia({
6800
+ video: mediaConstraints.video,
6801
+ audio: false
6802
+ });
6803
+ const cameraTrack = cameraStream.getVideoTracks()[0];
6804
+ if (this.localStream) {
6805
+ this.localStream.getVideoTracks().forEach((track) => {
6806
+ track.stop();
6807
+ this.localStream?.removeTrack(track);
6808
+ });
6809
+ this.localStream.addTrack(cameraTrack);
6810
+ } else {
6811
+ this.localStream = cameraStream;
6812
+ }
6813
+ if (this.onLocalStream) {
6814
+ this.onLocalStream(this.localStream);
6815
+ this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6816
+ }
6817
+ if (typeof this.onScreenShareChange === "function") {
6818
+ this.onScreenShareChange(false);
6819
+ }
6820
+ } catch (error) {
6821
+ console.error("Error stopping screen share and reverting to camera:", error);
6677
6822
  }
6678
6823
  }
6679
6824
  async toggleMic(enabled) {
@@ -6940,7 +7085,7 @@ var ErmisAuthProvider = class {
6940
7085
  return data;
6941
7086
  }
6942
7087
  getUserAgent() {
6943
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.2"}`;
7088
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.4"}`;
6944
7089
  }
6945
7090
  setUserAgent(userAgent) {
6946
7091
  this.userAgent = userAgent;
@@ -7173,70 +7318,116 @@ function parseSystemMessage(value, userMap) {
7173
7318
  }
7174
7319
 
7175
7320
  // src/signal_message.ts
7176
- function formatDuration(durationSec) {
7177
- const sec = parseInt(durationSec, 10);
7178
- if (isNaN(sec) || sec < 0) return durationSec;
7179
- const minutes = Math.floor(sec / 60);
7180
- const seconds = sec % 60;
7181
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
7182
- }
7183
- function resolveUser2(userId, userMap) {
7184
- return userMap[userId] ?? userId;
7321
+ var CallType = {
7322
+ AUDIO: "audio",
7323
+ VIDEO: "video"
7324
+ };
7325
+ function formatDuration(durationMs) {
7326
+ if (!durationMs) return "";
7327
+ const ms = parseInt(durationMs, 10);
7328
+ if (isNaN(ms) || ms <= 0) return "";
7329
+ const totalSeconds = Math.floor(ms / 1e3);
7330
+ const minutes = Math.floor(totalSeconds / 60);
7331
+ const seconds = totalSeconds % 60;
7332
+ return `${minutes} min, ${seconds} sec`;
7185
7333
  }
7186
- function parseSignalMessage(value, userMap) {
7187
- if (!value || typeof value !== "string") return value ?? "";
7334
+ function parseSignalMessage(value, myUserId) {
7335
+ if (!value || typeof value !== "string") return null;
7188
7336
  const trimmed = value.trim();
7189
- if (!trimmed) return "";
7337
+ if (!trimmed) return null;
7190
7338
  const parts = trimmed.split(" ");
7191
- const formatId = parts[0];
7192
- const userId = parts[1] ?? "";
7193
- const userName = userId ? resolveUser2(userId, userMap) : "User";
7194
- switch (formatId) {
7195
- // 1: Audio call started
7196
- case "1":
7197
- return `\u{1F4DE} ${userName} started an audio call.`;
7198
- // 2: Audio call missed
7199
- case "2":
7200
- return `\u{1F4DE} Missed audio call from ${userName}.`;
7201
- // 3: Audio call ended (caller_id ender_id duration)
7202
- case "3": {
7203
- const enderId = parts[2] ?? "";
7204
- const duration = parts[3] ?? "0";
7205
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7206
- return `\u{1F4DE} Audio call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7207
- }
7208
- // 4: Video call started
7209
- case "4":
7210
- return `\u{1F4F9} ${userName} started a video call.`;
7211
- // 5: Video call missed
7212
- case "5":
7213
- return `\u{1F4F9} Missed video call from ${userName}.`;
7214
- // 6: Video call ended (caller_id ender_id duration)
7215
- case "6": {
7216
- const enderId = parts[2] ?? "";
7217
- const duration = parts[3] ?? "0";
7218
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7219
- return `\u{1F4F9} Video call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7220
- }
7221
- // 7: Audio call rejected
7222
- case "7":
7223
- return `\u{1F4DE} Audio call from ${userName} was rejected.`;
7224
- // 8: Video call rejected
7225
- case "8":
7226
- return `\u{1F4F9} Video call from ${userName} was rejected.`;
7227
- // 9: Audio call busy
7228
- case "9":
7229
- return `\u{1F4DE} Audio call from ${userName} \u2014 recipient was busy.`;
7230
- // 10: Video call busy
7231
- case "10":
7232
- return `\u{1F4F9} Video call from ${userName} \u2014 recipient was busy.`;
7339
+ const number = parseInt(parts[0], 10);
7340
+ const callerId = parts[1] ?? "";
7341
+ const isMe = myUserId === callerId;
7342
+ let enderId = "";
7343
+ let duration = "";
7344
+ let callType = "";
7345
+ let color = "";
7346
+ if (number === 3 || number === 6) {
7347
+ enderId = parts[2] ?? "";
7348
+ duration = parts[3] === "0" ? "" : parts[3] ?? "";
7349
+ }
7350
+ let text;
7351
+ switch (number) {
7352
+ case 1:
7353
+ text = isMe ? "Calling..." : "Incoming audio call...";
7354
+ callType = CallType.AUDIO;
7355
+ color = "#54D62C";
7356
+ break;
7357
+ case 2:
7358
+ text = isMe ? "Outgoing audio call" : "You missed audio call";
7359
+ callType = CallType.AUDIO;
7360
+ color = "#FF4842";
7361
+ break;
7362
+ case 3:
7363
+ if (duration) {
7364
+ text = isMe ? "Outgoing audio call" : "Incoming audio call";
7365
+ color = "#54D62C";
7366
+ } else {
7367
+ if (enderId === myUserId) {
7368
+ text = "You cancel audio call";
7369
+ } else {
7370
+ text = "You missed audio call";
7371
+ }
7372
+ color = "#FF4842";
7373
+ }
7374
+ callType = CallType.AUDIO;
7375
+ break;
7376
+ case 4:
7377
+ text = isMe ? "Calling..." : "Incoming video call...";
7378
+ callType = CallType.VIDEO;
7379
+ color = "#54D62C";
7380
+ break;
7381
+ case 5:
7382
+ text = isMe ? "Outgoing video call" : "You missed video call";
7383
+ callType = CallType.VIDEO;
7384
+ color = "#FF4842";
7385
+ break;
7386
+ case 6:
7387
+ if (duration) {
7388
+ text = isMe ? "Outgoing video call" : "Incoming video call";
7389
+ color = "#54D62C";
7390
+ } else {
7391
+ if (enderId === myUserId) {
7392
+ text = "You cancel video call";
7393
+ } else {
7394
+ text = "You missed video call";
7395
+ }
7396
+ color = "#FF4842";
7397
+ }
7398
+ callType = CallType.VIDEO;
7399
+ break;
7400
+ case 7:
7401
+ text = isMe ? "Recipient rejected audio call" : "You rejected audio call";
7402
+ callType = CallType.AUDIO;
7403
+ color = "#FF4842";
7404
+ break;
7405
+ case 8:
7406
+ text = isMe ? "Recipient rejected video call" : "You rejected video call";
7407
+ callType = CallType.VIDEO;
7408
+ color = "#FF4842";
7409
+ break;
7410
+ case 9:
7411
+ text = isMe ? "Recipient was busy" : "You missed audio call";
7412
+ callType = CallType.AUDIO;
7413
+ color = "#FF4842";
7414
+ break;
7415
+ case 10:
7416
+ text = isMe ? "Recipient was busy" : "You missed video call";
7417
+ callType = CallType.VIDEO;
7418
+ color = "#FF4842";
7419
+ break;
7233
7420
  default:
7234
- return trimmed;
7421
+ text = trimmed;
7422
+ callType = "";
7423
+ color = "";
7235
7424
  }
7425
+ return { text, duration: formatDuration(duration), callType, color };
7236
7426
  }
7237
7427
  export {
7238
7428
  CallAction,
7239
7429
  CallStatus,
7430
+ CallType,
7240
7431
  Channel,
7241
7432
  ChannelState,
7242
7433
  ClientState,