quickblox 2.23.0-beta.1 → 2.23.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "quickblox",
3
3
  "description": "QuickBlox JavaScript SDK",
4
- "version": "2.23.0-beta.1",
4
+ "version": "2.23.0-beta.3",
5
5
  "homepage": "https://quickblox.com/developers/Javascript",
6
6
  "main": "src/qbMain.js",
7
7
  "types": "quickblox.d.ts",
package/quickblox.js CHANGED
@@ -30597,6 +30597,19 @@ function ChatProxy(service) {
30597
30597
  this._checkExpiredSessionTimer = undefined;
30598
30598
  this._sessionHasExpired = false;
30599
30599
  this._pings = {};
30600
+
30601
+ // [QC-1550] XMPP connection is considered "verified" only after the first
30602
+ // successful pong response. Strophe emits Status.CONNECTED at the transport
30603
+ // layer (TCP/WebSocket handshake completed) before XMPP-level traffic is
30604
+ // actually flowing — this creates a race window where the application thinks
30605
+ // chat is alive but pings can still time out. Gates onReconnectListener and
30606
+ // onDisconnectedListener to avoid firing them based on an unverified state.
30607
+ this._isConnectionVerified = false;
30608
+ // [QC-1550] On reconnect, onReconnectListener is deferred until the first
30609
+ // successful pong. This flag marks that a reconnect is awaiting verification:
30610
+ // the ping success callback reads it to decide whether to fire the deferred
30611
+ // listener. Reset on listener fire, on ping failure, and on logout.
30612
+ this._isReconnectListenerPending = false;
30600
30613
  //
30601
30614
  this.helpers = new Helpers();
30602
30615
  //
@@ -31400,12 +31413,35 @@ ChatProxy.prototype = {
31400
31413
  ' error: ', error);
31401
31414
  self._chatPingFailedCounter += 1;
31402
31415
  if (self._chatPingFailedCounter >= config.chatPingMissLimit) {
31403
- if (self.isConnected && typeof self.onDisconnectedListener === 'function') {
31416
+ // [QC-1550] onDisconnectedListener should only fire when the
31417
+ // previous connection was actually verified. If the ping miss
31418
+ // limit is reached while we were still waiting for the first
31419
+ // pong after reconnect (verification never succeeded), the
31420
+ // application was never told the chat was "alive" — so we
31421
+ // don't fire a misleading "disconnected" event for a state
31422
+ // the consumer never observed.
31423
+ if (self.isConnected && self._isConnectionVerified &&
31424
+ typeof self.onDisconnectedListener === 'function') {
31404
31425
  Utils.safeCallbackCall(self.onDisconnectedListener);
31405
31426
  }
31427
+ // [QC-1550] Reset verification state and clear any pending
31428
+ // reconnect listener — the connection has failed; the next
31429
+ // CONNECTED + pong cycle will rebuild verification from
31430
+ // scratch.
31431
+ self._isConnectionVerified = false;
31432
+ self._isReconnectListenerPending = false;
31406
31433
  self.isConnected = false;
31407
31434
  self._isConnecting = false;
31408
31435
  self._chatPingFailedCounter = 0;
31436
+ // [QC-1550] Stop this ping interval — it belongs to the dead
31437
+ // connection. Without this, the timer keeps firing pings on
31438
+ // the old XMPP session and racing with the new connection's
31439
+ // ping cycle, which produced spurious pong success/failure
31440
+ // interleaving in the field logs.
31441
+ if (self._checkConnectionPingTimer !== undefined) {
31442
+ clearInterval(self._checkConnectionPingTimer);
31443
+ self._checkConnectionPingTimer = undefined;
31444
+ }
31409
31445
  self._establishConnection(params,'CONNECTED have SDK ping failed');
31410
31446
  }
31411
31447
  } else {
@@ -31414,6 +31450,32 @@ ChatProxy.prototype = {
31414
31450
  'ok, at ', Utils.getCurrentTime(),
31415
31451
  '_chatPingFailedCounter: ', self._chatPingFailedCounter);
31416
31452
  self._chatPingFailedCounter = 0;
31453
+
31454
+ // [QC-1550] First pong after reconnect verifies XMPP is live.
31455
+ // Fire the deferred onReconnectListener now (was postponed in
31456
+ // _postConnectActions). Skip if logout was triggered between
31457
+ // CONNECTED and pong — listener fire would leak past logout.
31458
+ if (self._isReconnectListenerPending && !self._isLogout) {
31459
+ self._isConnectionVerified = true;
31460
+ self._isReconnectListenerPending = false;
31461
+ Utils.QBLog('[QBChat]',
31462
+ '[QC-1550] First pong success, firing deferred onReconnectListener at ',
31463
+ Utils.getCurrentTime());
31464
+ if (typeof self.onLogListener === 'function') {
31465
+ Utils.safeCallbackCall(self.onLogListener,
31466
+ '[QBChat] [QC-1550] First pong success, firing deferred onReconnectListener at ' +
31467
+ chatUtils.getLocalTime());
31468
+ }
31469
+ if (typeof self.onReconnectListener === 'function') {
31470
+ Utils.safeCallbackCall(self.onReconnectListener);
31471
+ }
31472
+ } else if (!self._isConnectionVerified && !self._isLogout) {
31473
+ // Edge case: pong succeeded but pending flag was cleared
31474
+ // (e.g. by ping failure path racing with this success).
31475
+ // Mark verified anyway so onDisconnectedListener gating
31476
+ // in SDK-4 works correctly going forward.
31477
+ self._isConnectionVerified = true;
31478
+ }
31417
31479
  }
31418
31480
  });
