@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.
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Absolute path to the files inside the installed package
6
+ const sourceWasm = path.join(__dirname, '../public/ermis_call_node_wasm_bg.wasm');
7
+ const sourceIncomingMp3 = path.join(__dirname, '../public/call_incoming.mp3');
8
+ const sourceOutgoingMp3 = path.join(__dirname, '../public/call_outgoing.mp3');
9
+
10
+ // Execution directory (always the root of the consumer's project)
11
+ const targetDir = path.join(process.cwd(), 'public');
12
+ const targetWasm = path.join(targetDir, 'ermis_call_node_wasm_bg.wasm');
13
+ const targetIncomingMp3 = path.join(targetDir, 'call_incoming.mp3');
14
+ const targetOutgoingMp3 = path.join(targetDir, 'call_outgoing.mp3');
15
+
16
+ console.log('🔄 Configuring WebAssembly & Audio files for Ermis Direct Call feature...');
17
+
18
+ if (!fs.existsSync(sourceWasm)) {
19
+ console.error('❌ Error: Could not find the original Wasm file in the SDK package.');
20
+ console.error('Search path:', sourceWasm);
21
+ process.exit(1);
22
+ }
23
+
24
+ // Create the public directory if it doesn't exist in the consumer project
25
+ if (!fs.existsSync(targetDir)) {
26
+ console.log('Creating public directory...');
27
+ fs.mkdirSync(targetDir, { recursive: true });
28
+ }
29
+
30
+ try {
31
+ fs.copyFileSync(sourceWasm, targetWasm);
32
+ console.log('✅ Successfully copied ermis_call_node_wasm_bg.wasm to your public/ directory!');
33
+
34
+ if (fs.existsSync(sourceIncomingMp3)) {
35
+ fs.copyFileSync(sourceIncomingMp3, targetIncomingMp3);
36
+ console.log('✅ Successfully copied call_incoming.mp3 to your public/ directory!');
37
+ } else {
38
+ console.warn('⚠️ Warning: call_incoming.mp3 not found in SDK, skipping copy.');
39
+ }
40
+
41
+ if (fs.existsSync(sourceOutgoingMp3)) {
42
+ fs.copyFileSync(sourceOutgoingMp3, targetOutgoingMp3);
43
+ console.log('✅ Successfully copied call_outgoing.mp3 to your public/ directory!');
44
+ } else {
45
+ console.warn('⚠️ Warning: call_outgoing.mp3 not found in SDK, skipping copy.');
46
+ }
47
+
48
+ console.log('You can now enable the Direct Call feature in your application.');
49
+ } catch (error) {
50
+ console.error('❌ An error occurred while copying the file:', error.message);
51
+ process.exit(1);
52
+ }
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  CallAction: () => CallAction,
34
34
  CallStatus: () => CallStatus,
35
+ CallType: () => CallType,
35
36
  Channel: () => Channel,
36
37
  ChannelState: () => ChannelState,
37
38
  ClientState: () => ClientState,
