@ermis-network/ermis-chat-sdk 1.0.9 → 2.0.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/dist/index.mjs CHANGED
@@ -157,11 +157,25 @@ function addToMessageList(messages, message, timestampChanged = false, sortBy =
157
157
  }
158
158
  if (!timestampChanged && message.id) {
159
159
  if (messageArr[left] && message.id === messageArr[left].id) {
160
- messageArr[left] = message;
160
+ const existingMessage = messageArr[left];
161
+ const mergedMessage = { ...existingMessage };
162
+ Object.keys(message).forEach((key) => {
163
+ if (message[key] !== void 0) {
164
+ mergedMessage[key] = message[key];
165
+ }
166
+ });
167
+ messageArr[left] = mergedMessage;
161
168
  return [...messageArr];
162
169
  }
163
170
  if (messageArr[left - 1] && message.id === messageArr[left - 1].id) {
164
- messageArr[left - 1] = message;
171
+ const existingMessage = messageArr[left - 1];
172
+ const mergedMessage = { ...existingMessage };
173
+ Object.keys(message).forEach((key) => {
174
+ if (message[key] !== void 0) {
175
+ mergedMessage[key] = message[key];
176
+ }
177
+ });
178
+ messageArr[left - 1] = mergedMessage;
165
179
  return [...messageArr];
166
180
  }
167
181
  }
@@ -270,7 +284,7 @@ var createPacketWithHeader = (data, timestamp, type, configMsg) => {
270
284
  const jsonString = JSON.stringify(configMsg);
271
285
  const encoder = new TextEncoder();
272
286
  payload = encoder.encode(jsonString);
273
- } else if (type === "connected") {
287
+ } else if (type === "connected" || type === "healthCall") {
274
288
  HEADER_SIZE = 1;
275
289
  payload = new Uint8Array(0);
276
290
  } else {
@@ -301,6 +315,9 @@ var createPacketWithHeader = (data, timestamp, type, configMsg) => {
301
315
  case "transciverState":
302
316
  typeCode = 7;
303
317
  break;
318
+ case "healthCall":
319
+ typeCode = 11;
320
+ break;
304
321
  }
305
322
  packet[0] = typeCode;
306
323
  if (timestamp !== null) {
@@ -625,8 +642,12 @@ var ChannelState = class {
625
642
  }
626
643
  }
627
644
  };
628
- this.messageSets.forEach((set) => _updateUserMessages(set.messages, user));
645
+ this.messageSets.forEach((set) => {
646
+ _updateUserMessages(set.messages, user);
647
+ set.messages = [...set.messages];
648
+ });
629
649
  _updateUserMessages(this.pinnedMessages, user);
650
+ this.pinnedMessages = [...this.pinnedMessages];
630
651
  };