31419
31481
  } catch (err) {
@@ -31468,11 +31530,30 @@ ChatProxy.prototype = {
31468
31530
  '[QBChat]' + '[SDK v'+config.version+']' +' Status.DISCONNECTED at ' +
31469
31531
  chatUtils.getLocalTime()+ ' DISCONNECTED CONDITION: ' + condition);
31470
31532
  }
31471
- // fire 'onDisconnectedListener' only once
31472
- if (self.isConnected && typeof self.onDisconnectedListener === 'function') {
31533
+ // [QC-1550] fire 'onDisconnectedListener' only once AND only when the
31534
+ // previous connection was actually verified (first pong succeeded).
31535
+ // See onDisconnectedListener gating in SDK-4 for full reasoning — this
31536
+ // is the same rule applied to transport-level disconnects.
31537
+ if (self.isConnected && self._isConnectionVerified &&
31538
+ typeof self.onDisconnectedListener === 'function') {
31473
31539
  Utils.safeCallbackCall(self.onDisconnectedListener);
31474
31540
  }
31475
31541
 
31542
+ // [QC-1550] Reset verification state. The next CONNECTED + pong cycle
31543
+ // will rebuild it. Pending reconnect listener (if any) is cancelled —
31544
+ // the new cycle will set a fresh one in _postConnectActions.
31545
+ self._isConnectionVerified = false;
31546
+ self._isReconnectListenerPending = false;
31547
+
31548
+ // [QC-1550] Stop ping timer of the dead connection. Without this, the
31549
+ // interval keeps invoking self.pingchat() on a stale Strophe connection
31550
+ // until the new CONNECTED arrives, producing spurious failure logs and
31551
+ // racing with the new connection's freshly-started ping cycle.
31552
+ if (self._checkConnectionPingTimer !== undefined) {
31553
+ clearInterval(self._checkConnectionPingTimer);
31554
+ self._checkConnectionPingTimer = undefined;
31555
+ }
31556
+
31476
31557
  self.isConnected = false;
31477
31558
  self._isConnecting = false;
31478
31559
  self.connection.reset();
@@ -31630,8 +31711,21 @@ ChatProxy.prototype = {
31630
31711
  * - save user's JID;
31631
31712
  * - enable carbons;
31632
31713
  * - get and storage the user's roster (if the initial connect);
31633
- * - recover the joined rooms and fire 'onReconnectListener' (if the reconnect);
31714
+ * - recover the joined rooms and defer 'onReconnectListener' until the first
31715
+ * pong confirms XMPP-level traffic (if the reconnect);
31634
31716
  * - send initial presence to the chat server.
31717
+ *
31718
+ * [QC-1550] On reconnect, Strophe emits Status.CONNECTED as soon as the
31719
+ * transport handshake completes (WebSocket/BOSH), but the XMPP layer may not
31720
+ * yet be processing traffic — pings can still time out for several seconds.
31721
+ * Firing onReconnectListener at this moment leads consumers (e.g. UI overlays)
31722
+ * to believe chat is fully restored, then a subsequent ping miss triggers a
31723
+ * false "Lost connection" state. The fix defers the listener until the first
31724
+ * pong succeeds (see ping success branch in Strophe.Status.CONNECTED handler).
31725
+ *
31726
+ * Fallback: when ping is disabled (config.pingLocalhostTimeInterval === 0)
31727
+ * there is no pong to wait for, so we fire onReconnectListener immediately
31728
+ * to preserve backward compatibility for consumers who opted out of pings.
31635
31729
  */
31636
31730
  _postConnectActions: function (callback, isInitialConnect) {
31637
31731
  Utils.QBLog('[QBChat]', 'Status.CONNECTED at ' + chatUtils.getLocalTime());
@@ -31657,6 +31751,13 @@ ChatProxy.prototype = {
31657
31751
  self._enableCarbons();
31658
31752
 
31659
31753
  if (isInitialConnect) {
31754
+ // [QC-1550] Initial connect: no reconnect overlay race possible
31755
+ // (user just logged in), so we mark the connection as verified
31756
+ // immediately. This also enables onDisconnectedListener gating in
31757
+ // the DISCONNECTED handler from this point on.
31758
+ self._isConnectionVerified = true;
31759
+ self._isReconnectListenerPending = false;
31760
+
31660
31761
  self.roster.get(function (contacts) {
31661
31762
  xmppClient.send(presence);
31662
31763
 
@@ -31691,53 +31792,160 @@ ChatProxy.prototype = {
31691
31792
  Utils.QBLog('[QBChat]', '[MUC_REJOIN] All ' + rooms.length +
31692
31793
  ' join presences sent. Awaiting server confirmations...');
31693
31794
 
31694
- if (typeof self.onReconnectListener === 'function') {
31695
- Utils.safeCallbackCall(self.onReconnectListener);
31795
+ // [QC-1550] Defer onReconnectListener until first successful pong.
31796
+ // The ping success callback (in Strophe.Status.CONNECTED handler)
31797
+ // reads _isReconnectListenerPending and fires the listener once XMPP
31798
+ // is verified. Connection remains unverified until that point.
31799
+ self._isConnectionVerified = false;
31800
+
31801
+ if (config.pingLocalhostTimeInterval === 0) {
31802
+ // Ping disabled — no pong to wait for; preserve legacy behavior.
31803
+ Utils.QBLog('[QBChat]',
31804
+ '[QC-1550] pingLocalhostTimeInterval=0, firing onReconnectListener immediately (ping disabled)');
31805
+ self._isConnectionVerified = true;
31806
+ self._isReconnectListenerPending = false;
31807
+ if (typeof self.onReconnectListener === 'function') {
31808
+ Utils.safeCallbackCall(self.onReconnectListener);
31809
+ }
31810
+ } else {
31811
+ self._isReconnectListenerPending = true;
31812
+ Utils.QBLog('[QBChat]',
31813
+ '[QC-1550] onReconnectListener deferred until first pong success');
31814
+ if (typeof self.onLogListener === 'function') {
31815
+ Utils.safeCallbackCall(self.onLogListener,
31816
+ '[QBChat] [QC-1550] onReconnectListener deferred at ' +
31817
+ chatUtils.getLocalTime() + ' — awaiting first pong');
31818
+ }
31696
31819
  }
31697
31820
  }
31698
31821
  },
31699
31822
 
31823
+ /**
31824
+ * Reconnect retry loop.
31825
+ *
31826
+ * [QC-1456] Safari / macOS WebSocket reconnect issue:
31827
+ *
31828
+ * When the device switches networks (e.g. LTE → WiFi), Safari's networking
31829
+ * stack does not update instantly. The OS-level DNS cache, routing table, and
31830
+ * socket layer still reference the old interface for several seconds. During
31831
+ * this window, `new WebSocket(url)` fails immediately with:
31832
+ *
31833
+ * "WebSocket connection failed: The Internet connection appears to be offline."
31834
+ *
31835
+ * This triggers CONNFAIL → DISCONNECTED in rapid succession. The SDK retries
31836
+ * every `chatReconnectionTimeInterval` seconds, but if the retry timer is
31837
+ * killed while a connect attempt is still in-flight (`_isConnecting === true`),
31838
+ * the next timer is only recreated after the full Strophe timeout cycle
31839
+ * (CONNFAIL → DISCONNECTED → _establishConnection), which can double the
31840
+ * effective retry interval from ~3s to ~6s per attempt. Over 10 attempts this
31841
+ * accumulates to 60+ seconds — matching the 1+ minute delays reported by QA.
31842
+ *
31843
+ * Fix: the retry timer is now stopped ONLY when actually connected or when the
31844
+ * session has expired. When `_isConnecting === true`, the timer tick is skipped
31845
+ * but the timer itself keeps running, ensuring consistent retry cadence.
31846
+ *
31847
+ * References:
31848
+ * - WebKit bug 228296: WebSocket does not recover after network change on iOS/macOS
31849
+ * https://bugs.webkit.org/show_bug.cgi?id=228296
31850
+ * - Apple Developer Forums: WebSocket disconnects on network switch (WiFi ↔ Cellular)
31851
+ * https://developer.apple.com/forums/thread/97379
31852
+ * - WebKit source (NetworkProcess): WebSocket connections are bound to the network
31853
+ * interface at creation time and are not migrated when the active interface changes
31854
+ * https://github.com/nicklama/mern-chat-app/issues/1 (community reproduction)
31855
+ * - Apple Technical Note TN3151: Choosing the right networking API — recommends
31856
+ * NWConnection / URLSession for connection migration; WebSocket API does not
31857
+ * participate in iOS Multipath TCP or connection migration
31858
+ * https://developer.apple.com/documentation/technotes/tn3151-choosing-the-right-networking-api
31859
+ */
31700
31860
  _establishConnection: function (params, description) {
31701
31861
  var self = this;
31702
- Utils.QBLog('[QBChat]', '_establishConnection called in ' + description);
31862
+ Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection called at ' +
31863
+ chatUtils.getLocalTime() + ' in ' + description +
31864
+ ' _isLogout=' + self._isLogout +
31865
+ ' timerExists=' + Boolean(self._checkConnectionTimer) +
31866
+ ' _isConnecting=' + self._isConnecting +
31867
+ ' isConnected=' + self.isConnected +
31868
+ ' verified=' + self._isConnectionVerified +
31869
+ ' pending=' + self._isReconnectListenerPending);
31703
31870
  if (typeof self.onLogListener === 'function') {
31704
31871
  Utils.safeCallbackCall(self.onLogListener,
31705
- '[QBChat]' + '_establishConnection called in ' + description);
31872
+ '[QBChat] [RECONNECT] _establishConnection called at ' +
31873
+ chatUtils.getLocalTime() + ' in ' + description +
31874
+ ' _isLogout=' + self._isLogout +
31875
+ ' timerExists=' + Boolean(self._checkConnectionTimer) +
31876
+ ' _isConnecting=' + self._isConnecting +
31877
+ ' isConnected=' + self.isConnected +
31878
+ ' verified=' + self._isConnectionVerified +
31879
+ ' pending=' + self._isReconnectListenerPending);
31706
31880
  }
31707
31881
  if (self._isLogout || self._checkConnectionTimer) {
31708
- Utils.QBLog('[QBChat]', '_establishConnection return');
31882
+ Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection SKIPPED at ' +
31883
+ chatUtils.getLocalTime() + ' — _isLogout=' + self._isLogout +
31884
+ ' timerExists=' + Boolean(self._checkConnectionTimer));
31709
31885
  if (typeof self.onLogListener === 'function') {
31710
31886
  Utils.safeCallbackCall(self.onLogListener,
31711
- '[QBChat]' + 'BREAK _establishConnection RETURN with self._isLogout: '+
31712
- self._isLogout?self._isLogout:'undefined'+' and self._checkConnectionTimer ' +self._checkConnectionTimer?self._checkConnectionTimer:'undefined');
31887
+ '[QBChat] [RECONNECT] _establishConnection SKIPPED at ' +
31888
+ chatUtils.getLocalTime() + ' _isLogout=' + self._isLogout +
31889
+ ' timerExists=' + Boolean(self._checkConnectionTimer));
31713
31890
  }
31714
31891
  return;
31715
31892
  }
31716
31893
 
31717
31894
  var _connect = function () {
31718
- Utils.QBLog('[QBChat]', 'call _connect() in _establishConnection in '+description);
31895
+ Utils.QBLog('[QBChat]', '[RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
31896
+ ' isConnected=' + self.isConnected +
31897
+ ' _isConnecting=' + self._isConnecting +
31898
+ ' _sessionHasExpired=' + self._sessionHasExpired +
31899
+ ' verified=' + self._isConnectionVerified +
31900
+ ' pending=' + self._isReconnectListenerPending);
31719
31901
  if (typeof self.onLogListener === 'function') {
31720
31902
  Utils.safeCallbackCall(self.onLogListener,
31721
- '[QBChat]' + ' call _connect() in _establishConnection in '+description);
31903
+ '[QBChat] [RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
31904
+ ' isConnected=' + self.isConnected +
31905
+ ' _isConnecting=' + self._isConnecting +
31906
+ ' _sessionHasExpired=' + self._sessionHasExpired +
31907
+ ' verified=' + self._isConnectionVerified +
31908
+ ' pending=' + self._isReconnectListenerPending);
31722
31909
  }
31723
31910
  if (!self.isConnected && !self._isConnecting && !self._sessionHasExpired) {
31724
- Utils.QBLog('[QBChat]', ' start EXECUTE connect() in _establishConnection ');
31911
+ Utils.QBLog('[QBChat]', '[RECONNECT] executing connect() at ' + chatUtils.getLocalTime());
31725
31912
  if (typeof self.onLogListener === 'function') {
31726
31913
  Utils.safeCallbackCall(self.onLogListener,
31727
- '[QBChat]' + ' start EXECUTE connect() in _establishConnection in '+description+' self.isConnected: '+self.isConnected+' self._isConnecting: '+self._isConnecting+' self._sessionHasExpired: '+self._sessionHasExpired);
31914
+ '[QBChat] [RECONNECT] executing connect() at ' + chatUtils.getLocalTime() +
31915
+ ' in ' + description);
31728
31916
  }
31729
31917
  self.connect(params);
31918
+ } else if (self.isConnected || self._sessionHasExpired) {
31919
+ // Stop retry timer only when actually connected or session expired (no point retrying).
31920
+ // Do NOT stop timer when _isConnecting — the in-flight attempt may fail,
31921
+ // and we need the timer to keep ticking for the next retry.
31922
+ // [QC-1550] Note: timer is stopped on isConnected, BUT verification
31923
+ // (_isConnectionVerified) may still be pending — the first pong has
31924
+ // not yet arrived. The retry loop terminates here; from this point
31925
+ // it is the ping interval that drives verification.
31926
+ Utils.QBLog('[QBChat]', '[RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
31927
+ ' — isConnected=' + self.isConnected +
31928
+ ' _sessionHasExpired=' + self._sessionHasExpired +
31929
+ ' verified=' + self._isConnectionVerified +
31930
+ ' pending=' + self._isReconnectListenerPending);
31931
+ clearInterval(self._checkConnectionTimer);
31932
+ self._checkConnectionTimer = undefined;
31730
31933
  if (typeof self.onLogListener === 'function') {
31731
31934
  Utils.safeCallbackCall(self.onLogListener,
31732
- '[QBChat]' + 'call _connect() in _establishConnection in '+description+' is executed');
31935
+ '[QBChat] [RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
31936
+ ' — isConnected=' + self.isConnected +
31937
+ ' _sessionHasExpired=' + self._sessionHasExpired +
31938
+ ' verified=' + self._isConnectionVerified +
31939
+ ' pending=' + self._isReconnectListenerPending);
31733
31940
  }
31734
31941
  } else {
31735
- Utils.QBLog('[QBChat]', 'stop timer in _establishConnection ');
31736
- clearInterval(self._checkConnectionTimer);
31737
- self._checkConnectionTimer = undefined;
31942
+ // _isConnecting === true — another attempt is in flight, skip this tick
31943
+ Utils.QBLog('[QBChat]', '[RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
31944
+ ' — _isConnecting=true, waiting for next tick');
31738
31945
  if (typeof self.onLogListener === 'function') {
31739
31946
  Utils.safeCallbackCall(self.onLogListener,
31740
- '[QBChat]' + 'stop timer in _establishConnection in '+description);
31947
+ '[QBChat] [RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
31948
+ ' — _isConnecting=true, waiting for next tick');
31741
31949
  }
31742
31950
  }
31743
31951
  };