@@ -3606,17 +3607,24 @@ var ErmisChat = class _ErmisChat {
3606
3607
  async unpinChannel(channelType, channelId) {
3607
3608
  return await this.post(this.baseURL + `/channels/${channelType}/${channelId}/unpin`);
3608
3609
  }
3609
- channel(channelType, channelID, custom = {}) {
3610
+ channel(channelType, channelIDOrCustom, custom) {
3610
3611
  if (!this.userID) {
3611
3612
  throw Error("Call connectUser before creating a channel");
3612
3613
  }
3613
3614
  if (~channelType.indexOf(":")) {
3614
3615
  throw Error(`Invalid channel group ${channelType}, can't contain the : character`);
3615
3616
  }
3616
- return this.getChannelById(channelType, channelID, custom);
3617
+ let channelID = void 0;
3618
+ let customData = custom || {};
3619
+ if (typeof channelIDOrCustom === "string") {
3620
+ channelID = channelIDOrCustom;
3621
+ } else if (typeof channelIDOrCustom === "object" && channelIDOrCustom !== null) {
3622
+ customData = channelIDOrCustom;
3623
+ }
3624
+ return this.getChannelById(channelType, channelID, customData);
3617
3625
  }
3618
3626
  getChannelById = (channelType, channelID, custom) => {
3619
- const cid = `${channelType}:${channelID}`;
3627
+ const cid = `${channelType}:${channelID || ""}`;
3620
3628
  if (cid in this.activeChannels && !this.activeChannels[cid].disconnected) {
3621
3629
  const channel2 = this.activeChannels[cid];
3622
3630
  if (Object.keys(custom).length > 0) {
@@ -3659,7 +3667,7 @@ var ErmisChat = class _ErmisChat {
3659
3667
  return pinExpires;
3660
3668
  }
3661
3669
  getUserAgent() {
3662
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.1"}`;
3670
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.3"}`;
3663
3671
  }
3664
3672
  setUserAgent(userAgent) {
3665
3673
  this.userAgent = userAgent;
@@ -6369,21 +6377,38 @@ var ErmisCallNode = class {
6369
6377
  const mediaConstraints = await this.getMediaConstraints();
6370
6378
  try {
6371
6379
  const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6372
- if (this.callStatus === "ended" /* ENDED */) {
6373
- stream.getTracks().forEach((track) => track.stop());
6374
- this.destroy();
6375
- return;
6380
+ return this.applyLocalStream(stream);
6381
+ } catch (error) {
6382
+ console.warn("Error getting user media:", error?.message);
6383
+ if (this.callType === "video" && mediaConstraints.video) {
6384
+ try {
6385
+ const audioOnlyStream = await navigator.mediaDevices.getUserMedia({
6386
+ audio: mediaConstraints.audio,
6387
+ video: false
6388
+ });
6389
+ this.setConnectionMessage("Camera not available, using audio only");
6390
+ return this.applyLocalStream(audioOnlyStream);
6391
+ } catch {
6392
+ }
6376
6393
  }
6377
- if (this.onLocalStream) {
6378
- this.onLocalStream(stream);
6394
+ if (typeof this.onError === "function") {
6395
+ this.onError("No microphone or camera found. Please check your device.");
6379
6396
  }
6380
- this.localStream = stream;
6381
- return stream;
6382
- } catch (error) {
6383
- console.error("Error getting user media:", error);
6384
6397
  return null;
6385
6398
  }
6386
6399
  }
6400
+ applyLocalStream(stream) {
6401
+ if (this.callStatus === "ended" /* ENDED */) {
6402
+ stream.getTracks().forEach((track) => track.stop());
6403
+ this.destroy();
6404
+ return;
6405
+ }
6406
+ if (this.onLocalStream) {
6407
+ this.onLocalStream(stream);
6408
+ }
6409
+ this.localStream = stream;
6410
+ return stream;
6411
+ }
6387
6412
  setConnectionMessage(message) {
6388
6413
  if (typeof this.onConnectionMessageChange === "function") {
6389
6414
  this.onConnectionMessageChange(message);
@@ -6428,20 +6453,10 @@ var ErmisCallNode = class {
6428
6453
  this.isDestroyed = false;
6429
6454
  this.callStatus = "";
6430
6455
  this.callType = is_video ? "video" : "audio";
6431
- await this.startLocalStream();
6432
- if (this.callStatus === "ended" /* ENDED */) return;
6433
6456
  this.setUserInfo(cid, eventUserId);
6434
6457
  this.setCallStatus("ringing" /* RINGING */);
6435
6458
  this.cid = cid || "";
6436
6459
  this.metadata = metadata || {};
6437
- console.log("----metadata---", metadata);
6438
- if (eventUserId !== this.userID) {
6439
- await this.initialize();
6440
- }
6441
- if (this.localStream && this.mediaSender && this.mediaReceiver) {
6442
- this.mediaSender?.initEncoders(this.localStream);
6443
- this.mediaReceiver?.initDecoders(this.callType);
6444
- }
6445
6460
  if (typeof this.onCallEvent === "function") {
6446
6461
  this.onCallEvent({
6447
6462
  type: eventUserId !== this.userID ? "incoming" : "outgoing",
@@ -6452,6 +6467,15 @@ var ErmisCallNode = class {
6452
6467
  metadata: this.metadata
6453
6468
  });
6454
6469
  }
6470
+ await this.startLocalStream();
6471
+ if (this.callStatus === "ended" /* ENDED */) return;
6472
+ if (eventUserId !== this.userID) {
6473
+ await this.initialize();
6474
+ }
6475
+ if (this.localStream && this.mediaSender && this.mediaReceiver) {
6476
+ this.mediaSender?.initEncoders(this.localStream);
6477
+ this.mediaReceiver?.initDecoders(this.callType);
6478
+ }
6455
6479
  if (eventUserId === this.userID) {
6456
6480
  if (this.missCallTimeout) clearTimeout(this.missCallTimeout);
6457
6481
  this.missCallTimeout = setTimeout(async () => {
@@ -6712,21 +6736,30 @@ var ErmisCallNode = class {
6712
6736
  }
6713
6737
  async stopScreenShare() {
6714
6738
  const mediaConstraints = await this.getMediaConstraints();
6715
- const cameraStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
6716
- const cameraTrack = cameraStream.getVideoTracks()[0];
6717
- if (this.localStream) {
6718
- this.localStream.getVideoTracks().forEach((track) => track.stop());
6719
- this.localStream.removeTrack(this.localStream.getVideoTracks()[0]);
6720
- this.localStream.addTrack(cameraTrack);
6721
- } else {
6722
- this.localStream = cameraStream;
6723
- }
6724
- if (this.onLocalStream) {
6725
- this.onLocalStream(this.localStream);
6726
- this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6727
- }
6728
- if (typeof this.onScreenShareChange === "function") {
6729
- this.onScreenShareChange(false);
6739
+ try {
6740
+ const cameraStream = await navigator.mediaDevices.getUserMedia({
6741
+ video: mediaConstraints.video,
6742
+ audio: false
6743
+ });
6744
+ const cameraTrack = cameraStream.getVideoTracks()[0];
6745
+ if (this.localStream) {
6746
+ this.localStream.getVideoTracks().forEach((track) => {
6747
+ track.stop();
6748
+ this.localStream?.removeTrack(track);
6749
+ });
6750
+ this.localStream.addTrack(cameraTrack);
6751
+ } else {
6752
+ this.localStream = cameraStream;
6753
+ }
6754
+ if (this.onLocalStream) {
6755
+ this.onLocalStream(this.localStream);
6756
+ this.mediaSender?.replaceVideoTrack(this.localStream.getVideoTracks()[0]);
6757
+ }
6758
+ if (typeof this.onScreenShareChange === "function") {
6759
+ this.onScreenShareChange(false);
6760
+ }
6761
+ } catch (error) {
6762
+ console.error("Error stopping screen share and reverting to camera:", error);
6730
6763
  }
6731
6764
  }
6732
6765
  async toggleMic(enabled) {
@@ -6993,7 +7026,7 @@ var ErmisAuthProvider = class {
6993
7026
  return data;
6994
7027
  }
6995
7028
  getUserAgent() {
6996
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.1"}`;
7029
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.3"}`;
6997
7030
  }
6998
7031
  setUserAgent(userAgent) {
6999
7032
  this.userAgent = userAgent;
@@ -7226,71 +7259,117 @@ function parseSystemMessage(value, userMap) {
7226
7259
  }
7227
7260
 
7228
7261
  // src/signal_message.ts
7229
- function formatDuration(durationSec) {
7230
- const sec = parseInt(durationSec, 10);
7231
- if (isNaN(sec) || sec < 0) return durationSec;
7232
- const minutes = Math.floor(sec / 60);
7233
- const seconds = sec % 60;
7234
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
7235
- }
7236
- function resolveUser2(userId, userMap) {
7237
- return userMap[userId] ?? userId;
7262
+ var CallType = {
7263
+ AUDIO: "audio",
7264
+ VIDEO: "video"
7265
+ };
7266
+ function formatDuration(durationMs) {
7267
+ if (!durationMs) return "";
7268
+ const ms = parseInt(durationMs, 10);
7269
+ if (isNaN(ms) || ms <= 0) return "";
7270
+ const totalSeconds = Math.floor(ms / 1e3);
7271
+ const minutes = Math.floor(totalSeconds / 60);
7272
+ const seconds = totalSeconds % 60;
7273
+ return `${minutes} min, ${seconds} sec`;
7238
7274
  }
7239
- function parseSignalMessage(value, userMap) {
7240
- if (!value || typeof value !== "string") return value ?? "";
7275
+ function parseSignalMessage(value, myUserId) {
7276
+ if (!value || typeof value !== "string") return null;
7241
7277
  const trimmed = value.trim();
7242
- if (!trimmed) return "";
7278
+ if (!trimmed) return null;
7243
7279
  const parts = trimmed.split(" ");
7244
- const formatId = parts[0];
7245
- const userId = parts[1] ?? "";
7246
- const userName = userId ? resolveUser2(userId, userMap) : "User";
7247
- switch (formatId) {
7248
- // 1: Audio call started
7249
- case "1":
7250
- return `\u{1F4DE} ${userName} started an audio call.`;
7251
- // 2: Audio call missed
7252
- case "2":
7253
- return `\u{1F4DE} Missed audio call from ${userName}.`;
7254
- // 3: Audio call ended (caller_id ender_id duration)
7255
- case "3": {
7256
- const enderId = parts[2] ?? "";
7257
- const duration = parts[3] ?? "0";
7258
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7259
- return `\u{1F4DE} Audio call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7260
- }
7261
- // 4: Video call started
7262
- case "4":
7263
- return `\u{1F4F9} ${userName} started a video call.`;
7264
- // 5: Video call missed
7265
- case "5":
7266
- return `\u{1F4F9} Missed video call from ${userName}.`;
7267
- // 6: Video call ended (caller_id ender_id duration)
7268
- case "6": {
7269
- const enderId = parts[2] ?? "";
7270
- const duration = parts[3] ?? "0";
7271
- const enderName = enderId ? resolveUser2(enderId, userMap) : "User";
7272
- return `\u{1F4F9} Video call by ${userName}, ended by ${enderName}. Duration: ${formatDuration(duration)}.`;
7273
- }
7274
- // 7: Audio call rejected
7275
- case "7":
7276
- return `\u{1F4DE} Audio call from ${userName} was rejected.`;
7277
- // 8: Video call rejected
7278
- case "8":
7279
- return `\u{1F4F9} Video call from ${userName} was rejected.`;
7280
- // 9: Audio call busy
7281
- case "9":
7282
- return `\u{1F4DE} Audio call from ${userName} \u2014 recipient was busy.`;
7283
- // 10: Video call busy
7284
- case "10":
7285
- return `\u{1F4F9} Video call from ${userName} \u2014 recipient was busy.`;
7280
+ const number = parseInt(parts[0], 10);
7281
+ const callerId = parts[1] ?? "";
7282
+ const isMe = myUserId === callerId;
7283
+ let enderId = "";
7284
+ let duration = "";
7285
+ let callType = "";
7286
+ let color = "";
7287
+ if (number === 3 || number === 6) {
7288
+ enderId = parts[2] ?? "";
7289
+ duration = parts[3] === "0" ? "" : parts[3] ?? "";
7290
+ }
7291
+ let text;
7292
+ switch (number) {
7293
+ case 1:
7294
+ text = isMe ? "Calling..." : "Incoming audio call...";
7295
+ callType = CallType.AUDIO;
7296
+ color = "#54D62C";
7297
+ break;
7298
+ case 2:
7299
+ text = isMe ? "Outgoing audio call" : "You missed audio call";
7300
+ callType = CallType.AUDIO;
7301
+ color = "#FF4842";
7302
+ break;
7303
+ case 3:
7304
+ if (duration) {
7305
+ text = isMe ? "Outgoing audio call" : "Incoming audio call";
7306
+ color = "#54D62C";
7307
+ } else {
7308
+ if (enderId === myUserId) {
7309
+ text = "You cancel audio call";
7310
+ } else {
7311
+ text = "You missed audio call";
7312
+ }
7313
+ color = "#FF4842";
7314
+ }
7315
+ callType = CallType.AUDIO;
7316
+ break;
7317
+ case 4:
7318
+ text = isMe ? "Calling..." : "Incoming video call...";
7319
+ callType = CallType.VIDEO;
7320
+ color = "#54D62C";
7321
+ break;
7322
+ case 5:
7323
+ text = isMe ? "Outgoing video call" : "You missed video call";
7324
+ callType = CallType.VIDEO;
7325
+ color = "#FF4842";
7326
+ break;
7327
+ case 6:
7328
+ if (duration) {
7329
+ text = isMe ? "Outgoing video call" : "Incoming video call";
7330
+ color = "#54D62C";
7331
+ } else {
7332
+ if (enderId === myUserId) {
7333
+ text = "You cancel video call";
7334
+ } else {
7335
+ text = "You missed video call";
7336
+ }
7337
+ color = "#FF4842";
7338
+ }
7339
+ callType = CallType.VIDEO;
7340
+ break;
7341
+ case 7:
7342
+ text = isMe ? "Recipient rejected audio call" : "You rejected audio call";
7343
+ callType = CallType.AUDIO;
7344
+ color = "#FF4842";
7345
+ break;
7346
+ case 8:
7347
+ text = isMe ? "Recipient rejected video call" : "You rejected video call";
7348
+ callType = CallType.VIDEO;
7349
+ color = "#FF4842";
7350
+ break;
7351
+ case 9:
7352
+ text = isMe ? "Recipient was busy" : "You missed audio call";
7353
+ callType = CallType.AUDIO;
7354
+ color = "#FF4842";
7355
+ break;
7356
+ case 10:
7357
+ text = isMe ? "Recipient was busy" : "You missed video call";
7358
+ callType = CallType.VIDEO;
7359
+ color = "#FF4842";
7360
+ break;
7286
7361
  default:
7287
- return trimmed;
7362
+ text = trimmed;
7363
+ callType = "";
7364
+ color = "";
7288
7365
  }
7366
+ return { text, duration: formatDuration(duration), callType, color };
7289
7367
  }
7290
7368
  // Annotate the CommonJS export names for ESM import in node:
7291
7369
  0 && (module.exports = {
7292
7370
  CallAction,
7293
7371
  CallStatus,
7372
+ CallType,
7294
7373
  Channel,
7295
7374
  ChannelState,
7296
7375
  ClientState,