631
652
  deleteUserMessages = (user, hardDelete = false) => {
632
653
  const _deleteUserMessages = (messages, user2, hardDelete2 = false) => {
@@ -1471,9 +1492,13 @@ var Channel = class {
1471
1492
  state.pinned_messages = state.pinned_messages ? enrichWithUserInfo(state.pinned_messages, users) : [];
1472
1493
  state.read = enrichWithUserInfo(state.read || [], users);
1473
1494
  state.channel.is_pinned = state.is_pinned || false;
1474
- if (!this.id) {
1495
+ const oldCid = this.cid;
1496
+ if (oldCid !== state.channel.cid) {
1475
1497
  this.id = state.channel.id;
1476
1498
  this.cid = state.channel.cid;
1499
+ if (oldCid in this.getClient().activeChannels) {
1500
+ delete this.getClient().activeChannels[oldCid];
1501
+ }
1477
1502
  const membersStr = state.channel.members.map((member) => member.user_id || member.user?.id).sort().join(",");
1478
1503
  const tempChannelCid = `${this.type}:!members-${membersStr}`;
1479
1504
  if (tempChannelCid in this.getClient().activeChannels) {
@@ -1482,6 +1507,8 @@ var Channel = class {
1482
1507
  if (!(this.cid in this.getClient().activeChannels)) {
1483
1508
  this.getClient().activeChannels[this.cid] = this;
1484
1509
  }
1510
+ } else if (!(this.cid in this.getClient().activeChannels)) {
1511
+ this.getClient().activeChannels[this.cid] = this;
1485
1512
  }
1486
1513
  const { messageSet } = this._initializeState(state, messageSetToAddToIfDoesNotExist);
1487
1514
  const areCapabilitiesChanged = [...state.channel.own_capabilities || []].sort().join() !== [...Array.isArray(this.data?.own_capabilities) ? this.data?.own_capabilities : []].sort().join();
@@ -1620,55 +1647,77 @@ var Channel = class {
1620
1647
  }
1621
1648
  async getThumbBlobVideo(file) {
1622
1649
  return new Promise((resolve) => {
1623
- const seekTo = 0.1;
1624
1650
  const videoPlayer = document.createElement("video");
1625
1651
  videoPlayer.src = URL.createObjectURL(file);
1626
1652
  videoPlayer.crossOrigin = "anonymous";
1653
+ videoPlayer.muted = true;
1627
1654
  videoPlayer.load();
1655
+ let attempts = 0;
1656
+ const maxAttempts = 5;
1657
+ const seekInterval = 1;
1658
+ const cleanup = () => {
1659
+ URL.revokeObjectURL(videoPlayer.src);
1660
+ videoPlayer.remove();
1661
+ };
1628
1662
  videoPlayer.addEventListener("error", () => {
1629
1663
  console.error("Error when loading video file.");
1664
+ cleanup();
1630
1665
  resolve(null);
1631
1666
  });
1632
- videoPlayer.addEventListener("loadedmetadata", () => {
1633
- if (videoPlayer.duration < seekTo) {
1634
- console.error("Video is too short.");
1635
- resolve(null);
1636
- return;
1637
- }
1638
- setTimeout(() => {
1639
- videoPlayer.currentTime = seekTo;
1640
- }, 200);
1641
- });
1642
- videoPlayer.addEventListener("seeked", () => {
1667
+ const captureFrame = () => {
1643
1668
  try {
1644
1669
  const canvas = document.createElement("canvas");
1645
1670
  canvas.width = videoPlayer.videoWidth;
1646
1671
  canvas.height = videoPlayer.videoHeight;
1647
- const ctx = canvas.getContext("2d");
1672
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
1648
1673
  if (!ctx) {
1649
1674
  console.error("Failed to create canvas context.");
1675
+ cleanup();
1650
1676
  resolve(null);
1651
1677
  return;
1652
1678
  }
1653
1679
  ctx.drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
1654
- ctx.canvas.toBlob(
1680
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
1681
+ const data = imageData.data;
1682
+ let totalLuminance = 0;
1683
+ const sampleStep = 40;
1684
+ let samples = 0;
1685
+ for (let i = 0; i < data.length; i += sampleStep * 4) {
1686
+ const r = data[i];
1687
+ const g = data[i + 1];
1688
+ const b = data[i + 2];
1689
+ totalLuminance += 0.2126 * r + 0.7152 * g + 0.0722 * b;
1690
+ samples++;
1691
+ }
1692
+ const avgLuminance = totalLuminance / samples;
1693
+ if (avgLuminance < 15 && attempts < maxAttempts && videoPlayer.currentTime + seekInterval < videoPlayer.duration) {
1694
+ attempts++;
1695
+ videoPlayer.currentTime += seekInterval;
1696
+ return;
1697
+ }
1698
+ canvas.toBlob(
1655
1699
  (blob) => {
1700
+ cleanup();
1656
1701
  if (!blob) {
1657
1702
  console.error("Failed to generate thumbnail.");
1658
1703
  resolve(null);
1659
1704
  return;
1660
1705
  }
1661
1706
  resolve(blob);
1662
- URL.revokeObjectURL(videoPlayer.src);
1663
1707
  },
1664
1708
  "image/jpeg",
1665
1709
  0.75
1666
1710
  );
1667
1711
  } catch (error) {
1668
1712
  console.error("Error while extracting thumbnail:", error);
1713
+ cleanup();
1669
1714
  resolve(null);
1670
1715
  }
1716
+ };
1717
+ videoPlayer.addEventListener("loadedmetadata", () => {
1718
+ videoPlayer.currentTime = Math.min(0.5, videoPlayer.duration);
1671
1719
  });
1720
+ videoPlayer.addEventListener("seeked", captureFrame);
1672
1721
  });
1673
1722
  }
1674
1723
  async enableTopics() {
@@ -1801,21 +1850,50 @@ var Channel = class {
1801
1850
  if (event.message) {
1802
1851
  this._extendEventWithOwnReactions(event);
1803
1852
  channelState.removeMessage(event.message);
1804
- channelState.addMessageSorted(event.message, false, false);
1853
+ if (channelState.latestMessages.length === 0) {
1854
+ this.query({ messages: { limit: 1 } }).then(() => {
1855
+ this._callChannelListeners({
1856
+ type: "channel.updated",
1857
+ cid: this.cid,
1858
+ channel: this.data
1859
+ });
1860
+ }).catch((err) => {
1861
+ this._client.logger("error", "Failed to query for new last message after deletion", { err });
1862
+ });
1863
+ }
1805
1864
  channelState.removeQuotedMessageReferences(event.message);
1806
1865
  if ([...channelState.pinnedMessages].some((msg) => msg.id === event.message?.id)) {
1807
1866
  channelState.removePinnedMessage(event.message);
1808
1867
  }
1868
+ const msgTime = event.message.created_at ? new Date(event.message.created_at) : null;
1809
1869
  for (const userId in channelState.read) {
1810
1870
  if (userId !== event.user?.id && event.message.id === channelState.read[userId].last_read_message_id) {
1811
1871
  channelState.read[userId] = { ...channelState.read[userId], last_read_message_id: void 0 };
1812
1872
  }
1873
+ const userRead = channelState.read[userId];
1874
+ const lastRead = userRead.last_read ? new Date(userRead.last_read) : /* @__PURE__ */ new Date(0);
1875
+ if (msgTime && msgTime > lastRead) {
1876
+ const wasSentByUser = event.message.user?.id === userId || event.message.user_id === userId;
1877
+ const isSystem = event.message.type === "system";
1878
+ if (!wasSentByUser && !isSystem) {
1879
+ userRead.unread_messages = Math.max(0, userRead.unread_messages - 1);
1880
+ if (userId === this.getClient().userID) {
1881
+ channelState.unreadCount = Math.max(0, channelState.unreadCount - 1);
1882
+ }
1883
+ }
1884
+ }
1813
1885
  }
1814
1886
  }
1815
1887
  break;
1816
1888
  case "message.deleted_for_me":
1817
1889
  if (event.message) {
1818
- channelState.removeMessage(event.message);
1890
+ delete event.message.user;
1891
+ delete event.message.user_id;
1892
+ event.message.display_type = "deleted";
1893
+ event.message.pinned_at = null;
1894
+ event.message.updated_at = null;
1895
+ event.message.status = "received";
1896
+ channelState.addMessageSorted(event.message);
1819
1897
  channelState.removeQuotedMessageReferences(event.message);
1820
1898
  if ([...channelState.pinnedMessages].some((msg) => msg.id === event.message?.id)) {
1821
1899
  channelState.removePinnedMessage(event.message);
@@ -1901,9 +1979,10 @@ var Channel = class {
1901
1979
  channelState.addMessageSorted(event.message, false, false);
1902
1980
  }
1903
1981
  break;
1904
- case "channel.truncate":
1905
- if (event.channel?.created_at) {
1906
- const truncatedAt = +new Date(event.channel.created_at);
1982
+ case "channel.truncate": {
1983
+ const truncateDate = event.channel?.created_at || event.created_at;
1984
+ if (truncateDate) {
1985
+ const truncatedAt = +new Date(truncateDate);
1907
1986
  channelState.messageSets.forEach((messageSet, messageSetIndex) => {
1908
1987
  messageSet.messages.forEach(({ created_at: createdAt, id }) => {
1909
1988
  if (truncatedAt > +createdAt) channelState.removeMessage({ id, messageSetIndex });
@@ -1924,6 +2003,7 @@ var Channel = class {
1924
2003
  }
1925
2004
  }
1926
2005
  break;
2006
+ }
1927
2007
  case "member.added":
1928
2008
  if (event.member?.user_id) {
1929
2009
  const user = getUserInfo(event.member.user_id, users);
@@ -1954,12 +2034,14 @@ var Channel = class {
1954
2034
  channel.data.topics_enabled = true;
1955
2035
  }
1956
2036
  channelState.topics = channelState.topics || [];
2037
+ event.user = getUserInfo(event.user?.id || "", users);
1957
2038
  break;
1958
2039
  case "channel.topic.disabled":
1959
2040
  if (channel.data) {
1960
2041
  channel.data.topics_enabled = false;
1961
2042
  }
1962
2043
  channelState.topics = [];
2044
+ event.user = getUserInfo(event.user?.id || "", users);
1963
2045
  break;
1964
2046
  case "channel.updated":
1965
2047
  if (event.channel) {
@@ -2075,18 +2157,6 @@ var Channel = class {
2075
2157
  channel.data.is_pinned = false;
2076
2158
  }
2077
2159
  break;
2078
- case "channel.topic.disabled":
2079
- if (channel.data) {
2080
- channel.data.topics_enabled = false;
2081
- }
2082
- event.user = getUserInfo(event.user?.id || "", users);
2083
- break;
2084
- case "channel.topic.enabled":
2085
- if (channel.data) {
2086
- channel.data.topics_enabled = true;
2087
- }
2088
- event.user = getUserInfo(event.user?.id || "", users);
2089
- break;
2090
2160
  case "channel.topic.created":
2091
2161
  const members = event.channel?.members || [];
2092
2162
  const enrichedMembers = enrichWithUserInfo(members, users);
@@ -2304,7 +2374,7 @@ var ClientState = class {
2304
2374
  };
2305
2375
 
2306
2376
  // src/connection.ts
2307
- import WebSocket2 from "isomorphic-ws";
2377
+ import WebSocket from "isomorphic-ws";
2308
2378
  var isCloseEvent = (res) => res.code !== void 0;
2309
2379
  var isErrorEvent = (res) => res.error !== void 0;
2310
2380
  var StableWSConnection = class {
@@ -2483,7 +2553,7 @@ var StableWSConnection = class {
2483
2553
  this._setupConnectionPromise();
2484
2554
  const wsURL = this._buildUrl();
2485
2555
  this._log(`_connect() - Connecting to ${wsURL}`, { wsURL, requestID: this.requestID });
2486
- this.ws = new WebSocket2(wsURL);
2556
+ this.ws = new WebSocket(wsURL);
2487
2557
  this.ws.onopen = this.onopen.bind(this, this.wsID);
2488
2558
  this.ws.onclose = this.onclose.bind(this, this.wsID);
2489
2559
  this.ws.onerror = this.onerror.bind(this, this.wsID);
@@ -2780,6 +2850,7 @@ var CallAction = /* @__PURE__ */ ((CallAction2) => {
2780
2850
  return CallAction2;
2781
2851
  })(CallAction || {});
2782
2852
  var CallStatus = /* @__PURE__ */ ((CallStatus2) => {
2853
+ CallStatus2["PREPARING"] = "preparing";
2783
2854
  CallStatus2["RINGING"] = "ringing";
2784
2855
  CallStatus2["ENDED"] = "ended";
2785
2856
  CallStatus2["CONNECTED"] = "connected";
@@ -2798,6 +2869,7 @@ var FRAME_TYPE = /* @__PURE__ */ ((FRAME_TYPE2) => {
2798
2869
  FRAME_TYPE2[FRAME_TYPE2["REQUEST_CONFIG"] = 8] = "REQUEST_CONFIG";
2799
2870
  FRAME_TYPE2[FRAME_TYPE2["REQUEST_KEY_FRAME"] = 9] = "REQUEST_KEY_FRAME";
2800
2871
  FRAME_TYPE2[FRAME_TYPE2["END_CALL"] = 10] = "END_CALL";
2872
+ FRAME_TYPE2[FRAME_TYPE2["HEALTH_CALL"] = 11] = "HEALTH_CALL";
2801
2873
  return FRAME_TYPE2;
2802
2874
  })(FRAME_TYPE || {});
2803
2875
 
@@ -2991,7 +3063,11 @@ var ErmisChat = class _ErmisChat {
2991
3063
  this.userID = connectionUser.id;
2992
3064
  const setTokenPromise = this._setToken(connectionUser, connectionToken);
2993
3065
  this._setUser(connectionUser);
2994
- this.state.updateUser({ id: connectionUser.id, name: connectionUser?.name || connectionUser.id, avatar: connectionUser?.avatar || "" });
3066
+ this.state.updateUser({
3067
+ id: connectionUser.id,
3068
+ name: connectionUser?.name || connectionUser.id,
3069
+ avatar: connectionUser?.avatar || ""
3070
+ });
2995
3071
  const wsPromise = this.openConnection();
2996
3072
  this.setUserPromise = Promise.all([setTokenPromise, wsPromise]).then(
2997
3073
  (result) => result[1]
@@ -3000,6 +3076,16 @@ var ErmisChat = class _ErmisChat {
3000
3076
  try {
3001
3077
  const result = await this.setUserPromise;
3002
3078
  await this.connectToSSE();
3079
+ this.queryUser(connectionUser.id).then((fullProfile) => {
3080
+ this.user = { ...this.user, ...fullProfile };
3081
+ this.state.updateUser(this.user);
3082
+ this.dispatchEvent({
3083
+ type: "user.updated",
3084
+ me: this.user
3085
+ });
3086
+ }).catch((err) => {
3087
+ this.logger("error", "client:connectUser() - failed to fetch full user profile", { err });
3088
+ });
3003
3089
  return result;
3004
3090
  } catch (err) {
3005
3091
  this.disconnectUser();
@@ -3206,10 +3292,11 @@ var ErmisChat = class _ErmisChat {
3206
3292
  * @returns A Blob of the file content.
3207
3293
  */
3208
3294
  async downloadMedia(url) {
3209
- const response = await this.axiosInstance.get(url, {
3210
- responseType: "blob"
3211
- });
3212
- return response.data;
3295
+ const response = await fetch(url, { cache: "no-store" });
3296
+ if (!response.ok) {
3297
+ throw new Error(`Failed to download media: ${response.statusText}`);
3298
+ }
3299
+ return await response.blob();
3213
3300
  }
3214
3301
  errorFromResponse(response) {
3215
3302
  let err;
@@ -3289,21 +3376,67 @@ var ErmisChat = class _ErmisChat {
3289
3376
  this.dispatchEvent(event);
3290
3377
  };
3291
3378
  _updateMemberWatcherReferences = (user) => {
3292
- const refMap = this.state.userChannelReferences[user.id] || {};
3293
- for (const channelID in refMap) {
3294
- const channel = this.activeChannels[channelID];
3379
+ Object.values(this.activeChannels).forEach((channel) => {
3295
3380
  if (channel?.state) {
3381
+ let hasChange = false;
3296
3382
  if (channel.state.members[user.id]) {
3297
- channel.state.members[user.id].user = user;
3383
+ channel.state.members = {
3384
+ ...channel.state.members,
3385
+ [user.id]: {
3386
+ ...channel.state.members[user.id],
3387
+ user
3388
+ }
3389
+ };
3390
+ hasChange = true;
3391
+ if (channel.data?.type === "messaging") {
3392
+ const members = Object.values(channel.state.members);
3393
+ if (members.length === 2) {
3394
+ const otherMember = members.find((m) => m.user?.id !== this.userID);
3395
+ if (otherMember && otherMember.user?.id === user.id) {
3396
+ channel.data.name = user.name || user.id;
3397
+ channel.data.image = user.avatar || "";
3398
+ }
3399
+ }
3400
+ }
3298
3401
  }
3299
3402
  if (channel.state.watchers[user.id]) {
3300
- channel.state.watchers[user.id] = user;
3403
+ channel.state.watchers = {
3404
+ ...channel.state.watchers,
3405
+ [user.id]: user
3406
+ };
3407
+ hasChange = true;
3301
3408
  }
3302
3409
  if (channel.state.read[user.id]) {
3303
- channel.state.read[user.id].user = user;
3410
+ channel.state.read = {
3411
+ ...channel.state.read,
3412
+ [user.id]: {
3413
+ ...channel.state.read[user.id],
3414
+ user
3415
+ }
3416
+ };
3417
+ hasChange = true;
3418
+ }
3419
+ if (hasChange) {
3420
+ channel._callChannelListeners({
3421
+ type: "channel.updated",
3422
+ channel: channel.data,
3423
+ cid: channel.cid
3424
+ });
3425
+ if (channel.state.members[user.id]) {
3426
+ channel._callChannelListeners({
3427
+ type: "member.updated",
3428
+ member: channel.state.members[user.id],
3429
+ cid: channel.cid
3430
+ });
3431
+ }
3432
+ channel._callChannelListeners({
3433
+ type: "user.updated",
3434
+ user,
3435
+ cid: channel.cid
3436
+ });
3304
3437
  }
3305
3438
  }
3306
- }
3439
+ });
3307
3440
  };
3308
3441
  _updateUserReferences = this._updateMemberWatcherReferences;
3309
3442
  _updateUserMessageReferences = (user) => {
@@ -3313,6 +3446,19 @@ var ErmisChat = class _ErmisChat {
3313
3446
  if (!channel) continue;
3314
3447
  const state = channel.state;
3315
3448
  state?.updateUserMessages(user);
3449
+ channel._callChannelListeners({
3450
+ type: "channel.updated",
3451
+ channel: channel.data,
3452
+ cid: channel.cid
3453
+ });
3454
+ const lastMessage = state?.messages[state.messages.length - 1];
3455
+ if (lastMessage) {
3456
+ channel._callChannelListeners({
3457
+ type: "message.updated",
3458
+ message: lastMessage,
3459
+ cid: channel.cid
3460
+ });
3461
+ }
3316
3462
  }
3317
3463
  };
3318
3464
  _deleteUserMessageReference = (user, hardDelete = false) => {
@@ -3378,7 +3524,11 @@ var ErmisChat = class _ErmisChat {
3378
3524
  const bTime = bLatest ? new Date(bLatest).getTime() : 0;
3379
3525
  return bTime - aTime;
3380
3526
  });
3381
- parentChannel._callChannelListeners({ ...event, type: "channel.updated", channel: parentChannel.data });
3527
+ parentChannel._callChannelListeners({
3528
+ ...event,
3529
+ type: "channel.updated",
3530
+ channel: parentChannel.data
3531
+ });
3382
3532
  }
3383
3533
  }
3384
3534
  });
@@ -3389,7 +3539,9 @@ var ErmisChat = class _ErmisChat {
3389
3539
  if (parentCid && this.activeChannels[parentCid]) {
3390
3540
  const parentChannel = this.activeChannels[parentCid];
3391
3541
  if (parentChannel.state?.topics && event.channel) {
3392
- const topicIndex = parentChannel.state.topics.findIndex((t) => t.cid === event.cid || t.channel?.cid === event.cid);
3542
+ const topicIndex = parentChannel.state.topics.findIndex(
3543
+ (t) => t.cid === event.cid || t.channel?.cid === event.cid
3544
+ );
3393
3545
  if (topicIndex !== -1) {
3394
3546
  const t = parentChannel.state.topics[topicIndex];
3395
3547
  if (t.data) {
@@ -3400,14 +3552,22 @@ var ErmisChat = class _ErmisChat {
3400
3552
  Object.assign(t, event.channel);
3401
3553
  }
3402
3554
  }
3403
- parentChannel._callChannelListeners({ ...event, type: "channel.updated", channel: parentChannel.data });
3555
+ parentChannel._callChannelListeners({
3556
+ ...event,
3557
+ type: "channel.updated",
3558
+ channel: parentChannel.data
3559
+ });
3404
3560
  }
3405
3561
  }
3406
3562
  if (event.cid && this.activeChannels[event.cid]) {
3407
3563
  const topicChannel = this.activeChannels[event.cid];
3408
3564
  if (event.channel) {
3409
3565
  topicChannel.data = { ...topicChannel.data, ...event.channel };
3410
- topicChannel._callChannelListeners({ ...event, type: "channel.updated", channel: topicChannel.data });
3566
+ topicChannel._callChannelListeners({
3567
+ ...event,
3568
+ type: "channel.updated",
3569
+ channel: topicChannel.data
3570
+ });
3411
3571
  }
3412
3572
  }
3413
3573
  });
@@ -3419,14 +3579,20 @@ var ErmisChat = class _ErmisChat {
3419
3579
  if (parentCid && this.activeChannels[parentCid]) {
3420
3580
  const parentChannel = this.activeChannels[parentCid];
3421
3581
  if (parentChannel.state?.topics) {
3422
- const topicIndex = parentChannel.state.topics.findIndex((t) => t.cid === event.cid || t.channel?.cid === event.cid);
3582
+ const topicIndex = parentChannel.state.topics.findIndex(
3583
+ (t) => t.cid === event.cid || t.channel?.cid === event.cid
3584
+ );
3423
3585
  if (topicIndex !== -1) {
3424
3586
  const t = parentChannel.state.topics[topicIndex];
3425
3587
  if (t.data) t.data.is_closed_topic = isClosed;
3426
3588
  else if (t.channel) t.channel.is_closed_topic = isClosed;
3427
3589
  else t.is_closed_topic = isClosed;
3428
3590
  }
3429
- parentChannel._callChannelListeners({ ...event, type: "channel.updated", channel: parentChannel.data });
3591
+ parentChannel._callChannelListeners({
3592
+ ...event,
3593
+ type: "channel.updated",
3594
+ channel: parentChannel.data
3595
+ });
3430
3596
  }
3431
3597
  }
3432
3598
  if (event.cid && this.activeChannels[event.cid]) {
@@ -3482,13 +3648,11 @@ var ErmisChat = class _ErmisChat {
3482
3648
  this.logger("info", `client:recoverState() - Start the querying of ${cids.length} channels`, {
3483
3649
  tags: ["connection", "client"]
3484
3650
  });
3485
- const filter = {
3486
- type: ["messaging", "team"]
3487
- };
3488
- const sort = [];
3489
- const options = {
3490
- message_limit: 25
3491
- };
3651
+ const {
3652
+ filter = { type: ["messaging", "team", "meeting"] },
3653
+ sort = [],
3654
+ options = { message_limit: 1 }
3655
+ } = this.options.recoveryConfig || {};
3492
3656
  await this.queryChannels(filter, sort, options);
3493
3657
  this.logger("info", "client:recoverState() - Querying channels finished", { tags: ["connection", "client"] });
3494
3658
  this.dispatchEvent({
@@ -3550,36 +3714,32 @@ var ErmisChat = class _ErmisChat {
3550
3714
  const data = JSON.parse(event.data);
3551
3715
  this.logger("info", `client:connectToSSE() - SSE message received event : ${JSON.stringify(data)}`, { event });
3552
3716
  if (data.type === "AccountUserChainProjects") {
3553
- let user = {
3554
- name: data.name,
3717
+ const userInfo = {
3555
3718
  id: data.id,
3719
+ name: data.name,
3556
3720
  avatar: data.avatar,
3557
3721
  about_me: data.about_me,
3558
3722
  project_id: data.project_id
3559
3723
  };
3560
- if (this.user?.id === user.id) {
3561
- this.user = { ...this.user, ...user };
3724
+ if (this.user?.id === userInfo.id) {
3725
+ this.user = { ...this.user, ...userInfo };
3562
3726
  }
3563
- this.state.updateUser(user);
3564
- const userInfo = {
3565
- id: user.id,
3566
- name: user.name ? user.name : user.id,
3567
- avatar: user?.avatar || ""
3727
+ this.state.updateUser(userInfo);
3728
+ const minimalUserInfo = {
3729
+ id: userInfo.id,
3730
+ name: userInfo.name || userInfo.id,
3731
+ avatar: userInfo.avatar || ""
3568
3732
  };
3569
- this._updateMemberWatcherReferences(userInfo);
3570
- this._updateUserMessageReferences(userInfo);
3571
- Object.values(this.activeChannels).forEach((channel) => {
3572
- if (channel.data?.type === "messaging" && Object.keys(channel.state.members).length === 2) {
3573
- const otherMember = Object.values(channel.state.members).find((member) => member.user?.id !== this.userID);
3574
- if (otherMember && otherMember.user?.id === user.id) {
3575
- channel.data.name = user.name || user.id;
3576
- channel.data.image = user.avatar || "";
3577
- }
3578
- }
3579
- });
3733
+ this._updateMemberWatcherReferences(minimalUserInfo);
3734
+ this._updateUserMessageReferences(minimalUserInfo);
3580
3735
  if (onCallBack) {
3581
3736
  onCallBack(data);
3582
3737
  }
3738
+ this.dispatchEvent({
3739
+ type: "user.updated",
3740
+ user: userInfo,
3741
+ me: this.user?.id === userInfo.id ? this.user : void 0
3742
+ });
3583
3743
  }
3584
3744
  };
3585
3745
  this.eventSource.onerror = (event) => {
@@ -3694,6 +3854,17 @@ var ErmisChat = class _ErmisChat {
3694
3854
  this.user.avatar = response.avatar;
3695
3855
  const new_user = { ...this.user, avatar: response.avatar };
3696
3856
  this.state.updateUser(new_user);
3857
+ const userInfo = {
3858
+ id: this.user.id,
3859
+ name: this.user.name ? this.user.name : this.user.id,
3860
+ avatar: this.user?.avatar || ""
3861
+ };
3862
+ this._updateMemberWatcherReferences(userInfo);
3863
+ this._updateUserMessageReferences(userInfo);
3864
+ this.dispatchEvent({
3865
+ type: "user.updated",
3866
+ me: this.user
3867
+ });
3697
3868
  }
3698
3869
  return response;
3699
3870
  }
@@ -3701,6 +3872,19 @@ var ErmisChat = class _ErmisChat {
3701
3872
  let response = await this.patch(this.userBaseURL + "/users/update", updates);
3702
3873
  this.user = response;
3703
3874
  this.state.updateUser(response);
3875
+ if (this.user) {
3876
+ const userInfo = {
3877
+ id: this.user.id,
3878
+ name: this.user.name ? this.user.name : this.user.id,
3879
+ avatar: this.user?.avatar || ""
3880
+ };
3881
+ this._updateMemberWatcherReferences(userInfo);
3882
+ this._updateUserMessageReferences(userInfo);
3883
+ this.dispatchEvent({
3884
+ type: "user.updated",
3885
+ me: this.user
3886
+ });
3887
+ }
3704
3888
  return response;
3705
3889
  }
3706
3890
  /**
@@ -3760,6 +3944,9 @@ var ErmisChat = class _ErmisChat {
3760
3944
  });
3761
3945
  const { channels, userIds } = this.hydrateChannels(data.channels, stateOptions);
3762
3946
  console.log("---channels---", channels);
3947
+ this.dispatchEvent({
3948
+ type: "channels.queried"
3949
+ });
3763
3950
  return channels;
3764
3951
  }
3765
3952
  hydrateChannels(channelsFromApi = [], stateOptions = {}) {
@@ -3915,7 +4102,7 @@ var ErmisChat = class _ErmisChat {
3915
4102
  return pinExpires;
3916
4103
  }
3917
4104
  getUserAgent() {
3918
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.9"}`;
4105
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"2.0.0"}`;
3919
4106
  }
3920
4107
  setUserAgent(userAgent) {
3921
4108
  this.userAgent = userAgent;
@@ -4030,1470 +4217,234 @@ var EVENT_MAP = {
4030
4217
  "channel.topic.updated": true
4031
4218
  };
4032
4219
 
4033
- // src/wasm/ermis_call_node_wasm.js
4034
- var wasm;
4035
- var cachedUint8ArrayMemory0 = null;
4036
- function getUint8ArrayMemory0() {
4037
- if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
4038
- cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
4039
- }
4040
- return cachedUint8ArrayMemory0;
4041
- }
4042
- var cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
4043
- cachedTextDecoder.decode();
4044
- var MAX_SAFARI_DECODE_BYTES = 2146435072;
4045
- var numBytesDecoded = 0;
4046
- function decodeText(ptr, len) {
4047
- numBytesDecoded += len;
4048
- if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
4049
- cachedTextDecoder = new TextDecoder("utf-8", { ignoreBOM: true, fatal: true });
4050
- cachedTextDecoder.decode();
4051
- numBytesDecoded = len;
4052
- }
4053
- return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
4054
- }
4055
- function getStringFromWasm0(ptr, len) {
4056
- ptr = ptr >>> 0;
4057
- return decodeText(ptr, len);
4058
- }
4059
- var heap = new Array(128).fill(void 0);
4060
- heap.push(void 0, null, true, false);
4061
- var heap_next = heap.length;
4062
- function addHeapObject(obj) {
4063
- if (heap_next === heap.length) heap.push(heap.length + 1);
4064
- const idx = heap_next;
4065
- heap_next = heap[idx];
4066
- heap[idx] = obj;
4067
- return idx;
4068
- }
4069
- function getObject(idx) {
4070
- return heap[idx];
4071
- }
4072
- var WASM_VECTOR_LEN = 0;
4073
- var cachedTextEncoder = new TextEncoder();
4074
- if (!("encodeInto" in cachedTextEncoder)) {
4075
- cachedTextEncoder.encodeInto = function(arg, view) {
4076
- const buf = cachedTextEncoder.encode(arg);
4077
- view.set(buf);
4078
- return {
4079
- read: arg.length,
4080
- written: buf.length
4081
- };
4082
- };
4083
- }
4084
- function passStringToWasm0(arg, malloc, realloc) {
4085
- if (realloc === void 0) {
4086
- const buf = cachedTextEncoder.encode(arg);
4087
- const ptr2 = malloc(buf.length, 1) >>> 0;
4088
- getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);
4089
- WASM_VECTOR_LEN = buf.length;
4090
- return ptr2;
4091
- }
4092
- let len = arg.length;
4093
- let ptr = malloc(len, 1) >>> 0;
4094
- const mem = getUint8ArrayMemory0();
4095
- let offset = 0;
4096
- for (; offset < len; offset++) {
4097
- const code = arg.charCodeAt(offset);
4098
- if (code > 127) break;
4099
- mem[ptr + offset] = code;
4100
- }
4101
- if (offset !== len) {
4102
- if (offset !== 0) {
4103
- arg = arg.slice(offset);
4104
- }
4105
- ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
4106
- const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
4107
- const ret = cachedTextEncoder.encodeInto(arg, view);
4108
- offset += ret.written;
4109
- ptr = realloc(ptr, len, offset, 1) >>> 0;
4110
- }
4111
- WASM_VECTOR_LEN = offset;
4112
- return ptr;
4113
- }
4114
- var cachedDataViewMemory0 = null;
4115
- function getDataViewMemory0() {
4116
- if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
4117
- cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
4118
- }
4119
- return cachedDataViewMemory0;
4120
- }
4121
- function isLikeNone(x) {
4122
- return x === void 0 || x === null;
4123
- }
4124
- function debugString(val) {
4125
- const type = typeof val;
4126
- if (type == "number" || type == "boolean" || val == null) {
4127
- return `${val}`;
4128
- }
4129
- if (type == "string") {
4130
- return `"${val}"`;
4131
- }
4132
- if (type == "symbol") {
4133
- const description = val.description;
4134
- if (description == null) {
4135
- return "Symbol";
4136
- } else {
4137
- return `Symbol(${description})`;
4138
- }
4139
- }
4140
- if (type == "function") {
4141
- const name = val.name;
4142
- if (typeof name == "string" && name.length > 0) {
4143
- return `Function(${name})`;
4220
+ // src/wasm_worker_proxy.ts
4221
+ var WasmWorkerProxy = class _WasmWorkerProxy {
4222
+ worker;
4223
+ nextId = 0;
4224
+ pendingCalls = /* @__PURE__ */ new Map();
4225
+ /** Queue cho asyncRecv — Worker gửi data về, Main Thread consume từng cái */
4226
+ recvResolveQueue = [];
4227
+ recvDataQueue = [];
4228
+ recvErrorQueue = [];
4229
+ /** Static cache persist across Worker instances */
4230
+ static cachedBlobUrl = null;
4231
+ static cachedWasmBytes = null;
4232
+ constructor(workerUrl) {
4233
+ if (!_WasmWorkerProxy.cachedBlobUrl) {
4234
+ const url = workerUrl.toString();
4235
+ const xhr = new XMLHttpRequest();
4236
+ xhr.open("GET", url, false);
4237
+ xhr.send();
4238
+ if (xhr.status === 200) {
4239
+ const blob = new Blob([xhr.responseText], { type: "application/javascript" });
4240
+ _WasmWorkerProxy.cachedBlobUrl = URL.createObjectURL(blob);
4241
+ }
4242
+ }
4243
+ if (_WasmWorkerProxy.cachedBlobUrl) {
4244
+ this.worker = new Worker(_WasmWorkerProxy.cachedBlobUrl, { type: "module" });
4144
4245
  } else {
4145
- return "Function";
4246
+ this.worker = new Worker(workerUrl, { type: "module" });
4146
4247
  }
4248
+ this.worker.onmessage = (e) => this.handleMessage(e.data);
4249
+ this.worker.onerror = (e) => {
4250
+ console.error("\u{1F534} WASM Worker error:", e.message);
4251
+ this.pendingCalls.forEach(({ reject }) => reject(new Error(`Worker error: ${e.message}`)));
4252
+ this.pendingCalls.clear();
4253
+ };
4147
4254
  }
4148
- if (Array.isArray(val)) {
4149
- const length = val.length;
4150
- let debug = "[";
4151
- if (length > 0) {
4152
- debug += debugString(val[0]);
4153
- }
4154
- for (let i = 1; i < length; i++) {
4155
- debug += ", " + debugString(val[i]);
4156
- }
4157
- debug += "]";
4158
- return debug;
4159
- }
4160
- const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
4161
- let className;
4162
- if (builtInMatches && builtInMatches.length > 1) {
4163
- className = builtInMatches[1];
4164
- } else {
4165
- return toString.call(val);
4166
- }
4167
- if (className == "Object") {
4168
- try {
4169
- return "Object(" + JSON.stringify(val) + ")";
4170
- } catch (_) {
4171
- return "Object";
4172
- }
4173
- }
4174
- if (val instanceof Error) {
4175
- return `${val.name}: ${val.message}
4176
- ${val.stack}`;
4177
- }
4178
- return className;
4179
- }
4180
- function handleError(f, args) {
4181
- try {
4182
- return f.apply(this, args);
4183
- } catch (e) {
4184
- wasm.__wbindgen_export3(addHeapObject(e));
4255
+ // === LIFECYCLE ===
4256
+ /** Initialize WASM trong Worker — fetch bytes 1 lần, gửi cached bytes cho Worker */
4257
+ async init(wasmPath) {
4258
+ if (!_WasmWorkerProxy.cachedWasmBytes) {
4259
+ const absoluteWasmPath = new URL(
4260
+ wasmPath || "/ermis_call_node_wasm_bg.wasm",
4261
+ window.location.origin
4262
+ ).href;
4263
+ const response = await fetch(absoluteWasmPath);
4264
+ _WasmWorkerProxy.cachedWasmBytes = await response.arrayBuffer();
4265
+ }
4266
+ const bytesCopy = _WasmWorkerProxy.cachedWasmBytes.slice(0);
4267
+ await this.call("init", { wasmBytes: bytesCopy }, [bytesCopy]);
4268
+ }
4269
+ /** Spawn WASM node */
4270
+ async spawn(relayUrls) {
4271
+ await this.call("spawn", { relayUrls });
4272
+ }
4273
+ /** Lấy local endpoint address */
4274
+ async getLocalEndpointAddr() {
4275
+ return await this.call("getLocalEndpointAddr");
4185
4276
  }
4186
- }
4187
- function dropObject(idx) {
4188
- if (idx < 132) return;
4189
- heap[idx] = heap_next;
4190
- heap_next = idx;
4191
- }
4192
- function takeObject(idx) {
4193
- const ret = getObject(idx);
4194
- dropObject(idx);
4195
- return ret;
4196
- }
4197
- function getArrayU8FromWasm0(ptr, len) {
4198
- ptr = ptr >>> 0;
4199
- return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
4200
- }
4201
- var CLOSURE_DTORS = typeof FinalizationRegistry === "undefined" ? { register: () => {
4202
- }, unregister: () => {
4203
- } } : new FinalizationRegistry((state) => state.dtor(state.a, state.b));
4204
- function makeMutClosure(arg0, arg1, dtor, f) {
4205
- const state = { a: arg0, b: arg1, cnt: 1, dtor };
4206
- const real = (...args) => {
4207
- state.cnt++;
4208
- const a = state.a;
4209
- state.a = 0;
4210
- try {
4211
- return f(a, state.b, ...args);
4212
- } finally {
4213
- state.a = a;
4214
- real._wbg_cb_unref();
4215
- }
4216
- };
4217
- real._wbg_cb_unref = () => {
4218
- if (--state.cnt === 0) {
4219
- state.dtor(state.a, state.b);
4220
- state.a = 0;
4221
- CLOSURE_DTORS.unregister(state);
4222
- }
4223
- };
4224
- CLOSURE_DTORS.register(real, state, state);
4225
- return real;
4226
- }
4227
- function makeClosure(arg0, arg1, dtor, f) {
4228
- const state = { a: arg0, b: arg1, cnt: 1, dtor };
4229
- const real = (...args) => {
4230
- state.cnt++;
4231
- try {
4232
- return f(state.a, state.b, ...args);
4233
- } finally {
4234
- real._wbg_cb_unref();
4235
- }
4236
- };
4237
- real._wbg_cb_unref = () => {
4238
- if (--state.cnt === 0) {
4239
- state.dtor(state.a, state.b);
4240
- state.a = 0;
4241
- CLOSURE_DTORS.unregister(state);
4242
- }
4243
- };
4244
- CLOSURE_DTORS.register(real, state, state);
4245
- return real;
4246
- }
4247
- function passArray8ToWasm0(arg, malloc) {
4248
- const ptr = malloc(arg.length * 1, 1) >>> 0;
4249
- getUint8ArrayMemory0().set(arg, ptr / 1);
4250
- WASM_VECTOR_LEN = arg.length;
4251
- return ptr;
4252
- }
4253
- function __wasm_bindgen_func_elem_12858(arg0, arg1) {
4254
- wasm.__wasm_bindgen_func_elem_12858(arg0, arg1);
4255
- }
4256
- function __wasm_bindgen_func_elem_11688(arg0, arg1, arg2) {
4257
- wasm.__wasm_bindgen_func_elem_11688(arg0, arg1, addHeapObject(arg2));
4258
- }
4259
- function __wasm_bindgen_func_elem_6230(arg0, arg1) {
4260
- wasm.__wasm_bindgen_func_elem_6230(arg0, arg1);
4261
- }
4262
- function __wasm_bindgen_func_elem_2287(arg0, arg1, arg2) {
4263
- wasm.__wasm_bindgen_func_elem_2287(arg0, arg1, addHeapObject(arg2));
4264
- }
4265
- function __wasm_bindgen_func_elem_12912(arg0, arg1, arg2) {
4266
- wasm.__wasm_bindgen_func_elem_12912(arg0, arg1, addHeapObject(arg2));
4267
- }
4268
- function __wasm_bindgen_func_elem_5748(arg0, arg1) {
4269
- wasm.__wasm_bindgen_func_elem_5748(arg0, arg1);
4270
- }
4271
- function __wasm_bindgen_func_elem_14376(arg0, arg1, arg2, arg3) {
4272
- wasm.__wasm_bindgen_func_elem_14376(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
4273
- }
4274
- var __wbindgen_enum_BinaryType = ["blob", "arraybuffer"];
4275
- var __wbindgen_enum_ReadableStreamType = ["bytes"];
4276
- var __wbindgen_enum_RequestCache = ["default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached"];
4277
- var __wbindgen_enum_RequestCredentials = ["omit", "same-origin", "include"];
4278
- var __wbindgen_enum_RequestMode = ["same-origin", "no-cors", "cors", "navigate"];
4279
- var ConnectionStatsFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
4280
- }, unregister: () => {
4281
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_connectionstats_free(ptr >>> 0, 1));
4282
- var ConnectionStats = class {
4283
- __destroy_into_raw() {
4284
- const ptr = this.__wbg_ptr;
4285
- this.__wbg_ptr = 0;
4286
- ConnectionStatsFinalization.unregister(this);
4287
- return ptr;
4288
- }
4289
- free() {
4290
- const ptr = this.__destroy_into_raw();
4291
- wasm.__wbg_connectionstats_free(ptr, 0);
4277
+ // === INodeCall IMPLEMENTATION ===
4278
+ async connect(address) {
4279
+ await this.call("connect", { address });
4292
4280
  }
4293
- /**
4294
- * @returns {number | undefined}
4295
- */
4296
- get rtt_ms() {
4297
- try {
4298
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4299
- wasm.__wbg_get_connectionstats_rtt_ms(retptr, this.__wbg_ptr);
4300
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4301
- var r2 = getDataViewMemory0().getFloat64(retptr + 8 * 1, true);
4302
- return r0 === 0 ? void 0 : r2;
4303
- } finally {
4304
- wasm.__wbindgen_add_to_stack_pointer(16);
4305
- }
4281
+ async acceptConnection() {
4282
+ await this.call("acceptConnection");
4306
4283
  }
4307
- /**
4308
- * @param {number | null} [arg0]
4309
- */
4310
- set rtt_ms(arg0) {
4311
- wasm.__wbg_set_connectionstats_rtt_ms(this.__wbg_ptr, !isLikeNone(arg0), isLikeNone(arg0) ? 0 : arg0);
4284
+ async sendFrame(data) {
4285
+ await this.call("sendFrame", { data }, [data.buffer]);
4312
4286
  }
4313
- /**
4314
- * @returns {number | undefined}
4315
- */
4316
- get packet_loss() {
4317
- try {
4318
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4319
- wasm.__wbg_get_connectionstats_packet_loss(retptr, this.__wbg_ptr);
4320
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4321
- var r2 = getDataViewMemory0().getFloat64(retptr + 8 * 1, true);
4322
- return r0 === 0 ? void 0 : r2;
4323
- } finally {
4324
- wasm.__wbindgen_add_to_stack_pointer(16);
4325
- }
4287
+ async beginWithGop(data) {
4288
+ await this.call("beginWithGop", { data }, [data.buffer]);
4326
4289
  }
4327
- /**
4328
- * @param {number | null} [arg0]
4329
- */
4330
- set packet_loss(arg0) {
4331
- wasm.__wbg_set_connectionstats_packet_loss(this.__wbg_ptr, !isLikeNone(arg0), isLikeNone(arg0) ? 0 : arg0);
4290
+ async sendAudioFrame(data) {
4291
+ await this.call("sendAudioFrame", { data }, [data.buffer]);
4332
4292
  }
4333
- /**
4334
- * @param {string | null} [connection_type]
4335
- * @param {number | null} [rtt_ms]
4336
- * @param {number | null} [packet_loss]
4337
- */
4338
- constructor(connection_type, rtt_ms, packet_loss) {
4339
- var ptr0 = isLikeNone(connection_type) ? 0 : passStringToWasm0(connection_type, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4340
- var len0 = WASM_VECTOR_LEN;
4341
- const ret = wasm.connectionstats_new(ptr0, len0, !isLikeNone(rtt_ms), isLikeNone(rtt_ms) ? 0 : rtt_ms, !isLikeNone(packet_loss), isLikeNone(packet_loss) ? 0 : packet_loss);
4342
- this.__wbg_ptr = ret >>> 0;
4343
- ConnectionStatsFinalization.register(this, this.__wbg_ptr, this);
4344
- return this;
4293
+ async sendControlFrame(data) {
4294
+ await this.call("sendControlFrame", { data });
4345
4295
  }
4346
4296
  /**
4347
- * @returns {string | undefined}
4297
+ * asyncRecv nhận data từ Worker recv loop.
4298
+ *
4299
+ * Worker chạy recv loop nội bộ, gửi data về qua postMessage.
4300
+ * Method này trả về Promise resolve khi có data mới.
4301
+ * KHÔNG BAO GIỜ block Main Thread — chỉ chờ postMessage event.
4348
4302
  */
4349
- get connection_type() {
4350
- try {
4351
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4352
- wasm.connectionstats_connection_type(retptr, this.__wbg_ptr);
4353
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4354
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4355
- let v1;
4356
- if (r0 !== 0) {
4357
- v1 = getStringFromWasm0(r0, r1).slice();
4358
- wasm.__wbindgen_export4(r0, r1 * 1, 1);
4359
- }
4360
- return v1;
4361
- } finally {
4362
- wasm.__wbindgen_add_to_stack_pointer(16);
4303
+ async asyncRecv() {
4304
+ if (this.recvDataQueue.length > 0) {
4305
+ return this.recvDataQueue.shift();
4363
4306
  }
4307
+ return new Promise((resolve, reject) => {
4308
+ this.recvResolveQueue.push(resolve);
4309
+ this.recvErrorQueue.push(reject);
4310
+ });
4364
4311
  }
4365
- /**
4366
- * @param {string | null} [value]
4367
- */
4368
- set connection_type(value) {
4369
- var ptr0 = isLikeNone(value) ? 0 : passStringToWasm0(value, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4370
- var len0 = WASM_VECTOR_LEN;
4371
- wasm.connectionstats_set_connection_type(this.__wbg_ptr, ptr0, len0);
4372
- }
4373
- };
4374
- if (Symbol.dispose) ConnectionStats.prototype[Symbol.dispose] = ConnectionStats.prototype.free;
4375
- var ErmisCallFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
4376
- }, unregister: () => {
4377
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_ermiscall_free(ptr >>> 0, 1));
4378
- var ErmisCall = class {
4379
- __destroy_into_raw() {
4380
- const ptr = this.__wbg_ptr;
4381
- this.__wbg_ptr = 0;
4382
- ErmisCallFinalization.unregister(this);
4383
- return ptr;
4384
- }
4385
- free() {
4386
- const ptr = this.__destroy_into_raw();
4387
- wasm.__wbg_ermiscall_free(ptr, 0);
4312
+ // === CONTROL ===
4313
+ /** Bắt đầu recv loop trong Worker */
4314
+ async startRecvLoop() {
4315
+ await this.call("startRecvLoop");
4388
4316
  }
4389
- constructor() {
4390
- const ret = wasm.ermiscall_new();
4391
- this.__wbg_ptr = ret >>> 0;
4392
- ErmisCallFinalization.register(this, this.__wbg_ptr, this);
4393
- return this;
4317
+ /** Dừng recv loop trong Worker */
4318
+ async stopRecvLoop() {
4319
+ await this.call("stopRecvLoop");
4394
4320
  }
4395
- /**
4396
- * @param {any} relay_urls
4397
- * @param {Uint8Array | null} [secret_key]
4398
- * @returns {Promise<void>}
4399
- */
4400
- spawn(relay_urls, secret_key) {
4401
- var ptr0 = isLikeNone(secret_key) ? 0 : passArray8ToWasm0(secret_key, wasm.__wbindgen_export);
4402
- var len0 = WASM_VECTOR_LEN;
4403
- const ret = wasm.ermiscall_spawn(this.__wbg_ptr, addHeapObject(relay_urls), ptr0, len0);
4404
- return takeObject(ret);
4321
+ async closeEndpoint() {
4322
+ await this.call("closeEndpoint");
4405
4323
  }
4406
- /**
4407
- * @returns {Promise<string>}
4408
- */
4409
- getLocalEndpointAddr() {
4410
- const ret = wasm.ermiscall_getLocalEndpointAddr(this.__wbg_ptr);
4411
- return takeObject(ret);
4324
+ closeConnection() {
4325
+ const id = this.nextId++;
4326
+ this.worker.postMessage({ id, type: "closeConnection" });
4412
4327
  }
4413
- /**
4414
- * @param {string} addr
4415
- * @returns {Promise<void>}
4416
- */
4417
- connect(addr) {
4418
- const ptr0 = passStringToWasm0(addr, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4419
- const len0 = WASM_VECTOR_LEN;
4420
- const ret = wasm.ermiscall_connect(this.__wbg_ptr, ptr0, len0);
4421
- return takeObject(ret);
4328
+ networkChange() {
4329
+ const id = this.nextId++;
4330
+ this.worker.postMessage({ id, type: "networkChange" });
4422
4331
  }
4423
- /**
4424
- * @returns {Promise<void>}
4425
- */
4426
- closeEndpoint() {
4427
- const ret = wasm.ermiscall_closeEndpoint(this.__wbg_ptr);
4428
- return takeObject(ret);
4332
+ async getStats() {
4333
+ return await this.call("getStats");
4429
4334
  }
4430
- closeConnection() {
4335
+ /** Terminate Worker — gọi khi call kết thúc */
4336
+ async terminate() {
4431
4337
  try {
4432
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4433
- wasm.ermiscall_closeConnection(retptr, this.__wbg_ptr);
4434
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4435
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4436
- if (r1) {
4437
- throw takeObject(r0);
4338
+ await this.call("terminate");
4339
+ } catch {
4340
+ }
4341
+ this.worker.terminate();
4342
+ this.recvResolveQueue = [];
4343
+ this.recvErrorQueue.forEach((reject) => reject(new Error("Worker terminated")));
4344
+ this.recvErrorQueue = [];
4345
+ this.recvDataQueue = [];
4346
+ }
4347
+ // === INTERNAL ===
4348
+ handleMessage(msg) {
4349
+ if (msg.type === "recv_data") {
4350
+ const data = msg.data;
4351
+ if (this.recvResolveQueue.length > 0) {
4352
+ const resolve = this.recvResolveQueue.shift();
4353
+ this.recvErrorQueue.shift();
4354
+ resolve(data);
4355
+ } else {
4356
+ this.recvDataQueue.push(data);
4438
4357
  }
4439
- } finally {
4440
- wasm.__wbindgen_add_to_stack_pointer(16);
4358
+ return;
4441
4359
  }
4442
- }
4443
- /**
4444
- * @returns {Promise<void>}
4445
- */
4446
- acceptConnection() {
4447
- const ret = wasm.ermiscall_acceptConnection(this.__wbg_ptr);
4448
- return takeObject(ret);
4449
- }
4450
- /**
4451
- * @param {Uint8Array} data
4452
- */
4453
- sendControlFrame(data) {
4454
- try {
4455
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4456
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
4457
- const len0 = WASM_VECTOR_LEN;
4458
- wasm.ermiscall_sendControlFrame(retptr, this.__wbg_ptr, ptr0, len0);
4459
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4460
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4461
- if (r1) {
4462
- throw takeObject(r0);
4360
+ if (msg.type === "recv_error") {
4361
+ const error = new Error(msg.error);
4362
+ if (this.recvErrorQueue.length > 0) {
4363
+ const reject = this.recvErrorQueue.shift();
4364
+ this.recvResolveQueue.shift();
4365
+ reject(error);
4463
4366
  }
4464
- } finally {
4465
- wasm.__wbindgen_add_to_stack_pointer(16);
4367
+ return;
4368
+ }
4369
+ const { id } = msg;
4370
+ const pending = this.pendingCalls.get(id);
4371
+ if (!pending) return;
4372
+ this.pendingCalls.delete(id);
4373
+ if (msg.type === "error") {
4374
+ pending.reject(new Error(msg.error));
4375
+ } else {
4376
+ pending.resolve(msg.data);
4466
4377
  }
4467
4378
  }
4468
- /**
4469
- * @param {Uint8Array} data
4470
- */
4471
- sendAudioFrame(data) {
4472
- try {
4473
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4474
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
4475
- const len0 = WASM_VECTOR_LEN;
4476
- wasm.ermiscall_sendAudioFrame(retptr, this.__wbg_ptr, ptr0, len0);
4477
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4478
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4479
- if (r1) {
4480
- throw takeObject(r0);
4379
+ /** Send RPC call to Worker and wait for response */
4380
+ call(type, payload, transfer) {
4381
+ const id = this.nextId++;
4382
+ return new Promise((resolve, reject) => {
4383
+ this.pendingCalls.set(id, { resolve, reject });
4384
+ const message = { id, type, ...payload };
4385
+ if (transfer && transfer.length > 0) {
4386
+ this.worker.postMessage(message, transfer);
4387
+ } else {
4388
+ this.worker.postMessage(message);
4481
4389
  }
4482
- } finally {
4483
- wasm.__wbindgen_add_to_stack_pointer(16);
4484
- }
4390
+ });
4391
+ }
4392
+ };
4393
+
4394
+ // src/media_stream_sender.ts
4395
+ var MediaStreamSender = class {
4396
+ videoEncoder = null;
4397
+ audioEncoder = null;
4398
+ videoReader = null;
4399
+ audioReader = null;
4400
+ localStream = null;
4401
+ videoConfig = null;
4402
+ audioConfig = null;
4403
+ videoConfigSent = false;
4404
+ audioConfigSent = false;
4405
+ hasVideo = false;
4406
+ hasAudio = false;
4407
+ forceKeyFrame = false;
4408
+ isSendingVideo = false;
4409
+ isSendingAudio = false;
4410
+ nodeCall;
4411
+ healthCallInterval = null;
4412
+ constructor(nodeCall) {
4413
+ this.nodeCall = nodeCall;
4485
4414
  }
4486
4415
  /**
4487
- * @param {Uint8Array} data
4416
+ * Bắt đầu xử lý MediaStream
4488
4417
  */
4489
- sendFrame(data) {
4418
+ async connect(address) {
4490
4419
  try {
4491
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4492
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
4493
- const len0 = WASM_VECTOR_LEN;
4494
- wasm.ermiscall_sendFrame(retptr, this.__wbg_ptr, ptr0, len0);
4495
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4496
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4497
- if (r1) {
4498
- throw takeObject(r0);
4499
- }
4500
- } finally {
4501
- wasm.__wbindgen_add_to_stack_pointer(16);
4420
+ await this.nodeCall.connect(address);
4421
+ await this.sendConnected();
4422
+ await this.sendConfigs();
4423
+ this.startHealthCallInterval();
4424
+ } catch (error) {
4425
+ console.error("Error starting MediaStreamSender:", error);
4502
4426
  }
4503
4427
  }
4504
- notifyNewGop() {
4428
+ async sendConfigs() {
4505
4429
  try {
4506
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4507
- wasm.ermiscall_notifyNewGop(retptr, this.__wbg_ptr);
4508
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4509
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4510
- if (r1) {
4511
- throw takeObject(r0);
4430
+ await this.sendTransceiverState(this.hasAudio, this.hasVideo);
4431
+ await this.sendAudioConfig();
4432
+ const videoTrack = this.localStream?.getVideoTracks()[0];
4433
+ if (videoTrack) {
4434
+ await this.sendVideoConfig();
4512
4435
  }
4513
- } finally {
4514
- wasm.__wbindgen_add_to_stack_pointer(16);
4436
+ } catch (error) {
4437
+ console.error("Error sending configs:", error);
4515
4438
  }
4516
4439
  }
4517
4440
  /**
4518
- * @returns {Uint8Array}
4441
+ * Dừng và reset encoders
4519
4442
  */
4520
- recv() {
4521
- try {
4522
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4523
- wasm.ermiscall_recv(retptr, this.__wbg_ptr);
4524
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4525
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4526
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
4527
- if (r2) {
4528
- throw takeObject(r1);
4529
- }
4530
- return takeObject(r0);
4531
- } finally {
4532
- wasm.__wbindgen_add_to_stack_pointer(16);
4443
+ stop = () => {
4444
+ if (this.healthCallInterval) {
4445
+ clearInterval(this.healthCallInterval);
4446
+ this.healthCallInterval = null;
4533
4447
  }
4534
- }
4535
- /**
4536
- * @returns {Promise<Uint8Array>}
4537
- */
4538
- asyncRecv() {
4539
- const ret = wasm.ermiscall_asyncRecv(this.__wbg_ptr);
4540
- return takeObject(ret);
4541
- }
4542
- /**
4543
- * @param {Uint8Array} data
4544
- */
4545
- beginWithGop(data) {
4546
- try {
4547
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4548
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
4549
- const len0 = WASM_VECTOR_LEN;
4550
- wasm.ermiscall_beginWithGop(retptr, this.__wbg_ptr, ptr0, len0);
4551
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4552
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4553
- if (r1) {
4554
- throw takeObject(r0);
4555
- }
4556
- } finally {
4557
- wasm.__wbindgen_add_to_stack_pointer(16);
4558
- }
4559
- }
4560
- /**
4561
- * @returns {string | undefined}
4562
- */
4563
- connectionType() {
4564
- try {
4565
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4566
- wasm.ermiscall_connectionType(retptr, this.__wbg_ptr);
4567
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4568
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4569
- let v1;
4570
- if (r0 !== 0) {
4571
- v1 = getStringFromWasm0(r0, r1).slice();
4572
- wasm.__wbindgen_export4(r0, r1 * 1, 1);
4573
- }
4574
- return v1;
4575
- } finally {
4576
- wasm.__wbindgen_add_to_stack_pointer(16);
4577
- }
4578
- }
4579
- /**
4580
- * @returns {number | undefined}
4581
- */
4582
- roundTripTime() {
4583
- try {
4584
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4585
- wasm.ermiscall_roundTripTime(retptr, this.__wbg_ptr);
4586
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4587
- var r2 = getDataViewMemory0().getFloat64(retptr + 8 * 1, true);
4588
- return r0 === 0 ? void 0 : r2;
4589
- } finally {
4590
- wasm.__wbindgen_add_to_stack_pointer(16);
4591
- }
4592
- }
4593
- /**
4594
- * @returns {number | undefined}
4595
- */
4596
- currentPacketLoss() {
4597
- try {
4598
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4599
- wasm.ermiscall_currentPacketLoss(retptr, this.__wbg_ptr);
4600
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4601
- var r2 = getDataViewMemory0().getFloat64(retptr + 8 * 1, true);
4602
- return r0 === 0 ? void 0 : r2;
4603
- } finally {
4604
- wasm.__wbindgen_add_to_stack_pointer(16);
4605
- }
4606
- }
4607
- networkChange() {
4608
- wasm.ermiscall_networkChange(this.__wbg_ptr);
4609
- }
4610
- /**
4611
- * @returns {any}
4612
- */
4613
- getStats() {
4614
- try {
4615
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
4616
- wasm.ermiscall_getStats(retptr, this.__wbg_ptr);
4617
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
4618
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
4619
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
4620
- if (r2) {
4621
- throw takeObject(r1);
4622
- }
4623
- return takeObject(r0);
4624
- } finally {
4625
- wasm.__wbindgen_add_to_stack_pointer(16);
4626
- }
4627
- }
4628
- };
4629
- if (Symbol.dispose) ErmisCall.prototype[Symbol.dispose] = ErmisCall.prototype.free;
4630
- var IntoUnderlyingByteSourceFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
4631
- }, unregister: () => {
4632
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_intounderlyingbytesource_free(ptr >>> 0, 1));
4633
- var IntoUnderlyingByteSource = class {
4634
- __destroy_into_raw() {
4635
- const ptr = this.__wbg_ptr;
4636
- this.__wbg_ptr = 0;
4637
- IntoUnderlyingByteSourceFinalization.unregister(this);
4638
- return ptr;
4639
- }
4640
- free() {
4641
- const ptr = this.__destroy_into_raw();
4642
- wasm.__wbg_intounderlyingbytesource_free(ptr, 0);
4643
- }
4644
- /**
4645
- * @returns {ReadableStreamType}
4646
- */
4647
- get type() {
4648
- const ret = wasm.intounderlyingbytesource_type(this.__wbg_ptr);
4649
- return __wbindgen_enum_ReadableStreamType[ret];
4650
- }
4651
- /**
4652
- * @returns {number}
4653
- */
4654
- get autoAllocateChunkSize() {
4655
- const ret = wasm.intounderlyingbytesource_autoAllocateChunkSize(this.__wbg_ptr);
4656
- return ret >>> 0;
4657
- }
4658
- /**
4659
- * @param {ReadableByteStreamController} controller
4660
- */
4661
- start(controller) {
4662
- wasm.intounderlyingbytesource_start(this.__wbg_ptr, addHeapObject(controller));
4663
- }
4664
- /**
4665
- * @param {ReadableByteStreamController} controller
4666
- * @returns {Promise<any>}
4667
- */
4668
- pull(controller) {
4669
- const ret = wasm.intounderlyingbytesource_pull(this.__wbg_ptr, addHeapObject(controller));
4670
- return takeObject(ret);
4671
- }
4672
- cancel() {
4673
- const ptr = this.__destroy_into_raw();
4674
- wasm.intounderlyingbytesource_cancel(ptr);
4675
- }
4676
- };
4677
- if (Symbol.dispose) IntoUnderlyingByteSource.prototype[Symbol.dispose] = IntoUnderlyingByteSource.prototype.free;
4678
- var IntoUnderlyingSinkFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
4679
- }, unregister: () => {
4680
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_intounderlyingsink_free(ptr >>> 0, 1));
4681
- var IntoUnderlyingSink = class {
4682
- __destroy_into_raw() {
4683
- const ptr = this.__wbg_ptr;
4684
- this.__wbg_ptr = 0;
4685
- IntoUnderlyingSinkFinalization.unregister(this);
4686
- return ptr;
4687
- }
4688
- free() {
4689
- const ptr = this.__destroy_into_raw();
4690
- wasm.__wbg_intounderlyingsink_free(ptr, 0);
4691
- }
4692
- /**
4693
- * @param {any} chunk
4694
- * @returns {Promise<any>}
4695
- */
4696
- write(chunk) {
4697
- const ret = wasm.intounderlyingsink_write(this.__wbg_ptr, addHeapObject(chunk));
4698
- return takeObject(ret);
4699
- }
4700
- /**
4701
- * @returns {Promise<any>}
4702
- */
4703
- close() {
4704
- const ptr = this.__destroy_into_raw();
4705
- const ret = wasm.intounderlyingsink_close(ptr);
4706
- return takeObject(ret);
4707
- }
4708
- /**
4709
- * @param {any} reason
4710
- * @returns {Promise<any>}
4711
- */
4712
- abort(reason) {
4713
- const ptr = this.__destroy_into_raw();
4714
- const ret = wasm.intounderlyingsink_abort(ptr, addHeapObject(reason));
4715
- return takeObject(ret);
4716
- }
4717
- };
4718
- if (Symbol.dispose) IntoUnderlyingSink.prototype[Symbol.dispose] = IntoUnderlyingSink.prototype.free;
4719
- var IntoUnderlyingSourceFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
4720
- }, unregister: () => {
4721
- } } : new FinalizationRegistry((ptr) => wasm.__wbg_intounderlyingsource_free(ptr >>> 0, 1));
4722
- var IntoUnderlyingSource = class {
4723
- __destroy_into_raw() {
4724
- const ptr = this.__wbg_ptr;
4725
- this.__wbg_ptr = 0;
4726
- IntoUnderlyingSourceFinalization.unregister(this);
4727
- return ptr;
4728
- }
4729
- free() {
4730
- const ptr = this.__destroy_into_raw();
4731
- wasm.__wbg_intounderlyingsource_free(ptr, 0);
4732
- }
4733
- /**
4734
- * @param {ReadableStreamDefaultController} controller
4735
- * @returns {Promise<any>}
4736
- */
4737
- pull(controller) {
4738
- const ret = wasm.intounderlyingsource_pull(this.__wbg_ptr, addHeapObject(controller));
4739
- return takeObject(ret);
4740
- }
4741
- cancel() {
4742
- const ptr = this.__destroy_into_raw();
4743
- wasm.intounderlyingsource_cancel(ptr);
4744
- }
4745
- };
4746
- if (Symbol.dispose) IntoUnderlyingSource.prototype[Symbol.dispose] = IntoUnderlyingSource.prototype.free;
4747
- var EXPECTED_RESPONSE_TYPES = /* @__PURE__ */ new Set(["basic", "cors", "default"]);
4748
- async function __wbg_load(module2, imports) {
4749
- if (typeof Response === "function" && module2 instanceof Response) {
4750
- if (typeof WebAssembly.instantiateStreaming === "function") {
4751
- try {
4752
- return await WebAssembly.instantiateStreaming(module2, imports);
4753
- } catch (e) {
4754
- const validResponse = module2.ok && EXPECTED_RESPONSE_TYPES.has(module2.type);
4755
- if (validResponse && module2.headers.get("Content-Type") !== "application/wasm") {
4756
- console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
4757
- } else {
4758
- throw e;
4759
- }
4760
- }
4761
- }
4762
- const bytes = await module2.arrayBuffer();
4763
- return await WebAssembly.instantiate(bytes, imports);
4764
- } else {
4765
- const instance = await WebAssembly.instantiate(module2, imports);
4766
- if (instance instanceof WebAssembly.Instance) {
4767
- return { instance, module: module2 };
4768
- } else {
4769
- return instance;
4770
- }
4771
- }
4772
- }
4773
- function __wbg_get_imports() {
4774
- const imports = {};
4775
- imports.wbg = {};
4776
- imports.wbg.__wbg_Error_e83987f665cf5504 = function(arg0, arg1) {
4777
- const ret = Error(getStringFromWasm0(arg0, arg1));
4778
- return addHeapObject(ret);
4779
- };
4780
- imports.wbg.__wbg_String_8f0eb39a4a4c2f66 = function(arg0, arg1) {
4781
- const ret = String(getObject(arg1));
4782
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4783
- const len1 = WASM_VECTOR_LEN;
4784
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
4785
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
4786
- };
4787
- imports.wbg.__wbg___wbindgen_boolean_get_6d5a1ee65bab5f68 = function(arg0) {
4788
- const v = getObject(arg0);
4789
- const ret = typeof v === "boolean" ? v : void 0;
4790
- return isLikeNone(ret) ? 16777215 : ret ? 1 : 0;
4791
- };
4792
- imports.wbg.__wbg___wbindgen_debug_string_df47ffb5e35e6763 = function(arg0, arg1) {
4793
- const ret = debugString(getObject(arg1));
4794
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4795
- const len1 = WASM_VECTOR_LEN;
4796
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
4797
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
4798
- };
4799
- imports.wbg.__wbg___wbindgen_is_function_ee8a6c5833c90377 = function(arg0) {
4800
- const ret = typeof getObject(arg0) === "function";
4801
- return ret;
4802
- };
4803
- imports.wbg.__wbg___wbindgen_is_object_c818261d21f283a4 = function(arg0) {
4804
- const val = getObject(arg0);
4805
- const ret = typeof val === "object" && val !== null;
4806
- return ret;
4807
- };
4808
- imports.wbg.__wbg___wbindgen_is_string_fbb76cb2940daafd = function(arg0) {
4809
- const ret = typeof getObject(arg0) === "string";
4810
- return ret;
4811
- };
4812
- imports.wbg.__wbg___wbindgen_is_undefined_2d472862bd29a478 = function(arg0) {
4813
- const ret = getObject(arg0) === void 0;
4814
- return ret;
4815
- };
4816
- imports.wbg.__wbg___wbindgen_jsval_loose_eq_b664b38a2f582147 = function(arg0, arg1) {
4817
- const ret = getObject(arg0) == getObject(arg1);
4818
- return ret;
4819
- };
4820
- imports.wbg.__wbg___wbindgen_number_get_a20bf9b85341449d = function(arg0, arg1) {
4821
- const obj = getObject(arg1);
4822
- const ret = typeof obj === "number" ? obj : void 0;
4823
- getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);
4824
- getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
4825
- };
4826
- imports.wbg.__wbg___wbindgen_string_get_e4f06c90489ad01b = function(arg0, arg1) {
4827
- const obj = getObject(arg1);
4828
- const ret = typeof obj === "string" ? obj : void 0;
4829
- var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
4830
- var len1 = WASM_VECTOR_LEN;
4831
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
4832
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
4833
- };
4834
- imports.wbg.__wbg___wbindgen_throw_b855445ff6a94295 = function(arg0, arg1) {
4835
- throw new Error(getStringFromWasm0(arg0, arg1));
4836
- };
4837
- imports.wbg.__wbg__wbg_cb_unref_2454a539ea5790d9 = function(arg0) {
4838
- getObject(arg0)._wbg_cb_unref();
4839
- };
4840
- imports.wbg.__wbg_abort_28ad55c5825b004d = function(arg0, arg1) {
4841
- getObject(arg0).abort(getObject(arg1));
4842
- };
4843
- imports.wbg.__wbg_abort_e7eb059f72f9ed0c = function(arg0) {
4844
- getObject(arg0).abort();
4845
- };
4846
- imports.wbg.__wbg_addEventListener_40dc0fc428fc49e1 = function() {
4847
- return handleError(function(arg0, arg1, arg2, arg3) {
4848
- getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3));
4849
- }, arguments);
4850
- };
4851
- imports.wbg.__wbg_append_b577eb3a177bc0fa = function() {
4852
- return handleError(function(arg0, arg1, arg2, arg3, arg4) {
4853
- getObject(arg0).append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
4854
- }, arguments);
4855
- };
4856
- imports.wbg.__wbg_body_587542b2fd8e06c0 = function(arg0) {
4857
- const ret = getObject(arg0).body;
4858
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
4859
- };
4860
- imports.wbg.__wbg_buffer_ccc4520b36d3ccf4 = function(arg0) {
4861
- const ret = getObject(arg0).buffer;
4862
- return addHeapObject(ret);
4863
- };
4864
- imports.wbg.__wbg_byobRequest_2344e6975f27456e = function(arg0) {
4865
- const ret = getObject(arg0).byobRequest;
4866
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
4867
- };
4868
- imports.wbg.__wbg_byteLength_bcd42e4025299788 = function(arg0) {
4869
- const ret = getObject(arg0).byteLength;
4870
- return ret;
4871
- };
4872
- imports.wbg.__wbg_byteOffset_ca3a6cf7944b364b = function(arg0) {
4873
- const ret = getObject(arg0).byteOffset;
4874
- return ret;
4875
- };
4876
- imports.wbg.__wbg_call_525440f72fbfc0ea = function() {
4877
- return handleError(function(arg0, arg1, arg2) {
4878
- const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
4879
- return addHeapObject(ret);
4880
- }, arguments);
4881
- };
4882
- imports.wbg.__wbg_call_e762c39fa8ea36bf = function() {
4883
- return handleError(function(arg0, arg1) {
4884
- const ret = getObject(arg0).call(getObject(arg1));
4885
- return addHeapObject(ret);
4886
- }, arguments);
4887
- };
4888
- imports.wbg.__wbg_cancel_48ab6f9dc366e369 = function(arg0) {
4889
- const ret = getObject(arg0).cancel();
4890
- return addHeapObject(ret);
4891
- };
4892
- imports.wbg.__wbg_catch_943836faa5d29bfb = function(arg0, arg1) {
4893
- const ret = getObject(arg0).catch(getObject(arg1));
4894
- return addHeapObject(ret);
4895
- };
4896
- imports.wbg.__wbg_clearTimeout_15dfc3d1dcb635c6 = function() {
4897
- return handleError(function(arg0, arg1) {
4898
- getObject(arg0).clearTimeout(takeObject(arg1));
4899
- }, arguments);
4900
- };
4901
- imports.wbg.__wbg_clearTimeout_7a42b49784aea641 = function(arg0) {
4902
- const ret = clearTimeout(takeObject(arg0));
4903
- return addHeapObject(ret);
4904
- };
4905
- imports.wbg.__wbg_close_5a6caed3231b68cd = function() {
4906
- return handleError(function(arg0) {
4907
- getObject(arg0).close();
4908
- }, arguments);
4909
- };
4910
- imports.wbg.__wbg_close_6956df845478561a = function() {
4911
- return handleError(function(arg0) {
4912
- getObject(arg0).close();
4913
- }, arguments);
4914
- };
4915
- imports.wbg.__wbg_close_885e277edf06b3fa = function() {
4916
- return handleError(function(arg0) {
4917
- getObject(arg0).close();
4918
- }, arguments);
4919
- };
4920
- imports.wbg.__wbg_code_20d453b11b200026 = function(arg0) {
4921
- const ret = getObject(arg0).code;
4922
- return ret;
4923
- };
4924
- imports.wbg.__wbg_code_218f5fdf8c7fcabd = function(arg0) {
4925
- const ret = getObject(arg0).code;
4926
- return ret;
4927
- };
4928
- imports.wbg.__wbg_crypto_574e78ad8b13b65f = function(arg0) {
4929
- const ret = getObject(arg0).crypto;
4930
- return addHeapObject(ret);
4931
- };
4932
- imports.wbg.__wbg_data_ee4306d069f24f2d = function(arg0) {
4933
- const ret = getObject(arg0).data;
4934
- return addHeapObject(ret);
4935
- };
4936
- imports.wbg.__wbg_done_2042aa2670fb1db1 = function(arg0) {
4937
- const ret = getObject(arg0).done;
4938
- return ret;
4939
- };
4940
- imports.wbg.__wbg_enqueue_7b18a650aec77898 = function() {
4941
- return handleError(function(arg0, arg1) {
4942
- getObject(arg0).enqueue(getObject(arg1));
4943
- }, arguments);
4944
- };
4945
- imports.wbg.__wbg_fetch_74a3e84ebd2c9a0e = function(arg0) {
4946
- const ret = fetch(getObject(arg0));
4947
- return addHeapObject(ret);
4948
- };
4949
- imports.wbg.__wbg_fetch_f8ba0e29a9d6de0d = function(arg0, arg1) {
4950
- const ret = getObject(arg0).fetch(getObject(arg1));
4951
- return addHeapObject(ret);
4952
- };
4953
- imports.wbg.__wbg_getRandomValues_1c61fac11405ffdc = function() {
4954
- return handleError(function(arg0, arg1) {
4955
- globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
4956
- }, arguments);
4957
- };
4958
- imports.wbg.__wbg_getRandomValues_b8f5dbd5f3995a9e = function() {
4959
- return handleError(function(arg0, arg1) {
4960
- getObject(arg0).getRandomValues(getObject(arg1));
4961
- }, arguments);
4962
- };
4963
- imports.wbg.__wbg_getReader_48e00749fe3f6089 = function() {
4964
- return handleError(function(arg0) {
4965
- const ret = getObject(arg0).getReader();
4966
- return addHeapObject(ret);
4967
- }, arguments);
4968
- };
4969
- imports.wbg.__wbg_getTime_14776bfb48a1bff9 = function(arg0) {
4970
- const ret = getObject(arg0).getTime();
4971
- return ret;
4972
- };
4973
- imports.wbg.__wbg_get_7bed016f185add81 = function(arg0, arg1) {
4974
- const ret = getObject(arg0)[arg1 >>> 0];
4975
- return addHeapObject(ret);
4976
- };
4977
- imports.wbg.__wbg_get_done_a0463af43a1fc764 = function(arg0) {
4978
- const ret = getObject(arg0).done;
4979
- return isLikeNone(ret) ? 16777215 : ret ? 1 : 0;
4980
- };
4981
- imports.wbg.__wbg_get_efcb449f58ec27c2 = function() {
4982
- return handleError(function(arg0, arg1) {
4983
- const ret = Reflect.get(getObject(arg0), getObject(arg1));
4984
- return addHeapObject(ret);
4985
- }, arguments);
4986
- };
4987
- imports.wbg.__wbg_get_value_5ce96c9f81ce7398 = function(arg0) {
4988
- const ret = getObject(arg0).value;
4989
- return addHeapObject(ret);
4990
- };
4991
- imports.wbg.__wbg_has_787fafc980c3ccdb = function() {
4992
- return handleError(function(arg0, arg1) {
4993
- const ret = Reflect.has(getObject(arg0), getObject(arg1));
4994
- return ret;
4995
- }, arguments);
4996
- };
4997
- imports.wbg.__wbg_headers_b87d7eaba61c3278 = function(arg0) {
4998
- const ret = getObject(arg0).headers;
4999
- return addHeapObject(ret);
5000
- };
5001
- imports.wbg.__wbg_instanceof_ArrayBuffer_70beb1189ca63b38 = function(arg0) {
5002
- let result;
5003
- try {
5004
- result = getObject(arg0) instanceof ArrayBuffer;
5005
- } catch (_) {
5006
- result = false;
5007
- }
5008
- const ret = result;
5009
- return ret;
5010
- };
5011
- imports.wbg.__wbg_instanceof_Blob_23b3322f66e5a83b = function(arg0) {
5012
- let result;
5013
- try {
5014
- result = getObject(arg0) instanceof Blob;
5015
- } catch (_) {
5016
- result = false;
5017
- }
5018
- const ret = result;
5019
- return ret;
5020
- };
5021
- imports.wbg.__wbg_instanceof_Response_f4f3e87e07f3135c = function(arg0) {
5022
- let result;
5023
- try {
5024
- result = getObject(arg0) instanceof Response;
5025
- } catch (_) {
5026
- result = false;
5027
- }
5028
- const ret = result;
5029
- return ret;
5030
- };
5031
- imports.wbg.__wbg_instanceof_Uint8Array_20c8e73002f7af98 = function(arg0) {
5032
- let result;
5033
- try {
5034
- result = getObject(arg0) instanceof Uint8Array;
5035
- } catch (_) {
5036
- result = false;
5037
- }
5038
- const ret = result;
5039
- return ret;
5040
- };
5041
- imports.wbg.__wbg_isArray_96e0af9891d0945d = function(arg0) {
5042
- const ret = Array.isArray(getObject(arg0));
5043
- return ret;
5044
- };
5045
- imports.wbg.__wbg_iterator_e5822695327a3c39 = function() {
5046
- const ret = Symbol.iterator;
5047
- return addHeapObject(ret);
5048
- };
5049
- imports.wbg.__wbg_length_69bca3cb64fc8748 = function(arg0) {
5050
- const ret = getObject(arg0).length;
5051
- return ret;
5052
- };
5053
- imports.wbg.__wbg_length_cdd215e10d9dd507 = function(arg0) {
5054
- const ret = getObject(arg0).length;
5055
- return ret;
5056
- };
5057
- imports.wbg.__wbg_log_ee0138cca4957740 = function(arg0, arg1) {
5058
- console.log(getStringFromWasm0(arg0, arg1));
5059
- };
5060
- imports.wbg.__wbg_message_bd42dbe3f2f3ed8e = function(arg0, arg1) {
5061
- const ret = getObject(arg1).message;
5062
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
5063
- const len1 = WASM_VECTOR_LEN;
5064
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
5065
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
5066
- };
5067
- imports.wbg.__wbg_msCrypto_a61aeb35a24c1329 = function(arg0) {
5068
- const ret = getObject(arg0).msCrypto;
5069
- return addHeapObject(ret);
5070
- };
5071
- imports.wbg.__wbg_new_0_f9740686d739025c = function() {
5072
- const ret = /* @__PURE__ */ new Date();
5073
- return addHeapObject(ret);
5074
- };
5075
- imports.wbg.__wbg_new_1acc0b6eea89d040 = function() {
5076
- const ret = new Object();
5077
- return addHeapObject(ret);
5078
- };
5079
- imports.wbg.__wbg_new_2531773dac38ebb3 = function() {
5080
- return handleError(function() {
5081
- const ret = new AbortController();
5082
- return addHeapObject(ret);
5083
- }, arguments);
5084
- };
5085
- imports.wbg.__wbg_new_3c3d849046688a66 = function(arg0, arg1) {
5086
- try {
5087
- var state0 = { a: arg0, b: arg1 };
5088
- var cb0 = (arg02, arg12) => {
5089
- const a = state0.a;
5090
- state0.a = 0;
5091
- try {
5092
- return __wasm_bindgen_func_elem_14376(a, state0.b, arg02, arg12);
5093
- } finally {
5094
- state0.a = a;
5095
- }
5096
- };
5097
- const ret = new Promise(cb0);
5098
- return addHeapObject(ret);
5099
- } finally {
5100
- state0.a = state0.b = 0;
5101
- }
5102
- };
5103
- imports.wbg.__wbg_new_5a79be3ab53b8aa5 = function(arg0) {
5104
- const ret = new Uint8Array(getObject(arg0));
5105
- return addHeapObject(ret);
5106
- };
5107
- imports.wbg.__wbg_new_881c4fe631eee9ad = function() {
5108
- return handleError(function(arg0, arg1) {
5109
- const ret = new WebSocket(getStringFromWasm0(arg0, arg1));
5110
- return addHeapObject(ret);
5111
- }, arguments);
5112
- };
5113
- imports.wbg.__wbg_new_9edf9838a2def39c = function() {
5114
- return handleError(function() {
5115
- const ret = new Headers();
5116
- return addHeapObject(ret);
5117
- }, arguments);
5118
- };
5119
- imports.wbg.__wbg_new_a7442b4b19c1a356 = function(arg0, arg1) {
5120
- const ret = new Error(getStringFromWasm0(arg0, arg1));
5121
- return addHeapObject(ret);
5122
- };
5123
- imports.wbg.__wbg_new_e17d9f43105b08be = function() {
5124
- const ret = new Array();
5125
- return addHeapObject(ret);
5126
- };
5127
- imports.wbg.__wbg_new_from_slice_92f4d78ca282a2d2 = function(arg0, arg1) {
5128
- const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
5129
- return addHeapObject(ret);
5130
- };
5131
- imports.wbg.__wbg_new_no_args_ee98eee5275000a4 = function(arg0, arg1) {
5132
- const ret = new Function(getStringFromWasm0(arg0, arg1));
5133
- return addHeapObject(ret);
5134
- };
5135
- imports.wbg.__wbg_new_with_byte_offset_and_length_46e3e6a5e9f9e89b = function(arg0, arg1, arg2) {
5136
- const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
5137
- return addHeapObject(ret);
5138
- };
5139
- imports.wbg.__wbg_new_with_length_01aa0dc35aa13543 = function(arg0) {
5140
- const ret = new Uint8Array(arg0 >>> 0);
5141
- return addHeapObject(ret);
5142
- };
5143
- imports.wbg.__wbg_new_with_str_and_init_0ae7728b6ec367b1 = function() {
5144
- return handleError(function(arg0, arg1, arg2) {
5145
- const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
5146
- return addHeapObject(ret);
5147
- }, arguments);
5148
- };
5149
- imports.wbg.__wbg_new_with_str_sequence_57a88eb77393f23f = function() {
5150
- return handleError(function(arg0, arg1, arg2) {
5151
- const ret = new WebSocket(getStringFromWasm0(arg0, arg1), getObject(arg2));
5152
- return addHeapObject(ret);
5153
- }, arguments);
5154
- };
5155
- imports.wbg.__wbg_next_020810e0ae8ebcb0 = function() {
5156
- return handleError(function(arg0) {
5157
- const ret = getObject(arg0).next();
5158
- return addHeapObject(ret);
5159
- }, arguments);
5160
- };
5161
- imports.wbg.__wbg_next_2c826fe5dfec6b6a = function(arg0) {
5162
- const ret = getObject(arg0).next;
5163
- return addHeapObject(ret);
5164
- };
5165
- imports.wbg.__wbg_node_905d3e251edff8a2 = function(arg0) {
5166
- const ret = getObject(arg0).node;
5167
- return addHeapObject(ret);
5168
- };
5169
- imports.wbg.__wbg_now_2c95c9de01293173 = function(arg0) {
5170
- const ret = getObject(arg0).now();
5171
- return ret;
5172
- };
5173
- imports.wbg.__wbg_now_793306c526e2e3b6 = function() {
5174
- const ret = Date.now();
5175
- return ret;
5176
- };
5177
- imports.wbg.__wbg_performance_7a3ffd0b17f663ad = function(arg0) {
5178
- const ret = getObject(arg0).performance;
5179
- return addHeapObject(ret);
5180
- };
5181
- imports.wbg.__wbg_process_dc0fbacc7c1c06f7 = function(arg0) {
5182
- const ret = getObject(arg0).process;
5183
- return addHeapObject(ret);
5184
- };
5185
- imports.wbg.__wbg_prototypesetcall_2a6620b6922694b2 = function(arg0, arg1, arg2) {
5186
- Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), getObject(arg2));
5187
- };
5188
- imports.wbg.__wbg_push_df81a39d04db858c = function(arg0, arg1) {
5189
- const ret = getObject(arg0).push(getObject(arg1));
5190
- return ret;
5191
- };
5192
- imports.wbg.__wbg_queueMicrotask_34d692c25c47d05b = function(arg0) {
5193
- const ret = getObject(arg0).queueMicrotask;
5194
- return addHeapObject(ret);
5195
- };
5196
- imports.wbg.__wbg_queueMicrotask_9d76cacb20c84d58 = function(arg0) {
5197
- queueMicrotask(getObject(arg0));
5198
- };
5199
- imports.wbg.__wbg_randomFillSync_ac0988aba3254290 = function() {
5200
- return handleError(function(arg0, arg1) {
5201
- getObject(arg0).randomFillSync(takeObject(arg1));
5202
- }, arguments);
5203
- };
5204
- imports.wbg.__wbg_read_48f1593df542f968 = function(arg0) {
5205
- const ret = getObject(arg0).read();
5206
- return addHeapObject(ret);
5207
- };
5208
- imports.wbg.__wbg_readyState_97984f126080aeda = function(arg0) {
5209
- const ret = getObject(arg0).readyState;
5210
- return ret;
5211
- };
5212
- imports.wbg.__wbg_reason_1cced37e3a93763e = function(arg0, arg1) {
5213
- const ret = getObject(arg1).reason;
5214
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
5215
- const len1 = WASM_VECTOR_LEN;
5216
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
5217
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
5218
- };
5219
- imports.wbg.__wbg_releaseLock_5d0b5a68887b891d = function(arg0) {
5220
- getObject(arg0).releaseLock();
5221
- };
5222
- imports.wbg.__wbg_removeEventListener_924d9db66a4f775d = function() {
5223
- return handleError(function(arg0, arg1, arg2, arg3) {
5224
- getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3));
5225
- }, arguments);
5226
- };
5227
- imports.wbg.__wbg_require_60cc747a6bc5215a = function() {
5228
- return handleError(function() {
5229
- const ret = module.require;
5230
- return addHeapObject(ret);
5231
- }, arguments);
5232
- };
5233
- imports.wbg.__wbg_resolve_caf97c30b83f7053 = function(arg0) {
5234
- const ret = Promise.resolve(getObject(arg0));
5235
- return addHeapObject(ret);
5236
- };
5237
- imports.wbg.__wbg_respond_0f4dbf5386f5c73e = function() {
5238
- return handleError(function(arg0, arg1) {
5239
- getObject(arg0).respond(arg1 >>> 0);
5240
- }, arguments);
5241
- };
5242
- imports.wbg.__wbg_send_171576d2f7487517 = function() {
5243
- return handleError(function(arg0, arg1, arg2) {
5244
- getObject(arg0).send(getStringFromWasm0(arg1, arg2));
5245
- }, arguments);
5246
- };
5247
- imports.wbg.__wbg_send_3d2cf376613294f0 = function() {
5248
- return handleError(function(arg0, arg1, arg2) {
5249
- getObject(arg0).send(getArrayU8FromWasm0(arg1, arg2));
5250
- }, arguments);
5251
- };
5252
- imports.wbg.__wbg_setTimeout_4eb823e8b72fbe79 = function() {
5253
- return handleError(function(arg0, arg1, arg2) {
5254
- const ret = getObject(arg0).setTimeout(takeObject(arg1), arg2);
5255
- return addHeapObject(ret);
5256
- }, arguments);
5257
- };
5258
- imports.wbg.__wbg_setTimeout_7bb3429662ab1e70 = function(arg0, arg1) {
5259
- const ret = setTimeout(getObject(arg0), arg1);
5260
- return addHeapObject(ret);
5261
- };
5262
- imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
5263
- getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
5264
- };
5265
- imports.wbg.__wbg_set_9e6516df7b7d0f19 = function(arg0, arg1, arg2) {
5266
- getObject(arg0).set(getArrayU8FromWasm0(arg1, arg2));
5267
- };
5268
- imports.wbg.__wbg_set_binaryType_9d839cea8fcdc5c3 = function(arg0, arg1) {
5269
- getObject(arg0).binaryType = __wbindgen_enum_BinaryType[arg1];
5270
- };
5271
- imports.wbg.__wbg_set_body_3c365989753d61f4 = function(arg0, arg1) {
5272
- getObject(arg0).body = getObject(arg1);
5273
- };
5274
- imports.wbg.__wbg_set_cache_2f9deb19b92b81e3 = function(arg0, arg1) {
5275
- getObject(arg0).cache = __wbindgen_enum_RequestCache[arg1];
5276
- };
5277
- imports.wbg.__wbg_set_credentials_f621cd2d85c0c228 = function(arg0, arg1) {
5278
- getObject(arg0).credentials = __wbindgen_enum_RequestCredentials[arg1];
5279
- };
5280
- imports.wbg.__wbg_set_handle_event_b2de49ad6c81e3c8 = function(arg0, arg1) {
5281
- getObject(arg0).handleEvent = getObject(arg1);
5282
- };
5283
- imports.wbg.__wbg_set_headers_6926da238cd32ee4 = function(arg0, arg1) {
5284
- getObject(arg0).headers = getObject(arg1);
5285
- };
5286
- imports.wbg.__wbg_set_method_c02d8cbbe204ac2d = function(arg0, arg1, arg2) {
5287
- getObject(arg0).method = getStringFromWasm0(arg1, arg2);
5288
- };
5289
- imports.wbg.__wbg_set_mode_52ef73cfa79639cb = function(arg0, arg1) {
5290
- getObject(arg0).mode = __wbindgen_enum_RequestMode[arg1];
5291
- };
5292
- imports.wbg.__wbg_set_onclose_c09e4f7422de8dae = function(arg0, arg1) {
5293
- getObject(arg0).onclose = getObject(arg1);
5294
- };
5295
- imports.wbg.__wbg_set_onerror_337a3a2db9517378 = function(arg0, arg1) {
5296
- getObject(arg0).onerror = getObject(arg1);
5297
- };
5298
- imports.wbg.__wbg_set_onmessage_8661558551a89792 = function(arg0, arg1) {
5299
- getObject(arg0).onmessage = getObject(arg1);
5300
- };
5301
- imports.wbg.__wbg_set_onopen_efccb9305427b907 = function(arg0, arg1) {
5302
- getObject(arg0).onopen = getObject(arg1);
5303
- };
5304
- imports.wbg.__wbg_set_signal_dda2cf7ccb6bee0f = function(arg0, arg1) {
5305
- getObject(arg0).signal = getObject(arg1);
5306
- };
5307
- imports.wbg.__wbg_signal_4db5aa055bf9eb9a = function(arg0) {
5308
- const ret = getObject(arg0).signal;
5309
- return addHeapObject(ret);
5310
- };
5311
- imports.wbg.__wbg_static_accessor_GLOBAL_89e1d9ac6a1b250e = function() {
5312
- const ret = typeof global === "undefined" ? null : global;
5313
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
5314
- };
5315
- imports.wbg.__wbg_static_accessor_GLOBAL_THIS_8b530f326a9e48ac = function() {
5316
- const ret = typeof globalThis === "undefined" ? null : globalThis;
5317
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
5318
- };
5319
- imports.wbg.__wbg_static_accessor_SELF_6fdf4b64710cc91b = function() {
5320
- const ret = typeof self === "undefined" ? null : self;
5321
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
5322
- };
5323
- imports.wbg.__wbg_static_accessor_WINDOW_b45bfc5a37f6cfa2 = function() {
5324
- const ret = typeof window === "undefined" ? null : window;
5325
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
5326
- };
5327
- imports.wbg.__wbg_status_de7eed5a7a5bfd5d = function(arg0) {
5328
- const ret = getObject(arg0).status;
5329
- return ret;
5330
- };
5331
- imports.wbg.__wbg_stringify_b5fb28f6465d9c3e = function() {
5332
- return handleError(function(arg0) {
5333
- const ret = JSON.stringify(getObject(arg0));
5334
- return addHeapObject(ret);
5335
- }, arguments);
5336
- };
5337
- imports.wbg.__wbg_subarray_480600f3d6a9f26c = function(arg0, arg1, arg2) {
5338
- const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
5339
- return addHeapObject(ret);
5340
- };
5341
- imports.wbg.__wbg_then_4f46f6544e6b4a28 = function(arg0, arg1) {
5342
- const ret = getObject(arg0).then(getObject(arg1));
5343
- return addHeapObject(ret);
5344
- };
5345
- imports.wbg.__wbg_then_70d05cf780a18d77 = function(arg0, arg1, arg2) {
5346
- const ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
5347
- return addHeapObject(ret);
5348
- };
5349
- imports.wbg.__wbg_url_9bd0af1cd8643de7 = function(arg0, arg1) {
5350
- const ret = getObject(arg1).url;
5351
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
5352
- const len1 = WASM_VECTOR_LEN;
5353
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
5354
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
5355
- };
5356
- imports.wbg.__wbg_url_b36d2a5008eb056f = function(arg0, arg1) {
5357
- const ret = getObject(arg1).url;
5358
- const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
5359
- const len1 = WASM_VECTOR_LEN;
5360
- getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
5361
- getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
5362
- };
5363
- imports.wbg.__wbg_value_692627309814bb8c = function(arg0) {
5364
- const ret = getObject(arg0).value;
5365
- return addHeapObject(ret);
5366
- };
5367
- imports.wbg.__wbg_versions_c01dfd4722a88165 = function(arg0) {
5368
- const ret = getObject(arg0).versions;
5369
- return addHeapObject(ret);
5370
- };
5371
- imports.wbg.__wbg_view_f6c15ac9fed63bbd = function(arg0) {
5372
- const ret = getObject(arg0).view;
5373
- return isLikeNone(ret) ? 0 : addHeapObject(ret);
5374
- };
5375
- imports.wbg.__wbg_wasClean_3d7c0cf05bd0a123 = function(arg0) {
5376
- const ret = getObject(arg0).wasClean;
5377
- return ret;
5378
- };
5379
- imports.wbg.__wbindgen_cast_0b4723bb5ff7475b = function(arg0, arg1) {
5380
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_11664, __wasm_bindgen_func_elem_11688);
5381
- return addHeapObject(ret);
5382
- };
5383
- imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) {
5384
- const ret = getStringFromWasm0(arg0, arg1);
5385
- return addHeapObject(ret);
5386
- };
5387
- imports.wbg.__wbindgen_cast_253c73f2760a05aa = function(arg0, arg1) {
5388
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_6219, __wasm_bindgen_func_elem_6230);
5389
- return addHeapObject(ret);
5390
- };
5391
- imports.wbg.__wbindgen_cast_343835dd8f264af2 = function(arg0, arg1) {
5392
- const ret = makeClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_5735, __wasm_bindgen_func_elem_5748);
5393
- return addHeapObject(ret);
5394
- };
5395
- imports.wbg.__wbindgen_cast_7bacc9fa7d2c65f4 = function(arg0, arg1) {
5396
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_12841, __wasm_bindgen_func_elem_12858);
5397
- return addHeapObject(ret);
5398
- };
5399
- imports.wbg.__wbindgen_cast_88fdcfb6b716b7f8 = function(arg0, arg1) {
5400
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_12896, __wasm_bindgen_func_elem_12912);
5401
- return addHeapObject(ret);
5402
- };
5403
- imports.wbg.__wbindgen_cast_c43a1cf1b94f2e7c = function(arg0, arg1) {
5404
- const ret = makeMutClosure(arg0, arg1, wasm.__wasm_bindgen_func_elem_2083, __wasm_bindgen_func_elem_2287);
5405
- return addHeapObject(ret);
5406
- };
5407
- imports.wbg.__wbindgen_cast_cb9088102bce6b30 = function(arg0, arg1) {
5408
- const ret = getArrayU8FromWasm0(arg0, arg1);
5409
- return addHeapObject(ret);
5410
- };
5411
- imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
5412
- const ret = arg0;
5413
- return addHeapObject(ret);
5414
- };
5415
- imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
5416
- const ret = getObject(arg0);
5417
- return addHeapObject(ret);
5418
- };
5419
- imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
5420
- takeObject(arg0);
5421
- };
5422
- return imports;
5423
- }
5424
- function __wbg_finalize_init(instance, module2) {
5425
- wasm = instance.exports;
5426
- __wbg_init.__wbindgen_wasm_module = module2;
5427
- cachedDataViewMemory0 = null;
5428
- cachedUint8ArrayMemory0 = null;
5429
- return wasm;
5430
- }
5431
- async function __wbg_init(module_or_path) {
5432
- if (wasm !== void 0) return wasm;
5433
- if (typeof module_or_path !== "undefined") {
5434
- if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
5435
- ({ module_or_path } = module_or_path);
5436
- } else {
5437
- console.warn("using deprecated parameters for the initialization function; pass a single object instead");
5438
- }
5439
- }
5440
- if (typeof module_or_path === "undefined") {
5441
- module_or_path = "/ermis_call_node_wasm_bg.wasm";
5442
- }
5443
- const imports = __wbg_get_imports();
5444
- if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) {
5445
- module_or_path = fetch(module_or_path);
5446
- }
5447
- const { instance, module: module2 } = await __wbg_load(await module_or_path, imports);
5448
- return __wbg_finalize_init(instance, module2);
5449
- }
5450
- var ermis_call_node_wasm_default = __wbg_init;
5451
-
5452
- // src/media_stream_sender.ts
5453
- var MediaStreamSender = class {
5454
- videoEncoder = null;
5455
- audioEncoder = null;
5456
- videoReader = null;
5457
- localStream = null;
5458
- videoConfig = null;
5459
- audioConfig = null;
5460
- videoConfigSent = false;
5461
- audioConfigSent = false;
5462
- hasVideo = false;
5463
- hasAudio = false;
5464
- forceKeyFrame = false;
5465
- nodeCall;
5466
- constructor(nodeCall) {
5467
- this.nodeCall = nodeCall;
5468
- }
5469
- /**
5470
- * Bắt đầu xử lý MediaStream
5471
- */
5472
- async connect(address) {
5473
- try {
5474
- await this.nodeCall.connect(address);
5475
- await this.sendConnected();
5476
- await this.sendConfigs();
5477
- } catch (error) {
5478
- console.error("Error starting MediaStreamSender:", error);
5479
- }
5480
- }
5481
- async sendConfigs() {
5482
- try {
5483
- await this.sendTransceiverState(this.hasAudio, this.hasVideo);
5484
- await this.sendAudioConfig();
5485
- const videoTrack = this.localStream?.getVideoTracks()[0];
5486
- if (videoTrack) {
5487
- await this.sendVideoConfig();
5488
- }
5489
- } catch (error) {
5490
- console.error("Error sending configs:", error);
5491
- }
5492
- }
5493
- /**
5494
- * Dừng và reset encoders
5495
- */
5496
- stop = () => {
5497
4448
  if (this.videoReader) {
5498
4449
  try {
5499
4450
  this.videoReader.cancel("Stream stopped").catch(() => {
@@ -5522,6 +4473,14 @@ var MediaStreamSender = class {
5522
4473
  }
5523
4474
  this.audioEncoder = null;
5524
4475
  }
4476
+ if (this.audioReader) {
4477
+ try {
4478
+ this.audioReader.cancel("Stream stopped").catch(() => {
4479
+ });
4480
+ } catch (e) {
4481
+ }
4482
+ this.audioReader = null;
4483
+ }
5525
4484
  this.videoConfig = null;
5526
4485
  this.audioConfig = null;
5527
4486
  this.videoConfigSent = false;
@@ -5550,22 +4509,29 @@ var MediaStreamSender = class {
5550
4509
  numberOfChannels: metadata.decoderConfig.numberOfChannels ?? 1,
5551
4510
  ...description && { description }
5552
4511
  };
4512
+ this.sendAudioConfig();
5553
4513
  }
5554
4514
  if (chunk && this.isReadyToSendData("audio")) {
4515
+ if (this.isSendingAudio) return;
4516
+ this.isSendingAudio = true;
5555
4517
  const data = new ArrayBuffer(chunk.byteLength);
5556
4518
  chunk.copyTo(data);
5557
4519
  const timestamp = chunk.timestamp;
5558
4520
  const packet = createPacketWithHeader(data, timestamp, "audio", null);
5559
- this.sendPacketOrQueue(packet, "audio", null);
4521
+ this.sendPacketOrQueue(packet, "audio", null).finally(() => {
4522
+ this.isSendingAudio = false;
4523
+ });
5560
4524
  }
5561
4525
  },
5562
4526
  error: (e) => console.error("AudioEncoder error:", e)
5563
4527
  });
5564
4528
  audioEncoder.configure({
5565
4529
  codec: "mp4a.40.2",
4530
+ // codec: 'opus',
5566
4531
  sampleRate: 48e3,
5567
4532
  numberOfChannels: 1,
5568
4533
  bitrate: 128e3
4534
+ // bitrate: 64000,
5569
4535
  });
5570
4536
  this.audioEncoder = audioEncoder;
5571
4537
  this.processAudioFrames(audioTrack);
@@ -5597,12 +4563,16 @@ var MediaStreamSender = class {
5597
4563
  await this.sendVideoConfig();
5598
4564
  }
5599
4565
  if (chunk && this.isReadyToSendData("video")) {
4566
+ if (this.isSendingVideo) return;
4567
+ this.isSendingVideo = true;
5600
4568
  const data = new ArrayBuffer(chunk.byteLength);
5601
4569
  chunk.copyTo(data);
5602
4570
  const frameType = chunk.type === "key" ? "video-key" : "video-delta";
5603
4571
  const timestamp = chunk.timestamp;
5604
4572
  const packet = createPacketWithHeader(data, timestamp, frameType, null);
5605
- this.sendPacketOrQueue(packet, "video", frameType);
4573
+ this.sendPacketOrQueue(packet, "video", frameType).finally(() => {
4574
+ this.isSendingVideo = false;
4575
+ });
5606
4576
  }
5607
4577
  },
5608
4578
  error: (e) => console.error("VideoEncoder error:", e)
@@ -5650,6 +4620,13 @@ var MediaStreamSender = class {
5650
4620
  }
5651
4621
  }
5652
4622
  async replaceAudioTrack(track) {
4623
+ if (this.audioReader) {
4624
+ try {
4625
+ await this.audioReader.cancel("Replacing audio track");
4626
+ } catch (e) {
4627
+ }
4628
+ this.audioReader = null;
4629
+ }
5653
4630
  if (track) {
5654
4631
  this.processAudioFrames(track);
5655
4632
  }
@@ -5704,10 +4681,11 @@ var MediaStreamSender = class {
5704
4681
  };
5705
4682
  processAudioFrames = async (audioTrack) => {
5706
4683
  const audioProcessor = new MediaStreamTrackProcessor({ track: audioTrack });
5707
- const audioReader = audioProcessor.readable.getReader();
4684
+ this.audioReader = audioProcessor.readable.getReader();
5708
4685
  try {
5709
4686
  while (true) {
5710
- const { done, value: frame } = await audioReader.read();
4687
+ if (!this.audioReader) break;
4688
+ const { done, value: frame } = await this.audioReader.read();
5711
4689
  if (done) break;
5712
4690
  if (!this.audioEncoder) {
5713
4691
  frame?.close();
@@ -5725,6 +4703,13 @@ var MediaStreamSender = class {
5725
4703
  }
5726
4704
  } catch (error) {
5727
4705
  console.error(`Error processing audio frames: ${error.message}`);
4706
+ } finally {
4707
+ if (this.audioReader) {
4708
+ try {
4709
+ this.audioReader.releaseLock();
4710
+ } catch (e) {
4711
+ }
4712
+ }
5728
4713
  }
5729
4714
  };
5730
4715
  isReadyToSendData = (type) => {
@@ -5764,6 +4749,22 @@ var MediaStreamSender = class {
5764
4749
  const configPacket = createPacketWithHeader(null, null, "connected", null);
5765
4750
  await this.nodeCall.sendControlFrame(configPacket);
5766
4751
  };
4752
+ startHealthCallInterval = () => {
4753
+ if (this.healthCallInterval) {
4754
+ clearInterval(this.healthCallInterval);
4755
+ }
4756
+ this.healthCallInterval = setInterval(() => {
4757
+ this.sendHealthCall().catch(() => {
4758
+ });
4759
+ }, 5e3);
4760
+ };
4761
+ sendHealthCall = async () => {
4762
+ try {
4763
+ const packet = createPacketWithHeader(null, null, "healthCall", null);
4764
+ await this.nodeCall.sendControlFrame(packet);
4765
+ } catch (e) {
4766
+ }
4767
+ };
5767
4768
  sendPacketOrQueue = async (packet, type, frameType) => {
5768
4769
  if (!this.isReadyToSendData(type)) {
5769
4770
  return;
@@ -5989,8 +4990,8 @@ var HEVCDecoderConfigurationRecord = class _HEVCDecoderConfigurationRecord {
5989
4990
  };
5990
4991
 
5991
4992
  // src/media_stream_receiver.ts
5992
- var MAX_AUDIO_LATENCY = 0.1;
5993
- var MIN_BUFFER_AHEAD = 0.02;
4993
+ var MAX_AUDIO_LATENCY = 0.5;
4994
+ var MIN_BUFFER_AHEAD = 0.05;
5994
4995
  var MediaStreamReceiver = class {
5995
4996
  videoDecoder = null;
5996
4997
  audioDecoder = null;
@@ -5998,9 +4999,12 @@ var MediaStreamReceiver = class {
5998
4999
  videoWriter = null;
5999
5000
  audioContext = null;
6000
5001
  mediaDestination = null;
5002
+ scheduledAudioNodes = [];
6001
5003
  isWaitingForKeyFrame = true;
6002
5004
  nextStartTime = 0;
6003
5005
  lastVideoConfig = null;
5006
+ lastVideoConfigStr = "";
5007
+ lastAudioConfigStr = "";
6004
5008
  nodeCall;
6005
5009
  events;
6006
5010
  generatedStream = null;
@@ -6086,14 +5090,17 @@ var MediaStreamReceiver = class {
6086
5090
  console.error("\u274C VideoDecoder CRASHED:", err);
6087
5091
  this.isWaitingForKeyFrame = true;
6088
5092
  if (this.videoWriter) {
6089
- console.log("\u267B\uFE0F Attempting to respawn VideoDecoder...");
6090
- this.setupVideoDecoder();
6091
- if (this.lastVideoConfig && this.videoDecoder) {
6092
- try {
6093
- this.videoDecoder.configure(this.lastVideoConfig);
6094
- } catch (configErr) {
5093
+ console.log("\u267B\uFE0F Scheduled VideoDecoder respawn in 1000ms...");
5094
+ setTimeout(() => {
5095
+ if (!this.videoWriter) return;
5096
+ this.setupVideoDecoder();
5097
+ if (this.lastVideoConfig && this.videoDecoder) {
5098
+ try {
5099
+ this.videoDecoder.configure(this.lastVideoConfig);
5100
+ } catch (configErr) {
5101
+ }
6095
5102
  }
6096
- }
5103
+ }, 1e3);
6097
5104
  }
6098
5105
  }
6099
5106
  });
@@ -6109,21 +5116,38 @@ var MediaStreamReceiver = class {
6109
5116
  const duration = numberOfFrames / sampleRate;
6110
5117
  const currentTime = this.audioContext.currentTime;
6111
5118
  if (this.nextStartTime < currentTime) {
6112
- this.nextStartTime = currentTime;
5119
+ this.nextStartTime = currentTime + MIN_BUFFER_AHEAD;
6113
5120
  } else if (this.nextStartTime > currentTime + MAX_AUDIO_LATENCY) {
6114
5121
  this.nextStartTime = currentTime + MIN_BUFFER_AHEAD;
5122
+ this.scheduledAudioNodes.forEach((node) => {
5123
+ try {
5124
+ node.stop();
5125
+ } catch (e) {
5126
+ }
5127
+ });
5128
+ this.scheduledAudioNodes = [];
6115
5129
  }
6116
5130
  const audioBuffer = this.audioContext.createBuffer(numberOfChannels, numberOfFrames, sampleRate);
6117
- const size = numberOfChannels * numberOfFrames;
6118
- const tempBuffer = new Float32Array(size);
6119
- audioData.copyTo(tempBuffer, { planeIndex: 0, format: "f32-planar" });
6120
5131
  for (let ch = 0; ch < numberOfChannels; ch++) {
6121
- const channelData = tempBuffer.subarray(ch * numberOfFrames, (ch + 1) * numberOfFrames);
5132
+ const channelData = new Float32Array(numberOfFrames);
5133
+ audioData.copyTo(channelData, { planeIndex: ch, format: "f32-planar" });
6122
5134
  audioBuffer.copyToChannel(channelData, ch);
6123
5135
  }
6124
5136
  const source = this.audioContext.createBufferSource();
6125
5137
  source.buffer = audioBuffer;
6126
5138
  source.connect(this.mediaDestination);
5139
+ this.scheduledAudioNodes.push(source);
5140
+ if (this.scheduledAudioNodes.length > 100) {
5141
+ const oldestNode = this.scheduledAudioNodes.shift();
5142
+ try {
5143
+ oldestNode?.stop();
5144
+ oldestNode?.disconnect();
5145
+ } catch (e) {
5146
+ }
5147
+ }
5148
+ source.onended = () => {
5149
+ this.scheduledAudioNodes = this.scheduledAudioNodes.filter((n) => n !== source);
5150
+ };
6127
5151
  source.start(this.nextStartTime);
6128
5152
  this.nextStartTime += duration;
6129
5153
  audioData.close();
@@ -6144,7 +5168,12 @@ var MediaStreamReceiver = class {
6144
5168
  // Vòng lặp chính xử lý dữ liệu
6145
5169
  receiveLoop = async () => {
6146
5170
  const textDecoder = new TextDecoder();
5171
+ let lastYieldTime = Date.now();
6147
5172
  while (true) {
5173
+ if (Date.now() - lastYieldTime > 16) {
5174
+ await new Promise((resolve) => setTimeout(resolve, 0));
5175
+ lastYieldTime = Date.now();
5176
+ }
6148
5177
  try {
6149
5178
  if (!this.nodeCall) break;
6150
5179
  const data = await this.nodeCall.asyncRecv();
@@ -6158,7 +5187,8 @@ var MediaStreamReceiver = class {
6158
5187
  5 /* ORIENTATION */,
6159
5188
  8 /* REQUEST_CONFIG */,
6160
5189
  9 /* REQUEST_KEY_FRAME */,
6161
- 10 /* END_CALL */
5190
+ 10 /* END_CALL */,
5191
+ 11 /* HEALTH_CALL */
6162
5192
  ].includes(frameType) ? 1 : 9;
6163
5193
  const payload = new Uint8Array(data.buffer, data.byteOffset + payloadOffset, data.byteLength - payloadOffset);
6164
5194
  switch (frameType) {
@@ -6166,8 +5196,12 @@ var MediaStreamReceiver = class {
6166
5196
  case 0 /* VIDEO_CONFIG */: {
6167
5197
  try {
6168
5198
  const videoConfigStr = textDecoder.decode(payload);
5199
+ if (this.lastVideoConfigStr === videoConfigStr && this.videoDecoder?.state === "configured") {
5200
+ break;
5201
+ }
5202
+ this.lastVideoConfigStr = videoConfigStr;
6169
5203
  const videoConfig = JSON.parse(videoConfigStr);
6170
- console.log("--videoConfig--", videoConfig);
5204
+ console.log("videoConfig", videoConfig);
6171
5205
  if (!this.videoWriter) {
6172
5206
  const videoTrackGenerator = new MediaStreamTrackGenerator({ kind: "video" });
6173
5207
  this.videoWriter = videoTrackGenerator.writable.getWriter();
@@ -6220,14 +5254,23 @@ var MediaStreamReceiver = class {
6220
5254
  }
6221
5255
  // --- AUDIO CONFIG ---
6222
5256
  case 1 /* AUDIO_CONFIG */: {
6223
- const audioConfig = JSON.parse(textDecoder.decode(payload));
6224
- console.log("--audioConfig--", audioConfig);
6225
- if (this.audioDecoder?.state !== "closed") {
6226
- this.audioDecoder?.configure({
6227
- codec: audioConfig.codec,
6228
- sampleRate: audioConfig.sampleRate,
6229
- numberOfChannels: audioConfig.numberOfChannels
6230
- });
5257
+ try {
5258
+ const audioConfigStr = textDecoder.decode(payload);
5259
+ if (this.lastAudioConfigStr === audioConfigStr && this.audioDecoder?.state === "configured") {
5260
+ break;
5261
+ }
5262
+ this.lastAudioConfigStr = audioConfigStr;
5263
+ const audioConfig = JSON.parse(audioConfigStr);
5264
+ console.log("audioConfig", audioConfig);
5265
+ if (this.audioDecoder?.state !== "closed") {
5266
+ this.audioDecoder?.configure({
5267
+ codec: audioConfig.codec,
5268
+ sampleRate: audioConfig.sampleRate,
5269
+ numberOfChannels: audioConfig.numberOfChannels
5270
+ });
5271
+ }
5272
+ } catch (e) {
5273
+ console.error("\u274C Error processing AUDIO_CONFIG:", e);
6231
5274
  }
6232
5275
  break;
6233
5276
  }
@@ -6238,11 +5281,9 @@ var MediaStreamReceiver = class {
6238
5281
  const isKeyFrame = frameType === 2 /* VIDEO_KEY */;
6239
5282
  if (this.isWaitingForKeyFrame) {
6240
5283
  if (!isKeyFrame) break;
6241
- console.log("\u2705 Resumed decoding at KeyFrame");
6242
5284
  this.isWaitingForKeyFrame = false;
6243
5285
  }
6244
- if (!isKeyFrame && this.videoDecoder.decodeQueueSize > 15) {
6245
- console.warn("\u26A0\uFE0F Queue > 15. Dropping & Waiting for KeyFrame...");
5286
+ if (!isKeyFrame && this.videoDecoder.decodeQueueSize > 5) {
6246
5287
  this.isWaitingForKeyFrame = true;
6247
5288
  break;
6248
5289
  }
@@ -6322,12 +5363,12 @@ var MediaStreamReceiver = class {
6322
5363
  this.events.onEndCall();
6323
5364
  }
6324
5365
  break;
5366
+ case 11 /* HEALTH_CALL */:
5367
+ break;
6325
5368
  default:
6326
- console.warn("\u2753 Unknown frame type received:", frameType);
6327
5369
  break;
6328
5370
  }
6329
5371
  } catch (error) {
6330
- console.error("Stream loop error", error);
6331
5372
  await new Promise((r) => setTimeout(r, 200));
6332
5373
  }
6333
5374
  }
@@ -6371,6 +5412,13 @@ var MediaStreamReceiver = class {
6371
5412
  }
6372
5413
  this.audioContext = null;
6373
5414
  }
5415
+ this.scheduledAudioNodes.forEach((node) => {
5416
+ try {
5417
+ node.stop();
5418
+ } catch (e) {
5419
+ }
5420
+ });
5421
+ this.scheduledAudioNodes = [];
6374
5422
  this.isWaitingForKeyFrame = true;
6375
5423
  this.mediaDestination = null;
6376
5424
  this.nextStartTime = 0;
@@ -6385,6 +5433,7 @@ var MediaStreamReceiver = class {
6385
5433
  // src/ermis_call_node.ts
6386
5434
  var ErmisCallNode = class {
6387
5435
  wasmPath;
5436
+ workerPath;
6388
5437
  relayUrl = "https://test-iroh.ermis.network.:8443";
6389
5438
  /** Reference to the Ermis Chat client instance */
6390
5439
  _client;
@@ -6394,8 +5443,10 @@ var ErmisCallNode = class {
6394
5443
  cid;
6395
5444
  /** Type of call: 'audio' or 'video' */
6396
5445
  callType;
6397
- /** ID of the current user */
6398
- userID;
5446
+ /** ID of the current user — always reads live value from client */
5447
+ get userID() {
5448
+ return this._client?.userID;
5449
+ }
6399
5450
  /** Current status of the call */
6400
5451
  callStatus = "";
6401
5452
  metadata;
@@ -6461,34 +5512,37 @@ var ErmisCallNode = class {
6461
5512
  isDestroyed = false;
6462
5513
  mediaSender = null;
6463
5514
  mediaReceiver = null;
6464
- constructor(client, sessionID, wasmPath, relayUrl) {
5515
+ constructor(client, sessionID, wasmPath, relayUrl, workerPath) {
6465
5516
  this._client = client;
6466
5517
  this.cid = "";
6467
5518
  this.callType = "";
6468
5519
  this.sessionID = sessionID;
6469
- this.userID = client.userID;
6470
5520
  this.metadata = {};
6471
5521
  this.wasmPath = wasmPath;
6472
5522
  this.relayUrl = relayUrl;
5523
+ this.workerPath = workerPath || "/wasm_worker.worker.mjs";
6473
5524
  this.listenSocketEvents();
6474
5525
  this.setupDeviceChangeListener();
6475
5526
  this.loadWasm();
6476
5527
  }
6477
5528
  async loadWasm() {
6478
5529
  try {
6479
- await ermis_call_node_wasm_default(this.wasmPath);
5530
+ this.callNode = new WasmWorkerProxy(new URL(this.workerPath, window.location.origin));
5531
+ await this.callNode.init(this.wasmPath);
6480
5532
  } catch (error) {
6481
- console.error("Failed to load ErmisCall WASM module:", error);
5533
+ console.error("Failed to load ErmisCall WASM Worker:", error);
6482
5534
  throw error;
6483
5535
  }
6484
5536
  }
6485
5537
  async initialize() {
6486
5538
  try {
6487
- const node = new ErmisCall();
6488
- await node.spawn([this.relayUrl]);
6489
- this.callNode = node;
6490
- this.mediaSender = new MediaStreamSender(node);
6491
- this.mediaReceiver = new MediaStreamReceiver(node, {
5539
+ if (!this.callNode) {
5540
+ await this.loadWasm();
5541
+ }
5542
+ const proxy = this.callNode;
5543
+ await proxy.spawn([this.relayUrl]);
5544
+ this.mediaSender = new MediaStreamSender(proxy);
5545
+ this.mediaReceiver = new MediaStreamReceiver(proxy, {
6492
5546
  onConnected: () => {
6493
5547
  this.setCallStatus("connected" /* CONNECTED */);
6494
5548
  this.connectCall();
@@ -6523,7 +5577,8 @@ var ErmisCallNode = class {
6523
5577
  this.destroy();
6524
5578
  }
6525
5579
  });
6526
- return node;
5580
+ await proxy.startRecvLoop();
5581
+ return proxy;
6527
5582
  } catch (error) {
6528
5583
  console.error("Failed to initialize Ermis SDK:", error);
6529
5584
  throw error;
@@ -6566,13 +5621,13 @@ var ErmisCallNode = class {
6566
5621
  if (typeof this.onError === "function") {
6567
5622
  if (error.code === "ERR_NETWORK") {
6568
5623
  if (action === "create-call" /* CREATE_CALL */) {
6569
- this.onError("Unable to make the call. Please check your network connection");
5624
+ this.onError("call_network_error");
6570
5625
  }
6571
5626
  } else {
6572
5627
  if (error.response.data.ermis_code === 20) {
6573
- this.onError("Recipient was busy");
5628
+ this.onError("call_recipient_busy");
6574
5629
  } else {
6575
- const errMsg = error.response.data?.message ? error.response.data?.message : "Call failed";
5630
+ const errMsg = error.response.data?.message ? error.response.data?.message : "call_failed";
6576
5631
  this.onError(errMsg);
6577
5632
  }
6578
5633
  }
@@ -6639,7 +5694,7 @@ var ErmisCallNode = class {
6639
5694
  }
6640
5695
  }
6641
5696
  if (typeof this.onError === "function") {
6642
- this.onError("No microphone or camera found. Please check your device.");
5697
+ this.onError("call_no_devices");
6643
5698
  }
6644
5699
  return null;
6645
5700
  }
@@ -6670,20 +5725,25 @@ var ErmisCallNode = class {
6670
5725
  setUserInfo(cid, eventUserId) {
6671
5726
  if (!cid || !eventUserId) return;
6672
5727
  const channel = cid ? this.getClient().activeChannels[cid] : void 0;
6673
- const members = channel?.state?.members || {};
6674
- const memberIds = Object.keys(members);
5728
+ const stateMembers = channel?.state?.members || {};
5729
+ const memberIds = Object.keys(stateMembers);
6675
5730
  const callerId = eventUserId || "";
6676
5731
  const receiverId = memberIds.find((id) => id !== callerId) || "";
6677
- const callerUser = this.getClient().state.users[callerId];
6678
- const receiverUser = this.getClient().state.users[receiverId];
5732
+ const dataMembers = channel?.data?.members || [];
5733
+ const findUserFromDataMembers = (userId) => {
5734
+ const member = dataMembers.find((m) => m.user_id === userId || m.user?.id === userId);
5735
+ return member?.user;
5736
+ };
5737
+ const callerUser = findUserFromDataMembers(callerId) || stateMembers[callerId]?.user || this.getClient().state.users[callerId];
5738
+ const receiverUser = findUserFromDataMembers(receiverId) || stateMembers[receiverId]?.user || this.getClient().state.users[receiverId];
6679
5739
  this.callerInfo = {
6680
5740
  id: callerId,
6681
- name: callerUser?.name,
5741
+ name: callerUser?.name || callerId,
6682
5742
  avatar: callerUser?.avatar || ""
6683
5743
  };
6684
5744
  this.receiverInfo = {
6685
5745
  id: receiverId,
6686
- name: receiverUser?.name,
5746
+ name: receiverUser?.name || receiverId,
6687
5747
  avatar: receiverUser?.avatar || ""
6688
5748
  };
6689
5749
  }
@@ -6701,7 +5761,6 @@ var ErmisCallNode = class {
6701
5761
  this.callStatus = "";
6702
5762
  this.callType = is_video ? "video" : "audio";
6703
5763
  this.setUserInfo(cid, eventUserId);
6704
- this.setCallStatus("ringing" /* RINGING */);
6705
5764
  this.cid = cid || "";
6706
5765
  this.metadata = metadata || {};
6707
5766
  if (typeof this.onCallEvent === "function") {
@@ -6714,15 +5773,12 @@ var ErmisCallNode = class {
6714
5773
  metadata: this.metadata
6715
5774
  });
6716
5775
  }
5776
+ this.setCallStatus("ringing" /* RINGING */);
6717
5777
  await this.startLocalStream();
6718
5778
  if (this.callStatus === "ended" /* ENDED */) return;
6719
5779
  if (eventUserId !== this.userID) {
6720
5780
  await this.initialize();
6721
5781
  }
6722
- if (this.localStream && this.mediaSender && this.mediaReceiver) {
6723
- this.mediaSender?.initEncoders(this.localStream);
6724
- this.mediaReceiver?.initDecoders(this.callType);
6725
- }
6726
5782
  if (eventUserId === this.userID) {
6727
5783
  if (this.missCallTimeout) clearTimeout(this.missCallTimeout);
6728
5784
  this.missCallTimeout = setTimeout(async () => {
@@ -6740,6 +5796,12 @@ var ErmisCallNode = class {
6740
5796
  if (this.mediaReceiver && this.mediaSender) {
6741
5797
  await this.mediaReceiver.acceptConnection();
6742
5798
  await this.mediaSender.sendConnected();
5799
+ }
5800
+ if (this.localStream && this.mediaSender && this.mediaReceiver && this.callType) {
5801
+ this.mediaSender?.initEncoders(this.localStream);
5802
+ this.mediaReceiver?.initDecoders(this.callType);
5803
+ }
5804
+ if (this.mediaSender) {
6743
5805
  await this.mediaSender.sendConfigs();
6744
5806
  }
6745
5807
  }
@@ -6747,7 +5809,7 @@ var ErmisCallNode = class {
6747
5809
  case "end-call" /* END_CALL */:
6748
5810
  case "reject-call" /* REJECT_CALL */:
6749
5811
  case "miss-call" /* MISS_CALL */:
6750
- this.destroy();
5812
+ await this.destroy();
6751
5813
  break;
6752
5814
  }
6753
5815
  };
@@ -6793,7 +5855,7 @@ var ErmisCallNode = class {
6793
5855
  this._client.on("connection.changed", this.connectionChangedHandler);
6794
5856
  this._client.on("message.updated", this.messageUpdatedHandler);
6795
5857
  }
6796
- cleanupCall() {
5858
+ async cleanupCall() {
6797
5859
  if (this.mediaSender) {
6798
5860
  this.mediaSender?.stop();
6799
5861
  this.mediaSender = null;
@@ -6803,9 +5865,9 @@ var ErmisCallNode = class {
6803
5865
  this.mediaReceiver = null;
6804
5866
  }
6805
5867
  if (this.callNode) {
6806
- this.callNode?.closeEndpoint();
6807
- if (this.callStatus === "connected" /* CONNECTED */) {
6808
- this.callNode?.closeConnection();
5868
+ try {
5869
+ await Promise.race([this.callNode.terminate(), new Promise((resolve) => setTimeout(resolve, 1e3))]);
5870
+ } catch {
6809
5871
  }
6810
5872
  this.callNode = null;
6811
5873
  }
@@ -6843,8 +5905,8 @@ var ErmisCallNode = class {
6843
5905
  }
6844
5906
  this.setCallStatus("ended" /* ENDED */);
6845
5907
  }
6846
- destroy() {
6847
- this.cleanupCall();
5908
+ async destroy() {
5909
+ await this.cleanupCall();
6848
5910
  }
6849
5911
  async getDevices() {
6850
5912
  if (this.availableAudioDevices.length > 0 || this.availableVideoDevices.length > 0) {
@@ -6868,9 +5930,14 @@ var ErmisCallNode = class {
6868
5930
  videoDevice: this.availableVideoDevices[0]
6869
5931
  };
6870
5932
  }
5933
+ prefillUserInfo(cid) {
5934
+ this.setUserInfo(cid, this.userID);
5935
+ }
6871
5936
  async createCall(callType, cid) {
6872
5937
  try {
6873
5938
  this.cid = cid;
5939
+ this.callType = callType;
5940
+ this.prefillUserInfo(cid);
6874
5941
  const address = await this.getLocalEndpointAddr();
6875
5942
  await this._sendSignal({
6876
5943
  action: "create-call" /* CREATE_CALL */,
@@ -6890,6 +5957,13 @@ var ErmisCallNode = class {
6890
5957
  const address = this.metadata?.address || "";
6891
5958
  await this.mediaSender.connect(address);
6892
5959
  }
5960
+ if (this.localStream && this.mediaSender && this.mediaReceiver) {
5961
+ this.mediaSender?.initEncoders(this.localStream);
5962
+ this.mediaReceiver?.initDecoders(this.callType || "audio");
5963
+ }
5964
+ if (this.mediaSender) {
5965
+ await this.mediaSender.sendConfigs();
5966
+ }
6893
5967
  } catch (error) {
6894
5968
  console.error("Failed to accept call:", error);
6895
5969
  throw error;
@@ -7042,12 +6116,16 @@ var ErmisCallNode = class {
7042
6116
  }
7043
6117
  this.selectedAudioDeviceId = deviceId;
7044
6118
  if (!this.localStream) return false;
6119
+ const mediaConstraints = await this.getMediaConstraints();
7045
6120
  const newStream = await navigator.mediaDevices.getUserMedia({
7046
- audio: { deviceId: { exact: deviceId } },
6121
+ audio: mediaConstraints.audio,
7047
6122
  video: false
7048
6123
  });
7049
6124
  const newAudioTrack = newStream.getAudioTracks()[0];
7050
6125
  const oldAudioTrack = this.localStream.getAudioTracks()[0];
6126
+ if (this.mediaSender && newAudioTrack) {
6127
+ await this.mediaSender.replaceAudioTrack(newAudioTrack);
6128
+ }
7051
6129
  if (oldAudioTrack) {
7052
6130
  this.localStream.removeTrack(oldAudioTrack);
7053
6131
  oldAudioTrack.stop();
@@ -7078,12 +6156,16 @@ var ErmisCallNode = class {
7078
6156
  }
7079
6157
  this.selectedVideoDeviceId = deviceId;
7080
6158
  if (!this.localStream) return false;
6159
+ const mediaConstraints = await this.getMediaConstraints();
7081
6160
  const newStream = await navigator.mediaDevices.getUserMedia({
7082
6161
  audio: false,
7083
- video: { deviceId: { exact: deviceId } }
6162
+ video: mediaConstraints.video
7084
6163
  });
7085
6164
  const newVideoTrack = newStream.getVideoTracks()[0];
7086
6165
  const oldVideoTrack = this.localStream.getVideoTracks()[0];
6166
+ if (this.mediaSender && newVideoTrack) {
6167
+ await this.mediaSender.replaceVideoTrack(newVideoTrack);
6168
+ }
7087
6169
  if (oldVideoTrack) {
7088
6170
  this.localStream.removeTrack(oldVideoTrack);
7089
6171
  oldVideoTrack.stop();
@@ -7274,7 +6356,7 @@ var ErmisAuthProvider = class {
7274
6356
  return data;
7275
6357
  }
7276
6358
  getUserAgent() {
7277
- return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"1.0.9"}`;
6359
+ return this.userAgent || `ermis-chat-sdk-javascript-client-${this.node ? "node" : "browser"}-${"2.0.0"}`;
7278
6360
  }
7279
6361
  setUserAgent(userAgent) {
7280
6362
  this.userAgent = userAgent;
@@ -7419,88 +6501,155 @@ var ErmisAuthProvider = class {
7419
6501
  };
7420
6502
 
7421
6503
  // src/system_message.ts
7422
- var DURATION_MAP = {
7423
- "10000": "10 seconds",
7424
- "30000": "30 seconds",
7425
- "60000": "1 minute",
7426
- "300000": "5 minutes",
7427
- "900000": "15 minutes",
7428
- "3600000": "60 minutes"
7429
- };
7430
6504
  function resolveUser(userId, userMap) {
7431
6505
  return userMap[userId] ?? userId;
7432
6506
  }
7433
- function parseSystemMessage(value, userMap) {
6507
+ function parseSystemMessage(value, userMap, translations) {
7434
6508
  if (!value || typeof value !== "string") return value ?? "";
7435
6509
  const trimmed = value.trim();
7436
6510
  if (!trimmed) return "";
7437
6511
  const parts = trimmed.split(" ");
7438
6512
  const formatId = parts[0];
7439
6513
  const userId = parts[1] ?? "";
7440
- const userName = userId ? resolveUser(userId, userMap) : "User";
6514
+ const userName = userId ? resolveUser(userId, userMap) : translations?.userFallback ?? "User";
7441
6515
  switch (formatId) {
7442
6516
  // 1: userName changed the channel name to channelName (may contain spaces)
7443
6517
  case "1": {
7444
6518
  const channelName = parts.slice(2).join(" ");
6519
+ const template = translations?.["1"] ?? translations?.changeName;
6520
+ if (template) {
6521
+ return template.replace("{{user}}", userName).replace("{{channel}}", channelName);
6522
+ }
7445
6523
  return `${userName} changed the channel name to ${channelName}.`;
7446
6524
  }
7447
6525
  // 2–13, 16–17: single-user actions
7448
- case "2":
6526
+ case "2": {
6527
+ const template = translations?.["2"] ?? translations?.changeAvatar;
6528
+ if (template) return template.replace("{{user}}", userName);
7449
6529
  return `${userName} changed the channel avatar.`;
7450
- case "3":
6530
+ }
6531
+ case "3": {
6532
+ const template = translations?.["3"] ?? translations?.changeDescription;
6533
+ if (template) return template.replace("{{user}}", userName);
7451
6534
  return `${userName} changed the channel description.`;
7452
- case "4":
6535
+ }
6536
+ case "4": {
6537
+ const template = translations?.["4"] ?? translations?.removed;
6538
+ if (template) return template.replace("{{user}}", userName);
7453
6539
  return `${userName} was removed from the channel.`;
7454
- case "5":
6540
+ }
6541
+ case "5": {
6542
+ const template = translations?.["5"] ?? translations?.banned;
6543
+ if (template) return template.replace("{{user}}", userName);
7455
6544
  return `${userName} was banned.`;
7456
- case "6":
6545
+ }
6546
+ case "6": {
6547
+ const template = translations?.["6"] ?? translations?.unbanned;
6548
+ if (template) return template.replace("{{user}}", userName);
7457
6549
  return `${userName} was unbanned.`;
7458
- case "7":
6550
+ }
6551
+ case "7": {
6552
+ const template = translations?.["7"] ?? translations?.promoted;
6553
+ if (template) return template.replace("{{user}}", userName);
7459
6554
  return `${userName} was promoted to moderator.`;
7460
- case "8":
6555
+ }
6556
+ case "8": {
6557
+ const template = translations?.["8"] ?? translations?.demoted;
6558
+ if (template) return template.replace("{{user}}", userName);
7461
6559
  return `${userName} was demoted from moderator.`;
7462
- case "9":
6560
+ }
6561
+ case "9": {
6562
+ const template = translations?.["9"] ?? translations?.permissionsUpdated;
6563
+ if (template) return template.replace("{{user}}", userName);
7463
6564
  return `${userName}'s permissions were updated.`;
7464
- case "10":
6565
+ }
6566
+ case "10": {
6567
+ const template = translations?.["10"] ?? translations?.joined;
6568
+ if (template) return template.replace("{{user}}", userName);
7465
6569
  return `${userName} joined the channel.`;
7466
- case "11":
6570
+ }
6571
+ case "11": {
6572
+ const template = translations?.["11"] ?? translations?.declined;
6573
+ if (template) return template.replace("{{user}}", userName);
7467
6574
  return `${userName} declined the channel invitation.`;
7468
- case "12":
6575
+ }
6576
+ case "12": {
6577
+ const template = translations?.["12"] ?? translations?.left;
6578
+ if (template) return template.replace("{{user}}", userName);
7469
6579
  return `${userName} left the channel.`;
7470
- case "13":
6580
+ }
6581
+ case "13": {
6582
+ const template = translations?.["13"] ?? translations?.clearedHistory;
6583
+ if (template) return template.replace("{{user}}", userName);
7471
6584
  return `${userName} cleared the chat history.`;
6585
+ }
7472
6586
  // 14: channel type change (true = public, false = private)
7473
6587
  case "14": {
7474
6588
  const rawType = parts[2] ?? "";
7475
- const channelType = rawType === "true" ? "public" : "private";
6589
+ const typeKey = rawType === "true" ? "public" : "private";
6590
+ const channelType = translations?.[typeKey] ?? typeKey;
6591
+ const template = translations?.["14"] ?? translations?.changeType;
6592
+ if (template) {
6593
+ return template.replace("{{user}}", userName).replace("{{type}}", channelType);
6594
+ }
7476
6595
  return `${userName} changed the channel to ${channelType}.`;
7477
6596
  }
7478
- // 15: cooldown toggle / duration
7479
6597
  case "15": {
7480
6598
  const duration = parts[2] ?? "0";
7481
6599
  if (duration === "0") {
6600
+ const template2 = translations?.["15_off"] ?? translations?.cooldownOff;
6601
+ if (template2) return template2.replace("{{user}}", userName);
7482
6602
  return `${userName} disabled cooldown.`;
7483
6603
  }
7484
- const durationText = DURATION_MAP[duration] ?? `${duration}ms`;
6604
+ let durationText = `${duration}ms`;
6605
+ const minLabel = translations?.durationUnitMin ?? "minute";
6606
+ const secLabel = translations?.durationUnitSec ?? "seconds";
6607
+ if (duration === "10000") durationText = `10 ${secLabel}`;
6608
+ else if (duration === "30000") durationText = `30 ${secLabel}`;
6609
+ else if (duration === "60000") durationText = `1 ${minLabel}`;
6610
+ else if (duration === "300000") durationText = `5 ${minLabel}`;
6611
+ else if (duration === "900000") durationText = `15 ${minLabel}`;
6612
+ else if (duration === "3600000") durationText = `60 ${minLabel}`;
6613
+ const template = translations?.["15_on"] ?? translations?.cooldownOn;
6614
+ if (template) {
6615
+ return template.replace("{{user}}", userName).replace("{{duration}}", durationText);
6616
+ }
7485
6617
  return `${userName} enabled cooldown for ${durationText}.`;
7486
6618
  }
7487
- case "16":
6619
+ case "16": {
6620
+ const template = translations?.["16"] ?? translations?.bannedWordsUpdated;
6621
+ if (template) return template.replace("{{user}}", userName);
7488
6622
  return `${userName} updated the banned words.`;
7489
- case "17":
6623
+ }
6624
+ case "17": {
6625
+ const template = translations?.["17"] ?? translations?.added;
6626
+ if (template) return template.replace("{{user}}", userName);
7490
6627
  return `${userName} was added to the channel.`;
6628
+ }
7491
6629
  // 18: admin transfer (two user IDs)
7492
6630
  case "18": {
7493
6631
  const oldUserId = parts[1] ?? "";
7494
6632
  const newUserId = parts[2] ?? "";
7495
- const oldUserName = oldUserId ? resolveUser(oldUserId, userMap) : "User";
7496
- const newUserName = newUserId ? resolveUser(newUserId, userMap) : "User";
7497
- return `Admin ${oldUserName} left and assigned ${newUserName} as the new admin.`;
6633
+ const oldUserName = oldUserId ? resolveUser(oldUserId, userMap) : translations?.userFallback ?? "User";
6634
+ const newUserName = newUserId ? resolveUser(newUserId, userMap) : translations?.userFallback ?? "User";
6635
+ const adminLabel = translations?.adminFallback ?? "Admin";
6636
+ const template = translations?.["18"] ?? translations?.adminTransfer;
6637
+ if (template) {
6638
+ return template.replace("{{user}}", oldUserName).replace("{{targetUser}}", newUserName).replace("{{admin}}", adminLabel);
6639
+ }
6640
+ return `${adminLabel} ${oldUserName} left and assigned ${newUserName} as the new admin.`;
7498
6641
  }
7499
6642
  // 19–20: pin / unpin (userId + msgID)
7500
- case "19":
6643
+ case "19": {
6644
+ const template = translations?.["19"] ?? translations?.pinned;
6645
+ if (template) return template.replace("{{user}}", userName);
7501
6646
  return `${userName} pinned a message.`;
7502
- case "20":
6647
+ }
6648
+ case "20": {
6649
+ const template = translations?.["20"] ?? translations?.unpinned;
6650
+ if (template) return template.replace("{{user}}", userName);
7503
6651
  return `${userName} unpinned a message.`;
6652
+ }
7504
6653
  default:
7505
6654
  return trimmed;
7506
6655
  }
@@ -7511,16 +6660,18 @@ var CallType = {
7511
6660
  AUDIO: "audio",
7512
6661
  VIDEO: "video"
7513
6662
  };
7514
- function formatDuration(durationMs) {
6663
+ function formatDuration(durationMs, translations) {
7515
6664
  if (!durationMs) return "";
7516
6665
  const ms = parseInt(durationMs, 10);
7517
6666
  if (isNaN(ms) || ms <= 0) return "";
7518
6667
  const totalSeconds = Math.floor(ms / 1e3);
7519
6668
  const minutes = Math.floor(totalSeconds / 60);
7520
6669
  const seconds = totalSeconds % 60;
7521
- return `${minutes} min, ${seconds} sec`;
6670
+ const minUnit = translations?.durationUnitMin ?? "min";
6671
+ const secUnit = translations?.durationUnitSec ?? "sec";
6672
+ return `${minutes} ${minUnit}, ${seconds} ${secUnit}`;
7522
6673
  }
7523
- function parseSignalMessage(value, myUserId) {
6674
+ function parseSignalMessage(value, myUserId, translations) {
7524
6675
  if (!value || typeof value !== "string") return null;
7525
6676
  const trimmed = value.trim();
7526
6677
  if (!trimmed) return null;
@@ -7539,70 +6690,70 @@ function parseSignalMessage(value, myUserId) {
7539
6690
  let text;
7540
6691
  switch (number) {
7541
6692
  case 1:
7542
- text = isMe ? "Calling..." : "Incoming audio call...";
6693
+ text = isMe ? translations?.calling ?? "Calling..." : translations?.incomingAudioCall ?? "Incoming audio call...";
7543
6694
  callType = CallType.AUDIO;
7544
6695
  color = "#54D62C";
7545
6696
  break;
7546
6697
  case 2:
7547
- text = isMe ? "Outgoing audio call" : "You missed audio call";
6698
+ text = isMe ? translations?.outgoingAudioCall ?? "Outgoing audio call" : translations?.missedAudioCall ?? "You missed audio call";
7548
6699
  callType = CallType.AUDIO;
7549
6700
  color = "#FF4842";
7550
6701
  break;
7551
6702
  case 3:
7552
6703
  if (duration) {
7553
- text = isMe ? "Outgoing audio call" : "Incoming audio call";
6704
+ text = isMe ? translations?.outgoingAudioCall ?? "Outgoing audio call" : translations?.incomingAudioCall ?? "Incoming audio call";
7554
6705
  color = "#54D62C";
7555
6706
  } else {
7556
6707
  if (enderId === myUserId) {
7557
- text = "You cancel audio call";
6708
+ text = translations?.cancelAudioCall ?? "You cancel audio call";
7558
6709
  } else {
7559
- text = "You missed audio call";
6710
+ text = translations?.missedAudioCall ?? "You missed audio call";
7560
6711
  }
7561
6712
  color = "#FF4842";
7562
6713
  }
7563
6714
  callType = CallType.AUDIO;
7564
6715
  break;
7565
6716
  case 4:
7566
- text = isMe ? "Calling..." : "Incoming video call...";
6717
+ text = isMe ? translations?.calling ?? "Calling..." : translations?.incomingVideoCall ?? "Incoming video call...";
7567
6718
  callType = CallType.VIDEO;
7568
6719
  color = "#54D62C";
7569
6720
  break;
7570
6721
  case 5:
7571
- text = isMe ? "Outgoing video call" : "You missed video call";
6722
+ text = isMe ? translations?.outgoingVideoCall ?? "Outgoing video call" : translations?.missedVideoCall ?? "You missed video call";
7572
6723
  callType = CallType.VIDEO;
7573
6724
  color = "#FF4842";
7574
6725
  break;
7575
6726
  case 6:
7576
6727
  if (duration) {
7577
- text = isMe ? "Outgoing video call" : "Incoming video call";
6728
+ text = isMe ? translations?.outgoingVideoCall ?? "Outgoing video call" : translations?.incomingVideoCall ?? "Incoming video call";
7578
6729
  color = "#54D62C";
7579
6730
  } else {
7580
6731
  if (enderId === myUserId) {
7581
- text = "You cancel video call";
6732
+ text = translations?.cancelVideoCall ?? "You cancel video call";
7582
6733
  } else {
7583
- text = "You missed video call";
6734
+ text = translations?.missedVideoCall ?? "You missed video call";
7584
6735
  }
7585
6736
  color = "#FF4842";
7586
6737
  }
7587
6738
  callType = CallType.VIDEO;
7588
6739
  break;
7589
6740
  case 7:
7590
- text = isMe ? "Recipient rejected audio call" : "You rejected audio call";
6741
+ text = isMe ? translations?.rejectedAudioCallRecipient ?? "Recipient rejected audio call" : translations?.rejectedAudioCallYou ?? "You rejected audio call";
7591
6742
  callType = CallType.AUDIO;
7592
6743
  color = "#FF4842";
7593
6744
  break;
7594
6745
  case 8:
7595
- text = isMe ? "Recipient rejected video call" : "You rejected video call";
6746
+ text = isMe ? translations?.rejectedVideoCallRecipient ?? "Recipient rejected video call" : translations?.rejectedVideoCallYou ?? "You rejected video call";
7596
6747
  callType = CallType.VIDEO;
7597
6748
  color = "#FF4842";
7598
6749
  break;
7599
6750
  case 9:
7600
- text = isMe ? "Recipient was busy" : "You missed audio call";
6751
+ text = isMe ? translations?.busyRecipient ?? "Recipient was busy" : translations?.missedAudioCall ?? "You missed audio call";
7601
6752
  callType = CallType.AUDIO;
7602
6753
  color = "#FF4842";
7603
6754
  break;
7604
6755
  case 10:
7605
- text = isMe ? "Recipient was busy" : "You missed video call";
6756
+ text = isMe ? translations?.busyRecipient ?? "Recipient was busy" : translations?.missedVideoCall ?? "You missed video call";
7606
6757
  callType = CallType.VIDEO;
7607
6758
  color = "#FF4842";
7608
6759
  break;
@@ -7611,7 +6762,7 @@ function parseSignalMessage(value, myUserId) {
7611
6762
  callType = "";
7612
6763
  color = "";
7613
6764
  }
7614
- return { text, duration: formatDuration(duration), callType, color };
6765
+ return { text, duration: formatDuration(duration, translations), callType, color };
7615
6766
  }
7616
6767
  export {
7617
6768
  CallAction,
@@ -7640,5 +6791,4 @@ export {
7640
6791
  parseSignalMessage,
7641
6792
  parseSystemMessage
7642
6793
  };
7643
- //! NOTE: check lai o day
7644
6794
  //# sourceMappingURL=index.mjs.map