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

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/index.d.mts CHANGED
@@ -1085,8 +1085,9 @@ declare class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGe
1085
1085
  searchPublicChannel(search_term: string, offset?: number, limit?: number): Promise<APIResponse>;
1086
1086
  pinChannel(channelType: string, channelId: string): Promise<APIResponse>;
1087
1087
  unpinChannel(channelType: string, channelId: string): Promise<APIResponse>;
1088
- channel(channelType: string, channelID: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1089
- getChannelById: (channelType: string, channelID: string, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1088
+ channel(type: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1089
+ channel(type: string, id: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1090
+ getChannelById: (channelType: string, channelID: string | undefined, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1090
1091
  getChannel: (channelType: string, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1091
1092
  _normalizeExpiration(timeoutOrExpirationDate?: null | number | string | Date): string | null;
1092
1093
  getUserAgent(): string;
@@ -1280,6 +1281,7 @@ declare class ErmisCallNode<ErmisChatGenerics extends ExtendableGenerics = Defau
1280
1281
  private getAvailableDevices;
1281
1282
  private getMediaConstraints;
1282
1283
  startLocalStream(): Promise<MediaStream | null | undefined>;
1284
+ private applyLocalStream;
1283
1285
  private setConnectionMessage;
1284
1286
  private setCallStatus;
1285
1287
  private setUserInfo;
@@ -1455,15 +1457,33 @@ declare const createForwardMessagePayload: <ErmisChatGenerics extends Extendable
1455
1457
  declare function parseSystemMessage(value: string, userMap: Record<string, string>): string;
1456
1458
 
1457
1459
  /**
1458
- * Parse a raw signal message string into a human-readable English sentence.
1460
+ * Call type constants for signal messages.
1461
+ */
1462
+ declare const CallType: {
1463
+ readonly AUDIO: "audio";
1464
+ readonly VIDEO: "video";
1465
+ };
1466
+ type CallTypeValue = (typeof CallType)[keyof typeof CallType];
1467
+ /**
1468
+ * Result of parsing a signal message.
1469
+ */
1470
+ interface SignalMessageResult {
1471
+ text: string;
1472
+ duration: string;
1473
+ callType: CallTypeValue | '';
1474
+ color: string;
1475
+ }
1476
+ /**
1477
+ * Parse a raw signal message string into a structured object
1478
+ * containing text, duration, call type, and color.
1459
1479
  *
1460
1480
  * Signal messages represent call events. The raw format is:
1461
- * `"<formatId> <userID> [<param1> <param2> ...]"`
1481
+ * `"<formatId> <callerId> [<enderId> <duration>]"`
1462
1482
  *
1463
- * @param value - Raw signal message string from the server
1464
- * @param userMap - Mapping of user IDs display names
1465
- * @returns Parsed English text, or the original string if unknown
1483
+ * @param value - Raw signal message string from the server
1484
+ * @param myUserId - The current user's ID (from client.userID)
1485
+ * @returns Parsed signal message object, or null if input is empty
1466
1486
  */
1467
- declare function parseSignalMessage(value: string, userMap: Record<string, string>): string;
1487
+ declare function parseSignalMessage(value: string, myUserId: string): SignalMessageResult | null;
1468
1488
 
1469
- export { type APIErrorResponse, type APIResponse, type AscDesc, type Attachment, type AttachmentResponse, type AudioConfig, CallAction, type CallEventData, type CallEventType, CallStatus, Channel, type ChannelAPIResponse, type ChannelData, type ChannelFilters, type ChannelMemberResponse, type ChannelMembership, type ChannelQueryOptions, type ChannelResponse, type ChannelSort, ChannelState, type ChannelStateOptions, ClientState, type ConnectAPIResponse, type ConnectionOpen, type Contact, type ContactResponse, type ContactResult, type DefaultGenerics, EVENT_MAP, type EditMessage, ErmisAuthProvider, ErmisCallNode, ErmisChat, type ErmisChatOptions, ErrorFromResponse, type Event$1 as Event, type EventHandler, type EventTypes, type ExtendableGenerics, FRAME_TYPE, type FormatMessageResponse, type ForwardMessage, type IMediaReceiverEvents, type INodeCall, type LiteralStringForUnion, type LogLevel, type Logger, type Message, type MessageBase, type MessageLabel, type MessageResponse, type MessageResponseBase, type MessageSetType, type Metadata, type PollMessage, type QueryChannelAPIResponse, type QueryChannelsAPIResponse, type Reaction, type ReactionAPIResponse, type ReactionResponse, type ReadResponse, type Role, type SendFileAPIResponse, type SendMessageAPIResponse, type SignalData, StableWSConnection, TokenManager, type TransceiverState, type UR, type UpdateChannelAPIResponse, type UserCallInfo, type UserResponse, type UsersResponse, type VideoConfig, type VoiceRecordingMeta, buildAttachmentPayload, chatCodes, createForwardMessagePayload, formatMessage, getAttachmentCategory, isHeicFile, isVideoFile, logChatPromiseExecution, normalizeFileName, parseSignalMessage, parseSystemMessage };
1489
+ export { type APIErrorResponse, type APIResponse, type AscDesc, type Attachment, type AttachmentResponse, type AudioConfig, CallAction, type CallEventData, type CallEventType, CallStatus, CallType, type CallTypeValue, Channel, type ChannelAPIResponse, type ChannelData, type ChannelFilters, type ChannelMemberResponse, type ChannelMembership, type ChannelQueryOptions, type ChannelResponse, type ChannelSort, ChannelState, type ChannelStateOptions, ClientState, type ConnectAPIResponse, type ConnectionOpen, type Contact, type ContactResponse, type ContactResult, type DefaultGenerics, EVENT_MAP, type EditMessage, ErmisAuthProvider, ErmisCallNode, ErmisChat, type ErmisChatOptions, ErrorFromResponse, type Event$1 as Event, type EventHandler, type EventTypes, type ExtendableGenerics, FRAME_TYPE, type FormatMessageResponse, type ForwardMessage, type IMediaReceiverEvents, type INodeCall, type LiteralStringForUnion, type LogLevel, type Logger, type Message, type MessageBase, type MessageLabel, type MessageResponse, type MessageResponseBase, type MessageSetType, type Metadata, type PollMessage, type QueryChannelAPIResponse, type QueryChannelsAPIResponse, type Reaction, type ReactionAPIResponse, type ReactionResponse, type ReadResponse, type Role, type SendFileAPIResponse, type SendMessageAPIResponse, type SignalData, type SignalMessageResult, StableWSConnection, TokenManager, type TransceiverState, type UR, type UpdateChannelAPIResponse, type UserCallInfo, type UserResponse, type UsersResponse, type VideoConfig, type VoiceRecordingMeta, buildAttachmentPayload, chatCodes, createForwardMessagePayload, formatMessage, getAttachmentCategory, isHeicFile, isVideoFile, logChatPromiseExecution, normalizeFileName, parseSignalMessage, parseSystemMessage };
package/dist/index.d.ts CHANGED
@@ -1085,8 +1085,9 @@ declare class ErmisChat<ErmisChatGenerics extends ExtendableGenerics = DefaultGe
1085
1085
  searchPublicChannel(search_term: string, offset?: number, limit?: number): Promise<APIResponse>;
1086
1086
  pinChannel(channelType: string, channelId: string): Promise<APIResponse>;
1087
1087
  unpinChannel(channelType: string, channelId: string): Promise<APIResponse>;
1088
- channel(channelType: string, channelID: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1089
- getChannelById: (channelType: string, channelID: string, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1088
+ channel(type: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1089
+ channel(type: string, id: string, custom?: ChannelData<ErmisChatGenerics>): Channel<ErmisChatGenerics>;
1090
+ getChannelById: (channelType: string, channelID: string | undefined, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1090
1091
  getChannel: (channelType: string, custom: ChannelData<ErmisChatGenerics>) => Channel<ErmisChatGenerics>;
1091
1092
  _normalizeExpiration(timeoutOrExpirationDate?: null | number | string | Date): string | null;
1092
1093
  getUserAgent(): string;
@@ -1280,6 +1281,7 @@ declare class ErmisCallNode<ErmisChatGenerics extends ExtendableGenerics = Defau
1280
1281
  private getAvailableDevices;
1281
1282
  private getMediaConstraints;
1282
1283
  startLocalStream(): Promise<MediaStream | null | undefined>;
1284
+ private applyLocalStream;
1283
1285
  private setConnectionMessage;
1284
1286
  private setCallStatus;
1285
1287
  private setUserInfo;
@@ -1455,15 +1457,33 @@ declare const createForwardMessagePayload: <ErmisChatGenerics extends Extendable
1455
1457
  declare function parseSystemMessage(value: string, userMap: Record<string, string>): string;
1456
1458
 
1457
1459
  /**
1458
- * Parse a raw signal message string into a human-readable English sentence.
1460
+ * Call type constants for signal messages.
1461
+ */
1462
+ declare const CallType: {
1463
+ readonly AUDIO: "audio";
1464
+ readonly VIDEO: "video";
1465
+ };
1466
+ type CallTypeValue = (typeof CallType)[keyof typeof CallType];
1467
+ /**
1468
+ * Result of parsing a signal message.
1469
+ */
1470
+ interface SignalMessageResult {
1471
+ text: string;
1472
+ duration: string;
1473
+ callType: CallTypeValue | '';
1474
+ color: string;
1475
+ }
1476
+ /**
1477
+ * Parse a raw signal message string into a structured object
1478
+ * containing text, duration, call type, and color.
1459
1479
  *
1460
1480
  * Signal messages represent call events. The raw format is:
1461
- * `"<formatId> <userID> [<param1> <param2> ...]"`
1481
+ * `"<formatId> <callerId> [<enderId> <duration>]"`
1462
1482
  *
1463
- * @param value - Raw signal message string from the server
1464
- * @param userMap - Mapping of user IDs display names
1465
- * @returns Parsed English text, or the original string if unknown
1483
+ * @param value - Raw signal message string from the server
1484
+ * @param myUserId - The current user's ID (from client.userID)
1485
+ * @returns Parsed signal message object, or null if input is empty
1466
1486
  */
1467
- declare function parseSignalMessage(value: string, userMap: Record<string, string>): string;
1487
+ declare function parseSignalMessage(value: string, myUserId: string): SignalMessageResult | null;
1468
1488
 
1469
- export { type APIErrorResponse, type APIResponse, type AscDesc, type Attachment, type AttachmentResponse, type AudioConfig, CallAction, type CallEventData, type CallEventType, CallStatus, Channel, type ChannelAPIResponse, type ChannelData, type ChannelFilters, type ChannelMemberResponse, type ChannelMembership, type ChannelQueryOptions, type ChannelResponse, type ChannelSort, ChannelState, type ChannelStateOptions, ClientState, type ConnectAPIResponse, type ConnectionOpen, type Contact, type ContactResponse, type ContactResult, type DefaultGenerics, EVENT_MAP, type EditMessage, ErmisAuthProvider, ErmisCallNode, ErmisChat, type ErmisChatOptions, ErrorFromResponse, type Event$1 as Event, type EventHandler, type EventTypes, type ExtendableGenerics, FRAME_TYPE, type FormatMessageResponse, type ForwardMessage, type IMediaReceiverEvents, type INodeCall, type LiteralStringForUnion, type LogLevel, type Logger, type Message, type MessageBase, type MessageLabel, type MessageResponse, type MessageResponseBase, type MessageSetType, type Metadata, type PollMessage, type QueryChannelAPIResponse, type QueryChannelsAPIResponse, type Reaction, type ReactionAPIResponse, type ReactionResponse, type ReadResponse, type Role, type SendFileAPIResponse, type SendMessageAPIResponse, type SignalData, StableWSConnection, TokenManager, type TransceiverState, type UR, type UpdateChannelAPIResponse, type UserCallInfo, type UserResponse, type UsersResponse, type VideoConfig, type VoiceRecordingMeta, buildAttachmentPayload, chatCodes, createForwardMessagePayload, formatMessage, getAttachmentCategory, isHeicFile, isVideoFile, logChatPromiseExecution, normalizeFileName, parseSignalMessage, parseSystemMessage };
1489
+ export { type APIErrorResponse, type APIResponse, type AscDesc, type Attachment, type AttachmentResponse, type AudioConfig, CallAction, type CallEventData, type CallEventType, CallStatus, CallType, type CallTypeValue, Channel, type ChannelAPIResponse, type ChannelData, type ChannelFilters, type ChannelMemberResponse, type ChannelMembership, type ChannelQueryOptions, type ChannelResponse, type ChannelSort, ChannelState, type ChannelStateOptions, ClientState, type ConnectAPIResponse, type ConnectionOpen, type Contact, type ContactResponse, type ContactResult, type DefaultGenerics, EVENT_MAP, type EditMessage, ErmisAuthProvider, ErmisCallNode, ErmisChat, type ErmisChatOptions, ErrorFromResponse, type Event$1 as Event, type EventHandler, type EventTypes, type ExtendableGenerics, FRAME_TYPE, type FormatMessageResponse, type ForwardMessage, type IMediaReceiverEvents, type INodeCall, type LiteralStringForUnion, type LogLevel, type Logger, type Message, type MessageBase, type MessageLabel, type MessageResponse, type MessageResponseBase, type MessageSetType, type Metadata, type PollMessage, type QueryChannelAPIResponse, type QueryChannelsAPIResponse, type Reaction, type ReactionAPIResponse, type ReactionResponse, type ReadResponse, type Role, type SendFileAPIResponse, type SendMessageAPIResponse, type SignalData, type SignalMessageResult, StableWSConnection, TokenManager, type TransceiverState, type UR, type UpdateChannelAPIResponse, type UserCallInfo, type UserResponse, type UsersResponse, type VideoConfig, type VoiceRecordingMeta, buildAttachmentPayload, chatCodes, createForwardMessagePayload, formatMessage, getAttachmentCategory, isHeicFile, isVideoFile, logChatPromiseExecution, normalizeFileName, parseSignalMessage, parseSystemMessage };
package/dist/index.mjs CHANGED
@@ -3545,17 +3545,24 @@ var ErmisChat = class _ErmisChat {
3545
3545
  async unpinChannel(channelType, channelId) {
3546
3546
  return await this.post(this.baseURL + `/channels/${channelType}/${channelId}/unpin`);
3547
3547
  }
3548
- channel(channelType, channelID, custom = {}) {
3548
+ channel(channelType, channelIDOrCustom, custom) {
3549
3549
  if (!this.userID) {
3550
3550
  throw Error("Call connectUser before creating a channel");
3551
3551
  }
3552
3552
  if (~channelType.indexOf(":")) {
3553
3553
  throw Error(`Invalid channel group ${channelType}, can't contain the : character`);
3554
3554
  }
3555
- return this.getChannelById(channelType, channelID, custom);
3555
+ let channelID = void 0;
3556
+ let customData = custom || {};
3557
+ if (typeof channelIDOrCustom === "string") {
3558
+ channelID = channelIDOrCustom;
3559
+ } else if (typeof channelIDOrCustom === "object" && channelIDOrCustom !== null) {
3560
+ customData = channelIDOrCustom;
3561
+ }
3562
+ return this.getChannelById(channelType, channelID, customData);
3556
3563
  }
3557
3564
  getChannelById = (channelType, channelID, custom) => {
3558
- const cid = `${channelType}:${channelID}`;
3565
+ const cid = `${channelType}:${channelID || ""}`;
3559
3566
  if (cid in this.activeChannels && !this.activeChannels[cid].disconnected) {
3560
3567
  const channel2 = this.activeChannels[cid];
3561
3568
  if (Object.keys(custom).length > 0) {
@@ -3598,7 +3605,7 @@ var ErmisChat = class _ErmisChat {
3598
3605
  return pinExpires;
3599
3606
  }
3600
3607
  getUserAgent() {
3601
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.1"}`;
3608
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.3"}`;
3602
3609
  }
3603
3610
  setUserAgent(userAgent) {
3604
3611
  this.userAgent = userAgent;
@@ -6307,21 +6314,38 @@ var ErmisCallNode = class {
6307
6314
  const mediaConstraints = await this.getMediaConstraints();
6308
6315
  try {
6309
6316
  const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6310
- if (this.callStatus === "ended" /* ENDED */) {
6311
- stream.getTracks().forEach((track) => track.stop());
6312
- this.destroy();
6313
- return;
6317
+ return this.applyLocalStream(stream);
6318
+ } catch (error) {
6319
+ console.warn("Error getting user media:", error?.message);
6320
+ if (this.callType === "video" && mediaConstraints.video) {
6321
+ try {
6322
+ const audioOnlyStream = await navigator.mediaDevices.getUserMedia({
6323
+ audio: mediaConstraints.audio,
6324
+ video: false
6325
+ });
6326
+ this.setConnectionMessage("Camera not available, using audio only");
6327
+ return this.applyLocalStream(audioOnlyStream);
6328
+ } catch {
6329
+ }
6314
6330
  }
6315
- if (this.onLocalStream) {
6316
- this.onLocalStream(stream);
6331
+ if (typeof this.onError === "function") {
6332
+ this.onError("No microphone or camera found. Please check your device.");
6317
6333
  }
6318
- this.localStream = stream;
6319
- return stream;
6320
- } catch (error) {
6321
- console.error("Error getting user media:", error);
6322
6334
  return null;
6323
6335
  }
6324
6336
  }
6337
+ applyLocalStream(stream) {
6338
+ if (this.callStatus === "ended" /* ENDED */) {
6339
+ stream.getTracks().forEach((track) => track.stop());
6340
+ this.destroy();
6341
+ return;
6342
+ }
6343
+ if (this.onLocalStream) {
6344
+ this.onLocalStream(stream);
6345
+ }
6346
+ this.localStream = stream;
6347
+ return stream;
6348
+ }
6325
6349
  setConnectionMessage(message) {
6326
6350
  if (typeof this.onConnectionMessageChange === "function") {
6327
6351
  this.onConnectionMessageChange(message);
@@ -6366,20 +6390,10 @@ var ErmisCallNode = class {
6366
6390
  this.isDestroyed = false;
6367
6391
  this.callStatus = "";
6368
6392
  this.callType = is_video ? "video" : "audio";
6369
- await this.startLocalStream();
6370
- if (this.callStatus === "ended" /* ENDED */) return;
6371
6393
  this.setUserInfo(cid, eventUserId);
6372
6394
  this.setCallStatus("ringing" /* RINGING */);
6373
6395
  this.cid = cid || "";
6374
6396
  this.metadata = metadata || {};
6375
- console.log("----metadata---", metadata);
6376
- if (eventUserId !== this.userID) {
6377
- await this.initialize();
6378
- }
6379
- if (this.localStream && this.mediaSender && this.mediaReceiver) {
6380
- this.mediaSender?.initEncoders(this.localStream);
6381
- this.mediaReceiver?.initDecoders(this.callType);
6382
- }
6383
6397
  if (typeof this.onCallEvent === "function") {
6384
6398
  this.onCallEvent({
6385
6399
  type: eventUserId !== this.userID ? "incoming" : "outgoing",
@@ -6390,6 +6404,15 @@ var ErmisCallNode = class {
6390
6404
  metadata: this.metadata
6391
6405
  });
6392
6406
  }
6407
+ await this.startLocalStream();
6408
+ if (this.callStatus === "ended" /* ENDED */) return;
6409
+ if (eventUserId !== this.userID) {
6410
+ await this.initialize();
6411
+ }
6412
+ if (this.localStream && this.mediaSender && this.mediaReceiver) {
6413
+ this.mediaSender?.initEncoders(this.localStream);
6414
+ this.mediaReceiver?.initDecoders(this.callType);
6415
+ }
6393
6416
  if (eventUserId === this.userID) {
6394
6417
  if (this.missCallTimeout) clearTimeout(this.missCallTimeout);
6395
6418
  this.missCallTimeout = setTimeout(async () => {
@@ -6650,21 +6673,30 @@ var ErmisCallNode = class {
6650
6673
  }
6651
6674
  async stopScreenShare() {
6652
6675
  const mediaConstraints = await this.getMediaConstraints();
6653
- const cameraStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6654
- const cameraTrack = cameraStream.getVideoTracks()[0];
6655
- if (this.localStream) {
6656
- this.localStream.getVideoTracks().forEach((track) => track.stop());
6657
- this.localStream.removeTrack(this.localStream.getVideoTracks()[0]);
6658
- this.localStream.addTrack(cameraTrack);
6659
- } else {
6660
- this.localStream = cameraStream;
6661
- }
6662
- if (this.onLocalStream) {
6663
- this.onLocalStream(this.localStream);
6664
- this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6665
- }
6666
- if (typeof this.onScreenShareChange === "function") {
6667
- this.onScreenShareChange(false);
6676
+ try {
6677
+ const cameraStream = await navigator.mediaDevices.getUserMedia({
6678
+ video: mediaConstraints.video,
6679
+ audio: false
6680
+ });
6681
+ const cameraTrack = cameraStream.getVideoTracks()[0];
6682
+ if (this.localStream) {
6683
+ this.localStream.getVideoTracks().forEach((track) => {
6684
+ track.stop();
6685
+ this.localStream?.removeTrack(track);
6686
+ });
6687
+ this.localStream.addTrack(cameraTrack);
6688
+ } else {
6689
+ this.localStream = cameraStream;
6690
+ }
6691
+ if (this.onLocalStream) {
6692
+ this.onLocalStream(this.localStream);
6693
+ this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6694
+ }
6695
+ if (typeof this.onScreenShareChange === "function") {
6696
+ this.onScreenShareChange(false);
6697
+ }
6698
+ } catch (error) {
6699
+ console.error("Error stopping screen share and reverting to camera:", error);
6668
6700
  }
6669
6701
  }
6670
6702
  async toggleMic(enabled) {
@@ -6932,7 +6964,7 @@ var ErmisAuthProvider = class {
6932
6964
  return data;
6933
6965
  }
6934
6966
  getUserAgent() {
6935
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.1"}`;
6967
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.3"}`;
6936
6968
  }
6937
6969
  setUserAgent(userAgent) {
6938
6970
  this.userAgent = userAgent;
@@ -7165,70 +7197,116 @@ function parseSystemMessage(value, userMap) {
7165
7197
  }
7166
7198
 
7167
7199
  // src/signal_message.ts
7168
- function formatDuration(durationSec) {
7169
- const sec = parseInt(durationSec, 10);
7170
- if (isNaN(sec) || sec < 0) return durationSec;
7171
- const minutes = Math.floor(sec / 60);
7172
- const seconds = sec % 60;
7173
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
7174
- }
7175
- function resolveUser2(userId, userMap) {
7176
- return userMap[userId] ?? userId;
7200
+ var CallType = {
7201
+ AUDIO: "audio",
7202
+ VIDEO: "video"
7203
+ };
7204
+ function formatDuration(durationMs) {
7205
+ if (!durationMs) return "";
7206
+ const ms = parseInt(durationMs, 10);
7207
+ if (isNaN(ms) || ms <= 0) return "";
7208
+ const totalSeconds = Math.floor(ms / 1e3);
7209
+ const minutes = Math.floor(totalSeconds / 60);
7210
+ const seconds = totalSeconds % 60;
7211
+ return `${minutes} min, ${seconds} sec`;
7177
7212
  }
7178
- function parseSignalMessage(value, userMap) {
7179
- if (!value || typeof value !== "string") return value ?? "";
7213
+ function parseSignalMessage(value, myUserId) {
7214
+ if (!value || typeof value !== "string") return null;
7180
7215
  const trimmed = value.trim();
7181
- if (!trimmed) return "";
7216
+ if (!trimmed) return null;
7182
7217
  const parts = trimmed.split(" ");
7183
- const formatId = parts[0];
7184
- const userId = parts[1] ?? "";
7185
- const userName = userId ? resolveUser2(userId, userMap) : "User";
7186
- switch (formatId) {
7187
- // 1: Audio call started
7188
- case "1":
7189
- return `\u{1F4DE} ${userName} started an audio call.`;
7190
- // 2: Audio call missed
7191
- case "2":
7192
- return `\u{1F4DE} Missed audio call from ${userName}.`;
7193
- // 3: Audio call ended (caller_id ender_id duration)
7194
- case "3": {
7195
- const enderId = parts[2] ?? "";
7196
- const duration = parts[3] ?? "0";
7197
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7198
- return `\u{1F4DE} Audio call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7199
- }
7200
- // 4: Video call started
7201
- case "4":
7202
- return `\u{1F4F9} ${userName} started a video call.`;
7203
- // 5: Video call missed
7204
- case "5":
7205
- return `\u{1F4F9} Missed video call from ${userName}.`;
7206
- // 6: Video call ended (caller_id ender_id duration)
7207
- case "6": {
7208
- const enderId = parts[2] ?? "";
7209
- const duration = parts[3] ?? "0";
7210
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7211
- return `\u{1F4F9} Video call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7212
- }
7213
- // 7: Audio call rejected
7214
- case "7":
7215
- return `\u{1F4DE} Audio call from ${userName} was rejected.`;
7216
- // 8: Video call rejected
7217
- case "8":
7218
- return `\u{1F4F9} Video call from ${userName} was rejected.`;
7219
- // 9: Audio call busy
7220
- case "9":
7221
- return `\u{1F4DE} Audio call from ${userName} \u2014 recipient was busy.`;
7222
- // 10: Video call busy
7223
- case "10":
7224
- return `\u{1F4F9} Video call from ${userName} \u2014 recipient was busy.`;
7218
+ const number = parseInt(parts[0], 10);
7219
+ const callerId = parts[1] ?? "";
7220
+ const isMe = myUserId === callerId;
7221
+ let enderId = "";
7222
+ let duration = "";
7223
+ let callType = "";
7224
+ let color = "";
7225
+ if (number === 3 || number === 6) {
7226
+ enderId = parts[2] ?? "";
7227
+ duration = parts[3] === "0" ? "" : parts[3] ?? "";
7228
+ }
7229
+ let text;
7230
+ switch (number) {
7231
+ case 1:
7232
+ text = isMe ? "Calling..." : "Incoming audio call...";
7233
+ callType = CallType.AUDIO;
7234
+ color = "#54D62C";
7235
+ break;
7236
+ case 2:
7237
+ text = isMe ? "Outgoing audio call" : "You missed audio call";
7238
+ callType = CallType.AUDIO;
7239
+ color = "#FF4842";
7240
+ break;
7241
+ case 3:
7242
+ if (duration) {
7243
+ text = isMe ? "Outgoing audio call" : "Incoming audio call";
7244
+ color = "#54D62C";
7245
+ } else {
7246
+ if (enderId === myUserId) {
7247
+ text = "You cancel audio call";
7248
+ } else {
7249
+ text = "You missed audio call";
7250
+ }
7251
+ color = "#FF4842";
7252
+ }
7253
+ callType = CallType.AUDIO;
7254
+ break;
7255
+ case 4:
7256
+ text = isMe ? "Calling..." : "Incoming video call...";
7257
+ callType = CallType.VIDEO;
7258
+ color = "#54D62C";
7259
+ break;
7260
+ case 5:
7261
+ text = isMe ? "Outgoing video call" : "You missed video call";
7262
+ callType = CallType.VIDEO;
7263
+ color = "#FF4842";
7264
+ break;
7265
+ case 6:
7266
+ if (duration) {
7267
+ text = isMe ? "Outgoing video call" : "Incoming video call";
7268
+ color = "#54D62C";
7269
+ } else {
7270
+ if (enderId === myUserId) {
7271
+ text = "You cancel video call";
7272
+ } else {
7273
+ text = "You missed video call";
7274
+ }
7275
+ color = "#FF4842";
7276
+ }
7277
+ callType = CallType.VIDEO;
7278
+ break;
7279
+ case 7:
7280
+ text = isMe ? "Recipient rejected audio call" : "You rejected audio call";
7281
+ callType = CallType.AUDIO;
7282
+ color = "#FF4842";
7283
+ break;
7284
+ case 8:
7285
+ text = isMe ? "Recipient rejected video call" : "You rejected video call";
7286
+ callType = CallType.VIDEO;
7287
+ color = "#FF4842";
7288
+ break;
7289
+ case 9:
7290
+ text = isMe ? "Recipient was busy" : "You missed audio call";
7291
+ callType = CallType.AUDIO;
7292
+ color = "#FF4842";
7293
+ break;
7294
+ case 10:
7295
+ text = isMe ? "Recipient was busy" : "You missed video call";
7296
+ callType = CallType.VIDEO;
7297
+ color = "#FF4842";
7298
+ break;
7225
7299
  default:
7226
- return trimmed;
7300
+ text = trimmed;
7301
+ callType = "";
7302
+ color = "";
7227
7303
  }
7304
+ return { text, duration: formatDuration(duration), callType, color };
7228
7305
  }
7229
7306
  export {
7230
7307
  CallAction,
7231
7308
  CallStatus,
7309
+ CallType,
7232
7310
  Channel,
7233
7311
  ChannelState,
7234
7312
  ClientState,