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