@tonconnect/sdk 3.4.0-beta.3 → 3.4.0-beta.5

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/lib/cjs/index.cjs CHANGED
@@ -919,180 +919,6 @@ function isExpiredPendingConnectionHttpRaw(connection) {
919
919
  return Date.now() - ((_a = connection.createdAt) !== null && _a !== void 0 ? _a : 0) > CONNECTION_HTTP_EXPIRATION_TIME;
920
920
  }
921
921
 
922
- class BridgeConnectionStorage {
923
- constructor(storage) {
924
- this.storage = storage;
925
- this.storeKey = 'ton-connect-storage_bridge-connection';
926
- }
927
- storeConnection(connection) {
928
- return __awaiter(this, void 0, void 0, function* () {
929
- if (connection.type === 'injected' || connection.type === 'wallet-connect') {
930
- return this.storage.setItem(this.storeKey, JSON.stringify(connection));
931
- }
932
- if (!isPendingConnectionHttp(connection)) {
933
- const rawSession = {
934
- sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
935
- walletPublicKey: connection.session.walletPublicKey,
936
- bridgeUrl: connection.session.bridgeUrl
937
- };
938
- const rawConnection = {
939
- type: 'http',
940
- connectEvent: connection.connectEvent,
941
- session: rawSession,
942
- lastWalletEventId: connection.lastWalletEventId,
943
- nextRpcRequestId: connection.nextRpcRequestId
944
- };
945
- return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
946
- }
947
- const rawConnection = {
948
- type: 'http',
949
- connectionSource: connection.connectionSource,
950
- sessionCrypto: connection.sessionCrypto.stringifyKeypair(),
951
- createdAt: Date.now()
952
- };
953
- return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
954
- });
955
- }
956
- removeConnection() {
957
- return __awaiter(this, void 0, void 0, function* () {
958
- return this.storage.removeItem(this.storeKey);
959
- });
960
- }
961
- getConnection() {
962
- return __awaiter(this, void 0, void 0, function* () {
963
- const stored = yield this.storage.getItem(this.storeKey);
964
- if (!stored) {
965
- return null;
966
- }
967
- const connection = JSON.parse(stored);
968
- if (connection.type === 'injected' || connection.type === 'wallet-connect') {
969
- return connection;
970
- }
971
- if (!isPendingConnectionHttpRaw(connection)) {
972
- const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
973
- return {
974
- type: 'http',
975
- connectEvent: connection.connectEvent,
976
- lastWalletEventId: connection.lastWalletEventId,
977
- nextRpcRequestId: connection.nextRpcRequestId,
978
- session: {
979
- sessionCrypto,
980
- bridgeUrl: connection.session.bridgeUrl,
981
- walletPublicKey: connection.session.walletPublicKey
982
- }
983
- };
984
- }
985
- if (isExpiredPendingConnectionHttpRaw(connection)) {
986
- yield this.removeConnection();
987
- return null;
988
- }
989
- return {
990
- type: 'http',
991
- sessionCrypto: new protocol.SessionCrypto(connection.sessionCrypto),
992
- connectionSource: connection.connectionSource
993
- };
994
- });
995
- }
996
- getHttpConnection() {
997
- return __awaiter(this, void 0, void 0, function* () {
998
- const connection = yield this.getConnection();
999
- if (!connection) {
1000
- throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
1001
- }
1002
- if (connection.type !== 'http') {
1003
- throw new TonConnectError(`Trying to read HTTP connection source while ${connection.type} connection is stored`);
1004
- }
1005
- return connection;
1006
- });
1007
- }
1008
- getHttpPendingConnection() {
1009
- return __awaiter(this, void 0, void 0, function* () {
1010
- const connection = yield this.getConnection();
1011
- if (!connection) {
1012
- throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
1013
- }
1014
- if (connection.type !== 'http') {
1015
- throw new TonConnectError(`Trying to read HTTP connection source while ${connection.type} connection is stored`);
1016
- }
1017
- if (!isPendingConnectionHttp(connection)) {
1018
- throw new TonConnectError('Trying to read HTTP-pending connection while http connection is stored');
1019
- }
1020
- return connection;
1021
- });
1022
- }
1023
- getInjectedConnection() {
1024
- return __awaiter(this, void 0, void 0, function* () {
1025
- const connection = yield this.getConnection();
1026
- if (!connection) {
1027
- throw new TonConnectError('Trying to read Injected bridge connection source while nothing is stored');
1028
- }
1029
- if ((connection === null || connection === void 0 ? void 0 : connection.type) !== 'injected') {
1030
- throw new TonConnectError(`Trying to read Injected bridge connection source while ${connection.type} connection is stored`);
1031
- }
1032
- return connection;
1033
- });
1034
- }
1035
- getWalletConnectConnection() {
1036
- return __awaiter(this, void 0, void 0, function* () {
1037
- const connection = yield this.getConnection();
1038
- if (!connection) {
1039
- throw new TonConnectError('Trying to read wallet connect bridge connection source while nothing is stored');
1040
- }
1041
- if ((connection === null || connection === void 0 ? void 0 : connection.type) !== 'wallet-connect') {
1042
- throw new TonConnectError(`Trying to read wallet connect bridge connection source while ${connection.type} connection is stored`);
1043
- }
1044
- return connection;
1045
- });
1046
- }
1047
- storedConnectionType() {
1048
- return __awaiter(this, void 0, void 0, function* () {
1049
- const stored = yield this.storage.getItem(this.storeKey);
1050
- if (!stored) {
1051
- return null;
1052
- }
1053
- const connection = JSON.parse(stored);
1054
- return connection.type;
1055
- });
1056
- }
1057
- storeLastWalletEventId(id) {
1058
- return __awaiter(this, void 0, void 0, function* () {
1059
- const connection = yield this.getConnection();
1060
- if (connection && connection.type === 'http' && !isPendingConnectionHttp(connection)) {
1061
- connection.lastWalletEventId = id;
1062
- return this.storeConnection(connection);
1063
- }
1064
- });
1065
- }
1066
- getLastWalletEventId() {
1067
- return __awaiter(this, void 0, void 0, function* () {
1068
- const connection = yield this.getConnection();
1069
- if (connection && 'lastWalletEventId' in connection) {
1070
- return connection.lastWalletEventId;
1071
- }
1072
- return undefined;
1073
- });
1074
- }
1075
- increaseNextRpcRequestId() {
1076
- return __awaiter(this, void 0, void 0, function* () {
1077
- const connection = yield this.getConnection();
1078
- if (connection && 'nextRpcRequestId' in connection) {
1079
- const lastId = connection.nextRpcRequestId || 0;
1080
- connection.nextRpcRequestId = lastId + 1;
1081
- return this.storeConnection(connection);
1082
- }
1083
- });
1084
- }
1085
- getNextRpcRequestId() {
1086
- return __awaiter(this, void 0, void 0, function* () {
1087
- const connection = yield this.getConnection();
1088
- if (connection && 'nextRpcRequestId' in connection) {
1089
- return connection.nextRpcRequestId || 0;
1090
- }
1091
- return 0;
1092
- });
1093
- }
1094
- }
1095
-
1096
922
  const PROTOCOL_VERSION = 2;
