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