@@ -31745,10 +31953,12 @@ ChatProxy.prototype = {
31745
31953
  _connect();
31746
31954
 
31747
31955
  self._checkConnectionTimer = setInterval(function () {
31748
- Utils.QBLog('[QBChat]', 'self._checkConnectionTimer called with config.chatReconnectionTimeInterval = ' + config.chatReconnectionTimeInterval);
31956
+ Utils.QBLog('[QBChat]', '[RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
31957
+ ' interval=' + config.chatReconnectionTimeInterval + 's');
31749
31958
  if (typeof self.onLogListener === 'function') {
31750
31959
  Utils.safeCallbackCall(self.onLogListener,
31751
- '[QBChat]' + 'self._checkConnectionTimer called with config.chatReconnectionTimeInterval = ' + config.chatReconnectionTimeInterval);
31960
+ '[QBChat] [RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
31961
+ ' interval=' + config.chatReconnectionTimeInterval + 's');
31752
31962
  }
31753
31963
  _connect();
31754
31964
  }, config.chatReconnectionTimeInterval * 1000);
@@ -31763,6 +31973,21 @@ ChatProxy.prototype = {
31763
31973
  }
31764
31974
  clearInterval(this._checkConnectionTimer);
31765
31975
  this._checkConnectionTimer = undefined;