1097
923
 
1098
924
  /**
@@ -1262,20 +1088,45 @@ function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
1262
1088
  return buf;
1263
1089
  }
1264
1090
 
1091
+ function waitForSome(promises, count) {
1092
+ return __awaiter(this, void 0, void 0, function* () {
1093
+ if (count <= 0)
1094
+ return [];
1095
+ if (count > promises.length) {
1096
+ throw new RangeError('count cannot be greater than the number of promises');
1097
+ }
1098
+ const results = new Array(promises.length);
1099
+ let settledCount = 0;
1100
+ return new Promise(resolve => {
1101
+ promises.forEach((p, index) => {
1102
+ Promise.resolve(p)
1103
+ .then(value => ({ status: 'fulfilled', value }))
1104
+ .catch(reason => ({ status: 'rejected', reason }))
1105
+ .then(result => {
1106
+ results[index] = result;
1107
+ settledCount++;
1108
+ if (settledCount === count) {
1109
+ resolve(results);
1110
+ }
1111
+ });
1112
+ });
1113
+ });
1114
+ });
1115
+ }
1116
+
1265
1117
  class BridgeProvider {
1266
1118
  static fromStorage(storage, analyticsManager) {
1267
1119
  return __awaiter(this, void 0, void 0, function* () {
1268
- const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
1269
- const connection = yield bridgeConnectionStorage.getHttpConnection();
1120
+ const connection = yield storage.getHttpConnection();
1270
1121
  if (isPendingConnectionHttp(connection)) {
1271
1122
  return new BridgeProvider(storage, connection.connectionSource, analyticsManager);
1272
1123
  }
1273
1124
  return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl }, analyticsManager);
1274
1125
  });
1275
1126
  }
1276
- constructor(storage, walletConnectionSource, analyticsManager) {
1127
+ constructor(connectionStorage, walletConnectionSource, analyticsManager) {
1277
1128
  var _a;
1278
- this.storage = storage;
1129
+ this.connectionStorage = connectionStorage;
1279
1130
  this.walletConnectionSource = walletConnectionSource;
1280
1131
  this.analyticsManager = analyticsManager;
1281
1132
  this.type = 'http';
@@ -1287,7 +1138,7 @@ class BridgeProvider {
1287
1138
  this.listeners = [];
1288
1139
  this.defaultOpeningDeadlineMS = 12000;
1289
1140
  this.defaultRetryTimeoutMS = 2000;
1290
- this.connectionStorage = new BridgeConnectionStorage(storage);
1141
+ this.optionalOpenGateways = 3;
1291
1142
  this.analytics = (_a = this.analyticsManager) === null || _a === void 0 ? void 0 : _a.scoped();
1292
1143
  }
1293
1144
  connect(message, options) {
@@ -1373,7 +1224,7 @@ class BridgeProvider {
1373
1224
  logDebug('Gateway is already opened, closing previous gateway');
1374
1225
  yield this.gateway.close();
1375
1226
  }
1376
- this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this), this.analyticsManager);
1227
+ this.gateway = new BridgeGateway(this.connectionStorage.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this), this.analyticsManager);
1377
1228
  if (abortController.signal.aborted) {
1378
1229
  return;
1379
1230
  }
@@ -1653,11 +1504,13 @@ class BridgeProvider {
1653
1504
  this.pendingGateways.map(bridge => bridge.close().catch());
1654
1505
  // open new gateways
1655
1506
  this.pendingGateways = this.walletConnectionSource.map(source => {
1656
- const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, () => { }, this.analyticsManager);
1507
+ const gateway = new BridgeGateway(this.connectionStorage.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, () => { }, this.analyticsManager);
1657
1508
  gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
1658
1509
  return gateway;
1659
1510
  });
1660
- yield Promise.allSettled(this.pendingGateways.map(bridge => callForSuccess((_options) => {
1511
+ // Wait until the specified optional gateways are opened, not necessarily all gateways
1512
+ const gatewaysToWaitFor = Math.max(this.pendingGateways.length - this.optionalOpenGateways, 1);
1513
+ yield waitForSome(this.pendingGateways.map(bridge => callForSuccess((_options) => {
1661
1514
  var _a;
1662
1515
  if (!this.pendingGateways.some(item => item === bridge)) {
1663
1516
  return bridge.close();
@@ -1671,7 +1524,7 @@ class BridgeProvider {
1671
1524
  attempts: Number.MAX_SAFE_INTEGER,
1672
1525
  delayMs: this.defaultRetryTimeoutMS,
1673
1526
  signal: options === null || options === void 0 ? void 0 : options.signal
1674
- })));
1527
+ })), gatewaysToWaitFor);
1675
1528
  return;
1676
1529
  }
1677
1530
  else {
@@ -1679,7 +1532,7 @@ class BridgeProvider {
1679
1532
  logDebug(`Gateway is already opened, closing previous gateway`);
1680
1533
  yield this.gateway.close();
1681
1534
  }
1682
- this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this), this.analyticsManager);
1535
+ this.gateway = new BridgeGateway(this.connectionStorage.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this), this.analyticsManager);
1683
1536
  return yield this.gateway.registerSession({
1684
1537
  openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
1685
1538
  signal: options === null || options === void 0 ? void 0 : options.signal,
@@ -1866,8 +1719,7 @@ function getWindowEntries() {
1866
1719
  class InjectedProvider {
1867
1720
  static fromStorage(storage, analyticsManager) {
1868
1721
  return __awaiter(this, void 0, void 0, function* () {
1869
- const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
1870
- const connection = yield bridgeConnectionStorage.getInjectedConnection();
1722
+ const connection = yield storage.getInjectedConnection();
1871
1723
  return new InjectedProvider(storage, connection.jsBridgeKey, analyticsManager);
1872
1724
  });
1873
1725
  }
@@ -1905,7 +1757,8 @@ class InjectedProvider {
1905
1757
  typeof window[injectedWalletKey] === 'object' &&
1906
1758
  'tonconnect' in window[injectedWalletKey]);
1907
1759
  }
1908
- constructor(storage, injectedWalletKey, analyticsManager) {
1760
+ constructor(connectionStorage, injectedWalletKey, analyticsManager) {
1761
+ this.connectionStorage = connectionStorage;
1909
1762
  this.injectedWalletKey = injectedWalletKey;
1910
1763
  this.type = 'injected';
1911
1764
  this.unsubscribeCallback = null;
@@ -1915,7 +1768,6 @@ class InjectedProvider {
1915
1768
  if (!InjectedProvider.isWindowContainsWallet(window, injectedWalletKey)) {
1916
1769
  throw new WalletNotInjectedError();
1917
1770
  }
1918
- this.connectionStorage = new BridgeConnectionStorage(storage);
1919
1771
  this.injectedWallet = window[injectedWalletKey].tonconnect;
1920
1772
  if (analyticsManager) {
1921
1773
  this.analytics = analyticsManager.scoped({
@@ -2131,6 +1983,205 @@ class InjectedProvider {
2131
1983
  }
2132
1984
  InjectedProvider.window = getWindow();
2133
1985
 
1986
+ class BridgeConnectionStorage {
1987
+ constructor(storage, walletsListManager) {
1988
+ this.storage = storage;
1989
+ this.walletsListManager = walletsListManager;
1990
+ this.storeKey = 'ton-connect-storage_bridge-connection';
1991
+ }
1992
+ storeConnection(connection) {
1993
+ return __awaiter(this, void 0, void 0, function* () {
1994
+ if (connection.type === 'injected' || connection.type === 'wallet-connect') {
1995
+ return this.storage.setItem(this.storeKey, JSON.stringify(connection));
1996
+ }
1997
+ if (!isPendingConnectionHttp(connection)) {
1998
+ const rawSession = {
1999
+ sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
2000
+ walletPublicKey: connection.session.walletPublicKey,
2001
+ bridgeUrl: connection.session.bridgeUrl
2002
+ };
2003
+ const rawConnection = {
2004
+ type: 'http',
2005
+ connectEvent: connection.connectEvent,
2006
+ session: rawSession,
2007
+ lastWalletEventId: connection.lastWalletEventId,
2008
+ nextRpcRequestId: connection.nextRpcRequestId
2009
+ };
2010
+ return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
2011
+ }
2012
+ const rawConnection = {
2013
+ type: 'http',
2014
+ connectionSource: connection.connectionSource,
2015
+ sessionCrypto: connection.sessionCrypto.stringifyKeypair(),
2016
+ createdAt: Date.now()
2017
+ };
2018
+ return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
2019
+ });
2020
+ }
2021
+ removeConnection() {
2022
+ return __awaiter(this, void 0, void 0, function* () {
2023
+ return this.storage.removeItem(this.storeKey);
2024
+ });
2025
+ }
2026
+ getConnection() {
2027
+ return __awaiter(this, void 0, void 0, function* () {
2028
+ try {
2029
+ const stored = yield this.storage.getItem(this.storeKey);
2030
+ if (!stored) {
2031
+ return null;
2032
+ }
2033
+ const connection = JSON.parse(stored);
2034
+ if (connection.type === 'injected' || connection.type === 'wallet-connect') {
2035
+ return connection;
2036
+ }
2037
+ if (!isPendingConnectionHttpRaw(connection)) {
2038
+ const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
2039
+ return yield this.actualizeBridgeConnection({
2040
+ type: 'http',
2041
+ connectEvent: connection.connectEvent,
2042
+ lastWalletEventId: connection.lastWalletEventId,
2043
+ nextRpcRequestId: connection.nextRpcRequestId,
2044
+ session: {
2045
+ sessionCrypto,
2046
+ bridgeUrl: connection.session.bridgeUrl,
2047
+ walletPublicKey: connection.session.walletPublicKey
2048
+ }
2049
+ });
2050
+ }
2051
+ if (isExpiredPendingConnectionHttpRaw(connection)) {
2052
+ yield this.removeConnection();
2053
+ return null;
2054
+ }
2055
+ return {
2056
+ type: 'http',
2057
+ sessionCrypto: new protocol.SessionCrypto(connection.sessionCrypto),
2058
+ connectionSource: connection.connectionSource
2059
+ };
2060
+ }
2061
+ catch (err) {
2062
+ logDebug('Error retrieving connection', err);
2063
+ return null;
2064
+ }
2065
+ });
2066
+ }
2067
+ getHttpConnection() {
2068
+ return __awaiter(this, void 0, void 0, function* () {
2069
+ const connection = yield this.getConnection();
2070
+ if (!connection) {
2071
+ throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
2072
+ }
2073
+ if (connection.type !== 'http') {
2074
+ throw new TonConnectError(`Trying to read HTTP connection source while ${connection.type} connection is stored`);
2075
+ }
2076
+ return connection;
2077
+ });
2078
+ }
2079
+ getHttpPendingConnection() {
2080
+ return __awaiter(this, void 0, void 0, function* () {
2081
+ const connection = yield this.getConnection();
2082
+ if (!connection) {
2083
+ throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
2084
+ }
2085
+ if (connection.type !== 'http') {
2086
+ throw new TonConnectError(`Trying to read HTTP connection source while ${connection.type} connection is stored`);
2087
+ }
2088
+ if (!isPendingConnectionHttp(connection)) {
2089
+ throw new TonConnectError('Trying to read HTTP-pending connection while http connection is stored');
2090
+ }
2091
+ return connection;
2092
+ });
2093
+ }
2094
+ getInjectedConnection() {
2095
+ return __awaiter(this, void 0, void 0, function* () {
2096
+ const connection = yield this.getConnection();
2097
+ if (!connection) {
2098
+ throw new TonConnectError('Trying to read Injected bridge connection source while nothing is stored');
2099
+ }
2100
+ if ((connection === null || connection === void 0 ? void 0 : connection.type) !== 'injected') {
2101
+ throw new TonConnectError(`Trying to read Injected bridge connection source while ${connection.type} connection is stored`);
2102
+ }
2103
+ return connection;
2104
+ });
2105
+ }
2106
+ getWalletConnectConnection() {
2107
+ return __awaiter(this, void 0, void 0, function* () {
2108
+ const connection = yield this.getConnection();
2109
+ if (!connection) {
2110
+ throw new TonConnectError('Trying to read wallet connect bridge connection source while nothing is stored');
2111
+ }
2112
+ if ((connection === null || connection === void 0 ? void 0 : connection.type) !== 'wallet-connect') {
2113
+ throw new TonConnectError(`Trying to read wallet connect bridge connection source while ${connection.type} connection is stored`);
2114
+ }
2115
+ return connection;
2116
+ });
2117
+ }
2118
+ storedConnectionType() {
2119
+ return __awaiter(this, void 0, void 0, function* () {
2120
+ const stored = yield this.storage.getItem(this.storeKey);
2121
+ if (!stored) {
2122
+ return null;
2123
+ }
2124
+ const connection = JSON.parse(stored);
2125
+ return connection.type;
2126
+ });
2127
+ }
2128
+ storeLastWalletEventId(id) {
2129
+ return __awaiter(this, void 0, void 0, function* () {
2130
+ const connection = yield this.getConnection();
2131
+ if (connection && connection.type === 'http' && !isPendingConnectionHttp(connection)) {
2132
+ connection.lastWalletEventId = id;
2133
+ return this.storeConnection(connection);
2134
+ }
2135
+ });
2136
+ }
2137
+ getLastWalletEventId() {
2138
+ return __awaiter(this, void 0, void 0, function* () {
2139
+ const connection = yield this.getConnection();
2140
+ if (connection && 'lastWalletEventId' in connection) {
2141
+ return connection.lastWalletEventId;
2142
+ }
2143
+ return undefined;
2144
+ });
2145
+ }
2146
+ increaseNextRpcRequestId() {
2147
+ return __awaiter(this, void 0, void 0, function* () {
2148
+ const connection = yield this.getConnection();
2149
+ if (connection && 'nextRpcRequestId' in connection) {
2150
+ const lastId = connection.nextRpcRequestId || 0;
2151
+ connection.nextRpcRequestId = lastId + 1;
2152
+ return this.storeConnection(connection);
2153
+ }
2154
+ });
2155
+ }
2156
+ getNextRpcRequestId() {
2157
+ return __awaiter(this, void 0, void 0, function* () {
2158
+ const connection = yield this.getConnection();
2159
+ if (connection && 'nextRpcRequestId' in connection) {
2160
+ return connection.nextRpcRequestId || 0;
2161
+ }
2162
+ return 0;
2163
+ });
2164
+ }
2165
+ actualizeBridgeConnection(connection) {
2166
+ return __awaiter(this, void 0, void 0, function* () {
2167
+ try {
2168
+ const appName = connection.connectEvent.payload.device.appName;
2169
+ const wallet = yield this.walletsListManager.getRemoteWallet(appName);
2170
+ if (wallet.bridgeUrl === connection.session.bridgeUrl) {
2171
+ return connection;
2172
+ }
2173
+ const actualizedConnection = Object.assign(Object.assign({}, connection), { session: Object.assign(Object.assign({}, connection.session), { bridgeUrl: wallet.bridgeUrl }) });
2174
+ yield this.storeConnection(actualizedConnection);
2175
+ return actualizedConnection;
2176
+ }
2177
+ catch (error) {
2178
+ logDebug('Failed to actualize bridge connection', error);
2179
+ return connection;
2180
+ }
2181
+ });
2182
+ }
2183
+ }
2184
+
2134
2185
  /**
2135
2186
  * Default storage to save protocol data, uses `localStorage` if it is available. In Safari's private mode, it uses `InMemoryStorage`. In Node.js, it throws an error.
2136
2187
  */
@@ -3081,6 +3132,7 @@ class WalletsListManager {
3081
3132
  (_a = options === null || options === void 0 ? void 0 : options.walletsListSource) !== null && _a !== void 0 ? _a : 'https://config.ton.org/wallets-v2.json';
3082
3133
  }
3083
3134
  this.cacheTTLMs = options === null || options === void 0 ? void 0 : options.cacheTTLMs;
3135
+ this.onDownloadDurationMeasured = options === null || options === void 0 ? void 0 : options.onDownloadDurationMeasured;
3084
3136
  }
3085
3137
  getWallets() {
3086
3138
  return __awaiter(this, void 0, void 0, function* () {
@@ -3119,9 +3171,24 @@ class WalletsListManager {
3119
3171
  return this.walletsListDTOCache;
3120
3172
  });
3121
3173
  }
3174
+ getRemoteWallet(appName) {
3175
+ return __awaiter(this, void 0, void 0, function* () {
3176
+ const walletsList = yield this.getWallets();
3177
+ const wallet = walletsList.find(wallet => wallet.appName === appName);
3178
+ if (!wallet) {
3179
+ throw new TonConnectError(`Wallet info not found for appName: "${appName}"`);
3180
+ }
3181
+ if (!isWalletInfoRemote(wallet)) {
3182
+ throw new TonConnectError(`Wallet "${appName}" is not remote`);
3183
+ }
3184
+ return wallet;
3185
+ });
3186
+ }
3122
3187
  fetchWalletsListFromSource() {
3123
3188
  return __awaiter(this, void 0, void 0, function* () {
3189
+ var _a, _b;
3124
3190
  let walletsList = [];
3191
+ const startTime = performance.now();
3125
3192
  try {
3126
3193
  const walletsResponse = yield fetch(this.walletsListSource);
3127
3194
  walletsList = yield walletsResponse.json();
@@ -3135,10 +3202,14 @@ class WalletsListManager {
3135
3202
  .join(', ')} config format is wrong. They were removed from the wallets list.`);
3136
3203
  walletsList = walletsList.filter(wallet => this.isCorrectWalletConfigDTO(wallet));
3137
3204
  }
3205
+ const endTime = performance.now();
3206
+ const duration = Math.round(endTime - startTime);
3207
+ (_a = this.onDownloadDurationMeasured) === null || _a === void 0 ? void 0 : _a.call(this, duration);
3138
3208
  }
3139
3209
  catch (e) {
3140
3210
  logError(e);
3141
3211
  walletsList = FALLBACK_WALLETS_LIST;
3212
+ (_b = this.onDownloadDurationMeasured) === null || _b === void 0 ? void 0 : _b.call(this, undefined);
3142
3213
  }
3143
3214
  return walletsList;
3144
3215
  });
@@ -3809,7 +3880,7 @@ class TonConnectTracker {
3809
3880
  }
3810
3881
  }
3811
3882
 
3812
- const tonConnectSdkVersion = "3.4.0-beta.2";
3883
+ const tonConnectSdkVersion = "3.4.0-beta.5";
3813
3884
 
3814
3885
  const bounceableTag = 0x11;
3815
3886
  const noBounceableTag = 0x51;
@@ -4248,10 +4319,6 @@ function validateTonProofItemReply(data) {
4248
4319
  if (!isValidObject(proof)) {
4249
4320
  return "Invalid 'proof' object";
4250
4321
  }
4251
- const allowedProofKeys = ['timestamp', 'domain', 'payload', 'signature'];
4252
- if (hasExtraProperties(proof, allowedProofKeys)) {
4253
- return 'ton_proof item contains extra properties';
4254
- }
4255
4322
  if (!isValidNumber(proof.timestamp)) {
4256
4323
  return "Invalid 'proof.timestamp'";
4257
4324
  }
@@ -4324,10 +4391,61 @@ function normalizeBase64(data) {
4324
4391
  function pascalToKebab(value) {
4325
4392
  return value.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
4326
4393
  }
4394
+ /**
4395
+ * Collects static connection metrics from the browser's Performance API.
4396
+ * TTFB is measured once at page load and doesn't change.
4397
+ * @returns An object containing static connection metrics (TTFB) or empty object if not available.
4398
+ */
4399
+ function getStaticConnectionMetrics() {
4400
+ const metrics = {};
4401
+ // Get TTFB from Navigation Timing API (static, measured once at page load)
4402
+ try {
4403
+ const navEntries = performance.getEntriesByType('navigation');
4404
+ if (navEntries.length > 0) {
4405
+ const nav = navEntries[0];
4406
+ if (nav.responseStart && nav.requestStart) {
4407
+ metrics.conn_ttfb = Math.round(nav.responseStart - nav.requestStart);
4408
+ }
4409
+ }
4410
+ }
4411
+ catch (e) {
4412
+ // Performance API not available or error occurred
4413
+ }
4414
+ return metrics;
4415
+ }
4416
+ /**
4417
+ * Collects dynamic connection metrics from the browser's Network Information API.
4418
+ * @returns An object containing dynamic connection metrics (RTT, network type) or empty object if not available.
4419
+ */
4420
+ function getDynamicConnectionMetrics() {
4421
+ const metrics = {};
4422
+ // Get RTT and network type from Network Information API (dynamic, can change)
4423
+ try {
4424
+ const navigatorWithConnection = navigator;
4425
+ const connection = navigatorWithConnection.connection ||
4426
+ navigatorWithConnection.mozConnection ||
4427
+ navigatorWithConnection.webkitConnection;
4428
+ if (connection) {
4429
+ if (connection.rtt !== undefined) {
4430
+ metrics.conn_rtt = connection.rtt;
4431
+ }
4432
+ if (connection.effectiveType) {
4433
+ metrics.conn_network_type = connection.effectiveType;
4434
+ }
4435
+ else if (connection.type) {
4436
+ metrics.conn_network_type = connection.type;
4437
+ }
4438
+ }
4439
+ }
4440
+ catch (e) {
4441
+ // Network Information API not available or error occurred
4442
+ }
4443
+ return metrics;
4444
+ }
4327
4445
 
4328
4446
  class AnalyticsManager {
4329
4447
  constructor(options = {}) {
4330
- var _a, _b, _c, _d, _e;
4448
+ var _a, _b, _c, _d, _e, _f;
4331
4449
  this.events = [];
4332
4450
  this.timeoutId = null;
4333
4451
  this.isProcessing = false;
@@ -4338,11 +4456,7 @@ class AnalyticsManager {
4338
4456
  this.maxBatchSize = (_b = options.maxBatchSize) !== null && _b !== void 0 ? _b : 100;
4339
4457
  this.analyticsUrl = (_c = options.analyticsUrl) !== null && _c !== void 0 ? _c : 'https://analytics.ton.org/events';
4340
4458
  this.enabled = (_d = options.enabled) !== null && _d !== void 0 ? _d : true;
4341
- this.baseEvent = {
4342
- subsystem: 'dapp-sdk',
4343
- version: tonConnectSdkVersion,
4344
- client_environment: (_e = options.environment) === null || _e === void 0 ? void 0 : _e.getClientEnvironment()
4345
- };
4459
+ this.baseEvent = Object.assign({ subsystem: 'dapp-sdk', version: tonConnectSdkVersion, client_environment: (_f = (_e = options.environment) === null || _e === void 0 ? void 0 : _e.getClientEnvironment) === null || _f === void 0 ? void 0 : _f.call(_e) }, getStaticConnectionMetrics());
4346
4460
  this.addWindowFocusAndBlurSubscriptions();
4347
4461
  }
4348
4462
  scoped(sharedData) {
@@ -4371,7 +4485,8 @@ class AnalyticsManager {
4371
4485
  return;
4372
4486
  }
4373
4487
  const traceId = (_a = event.trace_id) !== null && _a !== void 0 ? _a : UUIDv7();
4374
- const enhancedEvent = Object.assign(Object.assign(Object.assign({}, this.baseEvent), event), { event_id: UUIDv7(), client_timestamp: Math.floor(Date.now() / 1000), trace_id: traceId });
4488
+ const dynamicMetrics = getDynamicConnectionMetrics();
4489
+ const enhancedEvent = Object.assign(Object.assign(Object.assign(Object.assign({}, this.baseEvent), dynamicMetrics), event), { event_id: UUIDv7(), client_timestamp: Math.floor(Date.now() / 1000), trace_id: traceId });
4375
4490
  if (isQaModeEnabled()) {
4376
4491
  logDebug(enhancedEvent);
4377
4492
  }
@@ -4526,6 +4641,9 @@ class AnalyticsManager {
4526
4641
  getPendingEventsCount() {
4527
4642
  return this.events.length;
4528
4643
  }
4644
+ setWalletListDownloadDuration(duration) {
4645
+ this.baseEvent = Object.assign(Object.assign({}, this.baseEvent), { wallet_list_download_duration: duration });
4646
+ }
4529
4647
  }
4530
4648
  AnalyticsManager.HTTP_STATUS = {
4531
4649
  TOO_MANY_REQUESTS: 429,
@@ -4761,11 +4879,11 @@ function getWalletConnectOptions() {
4761
4879
  const DEFAULT_REQUEST_ID = '0';
4762
4880
  const DEFAULT_EVENT_ID = 0;
4763
4881
  class WalletConnectProvider {
4764
- constructor(storage) {
4882
+ constructor(connectionStorage) {
4883
+ this.connectionStorage = connectionStorage;
4765
4884
  this.type = 'injected';
4766
4885
  this.listeners = [];
4767
4886
  this.connector = undefined;
4768
- this.connectionStorage = new BridgeConnectionStorage(storage);
4769
4887
  const { projectId, metadata } = getWalletConnectOptions();
4770
4888
  this.config = {
4771
4889
  networks: [
@@ -5252,7 +5370,6 @@ class TonConnect {
5252
5370
  }
5253
5371
  constructor(options) {
5254
5372
  var _a, _b;
5255
- this.walletsList = new WalletsListManager();
5256
5373
  this._wallet = null;
5257
5374
  this.provider = null;
5258
5375
  this.statusChangeSubscriptions = [];
@@ -5263,18 +5380,22 @@ class TonConnect {
5263
5380
  storage: (options === null || options === void 0 ? void 0 : options.storage) || new DefaultStorage()
5264
5381
  };
5265
5382
  this.walletsRequiredFeatures = options === null || options === void 0 ? void 0 : options.walletsRequiredFeatures;
5383
+ this.environment = (_a = options === null || options === void 0 ? void 0 : options.environment) !== null && _a !== void 0 ? _a : new DefaultEnvironment();
5384
+ // TODO: in production ready make flag to enable them?
5385
+ this.analytics = new AnalyticsManager({ environment: this.environment });
5266
5386
  this.walletsList = new WalletsListManager({
5267
5387
  walletsListSource: options === null || options === void 0 ? void 0 : options.walletsListSource,
5268
- cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs
5388
+ cacheTTLMs: options === null || options === void 0 ? void 0 : options.walletsListCacheTTLMs,
5389
+ onDownloadDurationMeasured: (duration) => {
5390
+ var _a;
5391
+ (_a = this.analytics) === null || _a === void 0 ? void 0 : _a.setWalletListDownloadDuration(duration);
5392
+ }
5269
5393
  });
5270
- const eventDispatcher = (_a = options === null || options === void 0 ? void 0 : options.eventDispatcher) !== null && _a !== void 0 ? _a : new BrowserEventDispatcher();
5394
+ const eventDispatcher = (_b = options === null || options === void 0 ? void 0 : options.eventDispatcher) !== null && _b !== void 0 ? _b : new BrowserEventDispatcher();
5271
5395
  this.tracker = new TonConnectTracker({
5272
5396
  eventDispatcher,
5273
5397
  tonConnectSdkVersion: tonConnectSdkVersion
5274
5398
  });
5275
- this.environment = (_b = options === null || options === void 0 ? void 0 : options.environment) !== null && _b !== void 0 ? _b : new DefaultEnvironment();
5276
- // TODO: in production ready make flag to enable them?
5277
- this.analytics = new AnalyticsManager({ environment: this.environment });
5278
5399
  const telegramUser = this.environment.getTelegramUser();
5279
5400
  bindEventsTo(eventDispatcher, this.analytics.scoped({
5280
5401
  locale: this.environment.getLocale(),
@@ -5288,7 +5409,7 @@ class TonConnect {
5288
5409
  if (!this.dappSettings.manifestUrl) {
5289
5410
  throw new DappMetadataError('Dapp tonconnect-manifest.json must be specified if window.location.origin is undefined. See more https://github.com/ton-connect/docs/blob/main/requests-responses.md#app-manifest');
5290
5411
  }
5291
- this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage);
5412
+ this.bridgeConnectionStorage = new BridgeConnectionStorage(this.dappSettings.storage, this.walletsList);
5292
5413
  if (!(options === null || options === void 0 ? void 0 : options.disableAutoPauseConnection)) {
5293
5414
  this.addWindowFocusAndBlurSubscriptions();
5294
5415
  }
@@ -5400,13 +5521,13 @@ class TonConnect {
5400
5521
  try {
5401
5522
  switch (bridgeConnectionType) {
5402
5523
  case 'http':
5403
- provider = yield BridgeProvider.fromStorage(this.dappSettings.storage, this.analytics);
5524
+ provider = yield BridgeProvider.fromStorage(this.bridgeConnectionStorage, this.analytics);
5404
5525
  break;
5405
5526
  case 'injected':
5406
- provider = yield InjectedProvider.fromStorage(this.dappSettings.storage, this.analytics);
5527
+ provider = yield InjectedProvider.fromStorage(this.bridgeConnectionStorage, this.analytics);
5407
5528
  break;
5408
5529
  case 'wallet-connect':
5409
- provider = yield WalletConnectProvider.fromStorage(this.dappSettings.storage);
5530
+ provider = yield WalletConnectProvider.fromStorage(this.bridgeConnectionStorage);
5410
5531
  break;
5411
5532
  default:
5412
5533
  if (embeddedWallet) {
@@ -5719,13 +5840,13 @@ class TonConnect {
5719
5840
  createProvider(wallet) {
5720
5841
  let provider;
5721
5842
  if (!Array.isArray(wallet) && isWalletConnectionSourceJS(wallet)) {
5722
- provider = new InjectedProvider(this.dappSettings.storage, wallet.jsBridgeKey, this.analytics);
5843
+ provider = new InjectedProvider(this.bridgeConnectionStorage, wallet.jsBridgeKey, this.analytics);
5723
5844
  }
5724
5845
  else if (!Array.isArray(wallet) && isWalletConnectionSourceWalletConnect(wallet)) {
5725
- provider = new WalletConnectProvider(this.dappSettings.storage);
5846
+ provider = new WalletConnectProvider(this.bridgeConnectionStorage);
5726
5847
  }
5727
5848
  else {
5728
- provider = new BridgeProvider(this.dappSettings.storage, wallet, this.analytics);
5849
+ provider = new BridgeProvider(this.bridgeConnectionStorage, wallet, this.analytics);
5729
5850
  }
5730
5851
  provider.listen(this.walletEventsListener.bind(this));
5731
5852
  return provider;