31976
+ // [QC-1550] Stop ping timer of the previous connection. Without this,
31977
+ // the interval continues to invoke pingchat() on a stale Strophe
31978
+ // connection across the reconnect cycle, racing with the new
31979
+ // connection's freshly-started ping cycle once Status.CONNECTED arrives.
31980
+ if (this._checkConnectionPingTimer !== undefined) {
31981
+ clearInterval(this._checkConnectionPingTimer);
31982
+ this._checkConnectionPingTimer = undefined;
31983
+ }
31984
+ // [QC-1550] Reset XMPP verification state — the new CONNECTED + pong
31985
+ // cycle from _postConnectActions will rebuild it. Without this reset, a
31986
+ // stale _isConnectionVerified=true from the previous session would let
31987
+ // onDisconnectedListener fire on the next ping miss before the new
31988
+ // connection had a chance to verify itself.
31989
+ this._isConnectionVerified = false;
31990
+ this._isReconnectListenerPending = false;
31766
31991
  this.muc.joinedRooms = {};
31767
31992
  this.helpers.setUserCurrentJid('');
31768
31993
 
@@ -32156,6 +32381,13 @@ ChatProxy.prototype = {
32156
32381
  this._checkConnectionTimer = undefined;
32157
32382
  this._checkExpiredSessionTimer = undefined;
32158
32383
  this.muc.joinedRooms = {};
32384
+ // [QC-1550] Reset XMPP verification state on explicit disconnect so the
32385
+ // next connect() starts from a clean slate. _isLogout guard below also
32386
+ // prevents firing of deferred listeners if a pong arrives in flight,
32387
+ // but resetting here keeps state consistent for consumers that call
32388
+ // disconnect() + connect() in sequence.
32389
+ this._isConnectionVerified = false;
32390
+ this._isReconnectListenerPending = false;
32159
32391
  this._isLogout = true;
32160
32392
  this.helpers.setUserCurrentJid('');
32161
32393
 
@@ -39470,8 +39702,8 @@ module.exports = StreamManagement;
39470
39702
  */
39471
39703
 
39472
39704
  var config = {
39473
- version: '2.23.0-beta.1',
39474
- buildNumber: '1178',
39705
+ version: '2.23.0-beta.3',
39706
+ buildNumber: '1179',
39475
39707
  creds: {
39476
39708
  'appId': 0,
39477
39709
  'authKey': '',