@tonconnect/sdk 2.2.0 → 3.0.0-beta.1

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
@@ -333,6 +333,15 @@ function isTelegramUrl(link) {
333
333
  const url = new URL(link);
334
334
  return url.protocol === 'tg:' || url.hostname === 't.me';
335
335
  }
336
+ function encodeTelegramUrlParameters(parameters) {
337
+ return parameters
338
+ .replaceAll('.', '%2E')
339
+ .replaceAll('-', '%2D')
340
+ .replaceAll('_', '%5F')
341
+ .replaceAll('&', '-')
342
+ .replaceAll('=', '__')
343
+ .replaceAll('%', '--');
344
+ }
336
345
 
337
346
  class BridgeGateway {
338
347
  constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
@@ -347,7 +356,7 @@ class BridgeGateway {
347
356
  this.isClosed = false;
348
357
  this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
349
358
  }
350
- registerSession() {
359
+ registerSession(options) {
351
360
  return __awaiter(this, void 0, void 0, function* () {
352
361
  const url = new URL(addPathToUrl(this.bridgeUrl, this.ssePath));
353
362
  url.searchParams.append('client_id', this.sessionId);
@@ -360,8 +369,17 @@ class BridgeGateway {
360
369
  }
361
370
  this.eventSource = new EventSource(url.toString());
362
371
  return new Promise((resolve, reject) => {
363
- this.eventSource.onerror = reject;
372
+ const timeout = (options === null || options === void 0 ? void 0 : options.openingDeadlineMS) ? setTimeout(() => {
373
+ var _a;
374
+ if (((_a = this.eventSource) === null || _a === void 0 ? void 0 : _a.readyState) !== EventSource.OPEN) {
375
+ reject(new TonConnectError('Bridge connection timeout'));
376
+ this.close();
377
+ }
378
+ }, options.openingDeadlineMS) : undefined;
379
+ this.eventSource.onerror = () => reject;
364
380
  this.eventSource.onopen = () => {
381
+ clearTimeout(timeout);
382
+ this.isClosed = false;
365
383
  this.eventSource.onerror = this.errorsHandler.bind(this);
366
384
  this.eventSource.onmessage = this.messagesHandler.bind(this);
367
385
  resolve();
@@ -435,6 +453,10 @@ class BridgeGateway {
435
453
  }
436
454
  }
437
455
 
456
+ function isPendingConnectionHttp(connection) {
457
+ return !('connectEvent' in connection);
458
+ }
459
+
438
460
  class BridgeConnectionStorage {
439
461
  constructor(storage) {
440
462
  this.storage = storage;
@@ -445,17 +467,25 @@ class BridgeConnectionStorage {
445
467
  if (connection.type === 'injected') {
446
468
  return this.storage.setItem(this.storeKey, JSON.stringify(connection));
447
469
  }
448
- const rawSession = {
449
- sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
450
- walletPublicKey: connection.session.walletPublicKey,
451
- bridgeUrl: connection.session.bridgeUrl
452
- };
470
+ if (!isPendingConnectionHttp(connection)) {
471
+ const rawSession = {
472
+ sessionKeyPair: connection.session.sessionCrypto.stringifyKeypair(),
473
+ walletPublicKey: connection.session.walletPublicKey,
474
+ bridgeUrl: connection.session.bridgeUrl
475
+ };
476
+ const rawConnection = {
477
+ type: 'http',
478
+ connectEvent: connection.connectEvent,
479
+ session: rawSession,
480
+ lastWalletEventId: connection.lastWalletEventId,
481
+ nextRpcRequestId: connection.nextRpcRequestId
482
+ };
483
+ return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
484
+ }
453
485
  const rawConnection = {
454
486
  type: 'http',
455
- connectEvent: connection.connectEvent,
456
- session: rawSession,
457
- lastWalletEventId: connection.lastWalletEventId,
458
- nextRpcRequestId: connection.nextRpcRequestId
487
+ connectionSource: connection.connectionSource,
488
+ sessionCrypto: connection.sessionCrypto.stringifyKeypair()
459
489
  };
460
490
  return this.storage.setItem(this.storeKey, JSON.stringify(rawConnection));
461
491
  });
@@ -475,17 +505,24 @@ class BridgeConnectionStorage {
475
505
  if (connection.type === 'injected') {
476
506
  return connection;
477
507
  }
478
- const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
508
+ if ('connectEvent' in connection) {
509
+ const sessionCrypto = new protocol.SessionCrypto(connection.session.sessionKeyPair);
510
+ return {
511
+ type: 'http',
512
+ connectEvent: connection.connectEvent,
513
+ lastWalletEventId: connection.lastWalletEventId,
514
+ nextRpcRequestId: connection.nextRpcRequestId,
515
+ session: {
516
+ sessionCrypto,
517
+ bridgeUrl: connection.session.bridgeUrl,
518
+ walletPublicKey: connection.session.walletPublicKey
519
+ }
520
+ };
521
+ }
479
522
  return {
480
523
  type: 'http',
481
- connectEvent: connection.connectEvent,
482
- lastWalletEventId: connection.lastWalletEventId,
483
- nextRpcRequestId: connection.nextRpcRequestId,
484
- session: {
485
- sessionCrypto,
486
- bridgeUrl: connection.session.bridgeUrl,
487
- walletPublicKey: connection.session.walletPublicKey
488
- }
524
+ sessionCrypto: new protocol.SessionCrypto(connection.sessionCrypto),
525
+ connectionSource: connection.connectionSource
489
526
  };
490
527
  });
491
528
  }
@@ -501,6 +538,21 @@ class BridgeConnectionStorage {
501
538
  return connection;
502
539
  });
503
540
  }
541
+ getHttpPendingConnection() {
542
+ return __awaiter(this, void 0, void 0, function* () {
543
+ const connection = yield this.getConnection();
544
+ if (!connection) {
545
+ throw new TonConnectError('Trying to read HTTP connection source while nothing is stored');
546
+ }
547
+ if (connection.type === 'injected') {
548
+ throw new TonConnectError('Trying to read HTTP connection source while injected connection is stored');
549
+ }
550
+ if (!isPendingConnectionHttp(connection)) {
551
+ throw new TonConnectError('Trying to read HTTP-pending connection while http connection is stored');
552
+ }
553
+ return connection;
554
+ });
555
+ }
504
556
  getInjectedConnection() {
505
557
  return __awaiter(this, void 0, void 0, function* () {
506
558
  const connection = yield this.getConnection();
@@ -526,7 +578,7 @@ class BridgeConnectionStorage {
526
578
  storeLastWalletEventId(id) {
527
579
  return __awaiter(this, void 0, void 0, function* () {
528
580
  const connection = yield this.getConnection();
529
- if (connection && connection.type === 'http') {
581
+ if (connection && connection.type === 'http' && !isPendingConnectionHttp(connection)) {
530
582
  connection.lastWalletEventId = id;
531
583
  return this.storeConnection(connection);
532
584
  }
@@ -544,7 +596,7 @@ class BridgeConnectionStorage {
544
596
  increaseNextRpcRequestId() {
545
597
  return __awaiter(this, void 0, void 0, function* () {
546
598
  const connection = yield this.getConnection();
547
- if (connection) {
599
+ if (connection && 'nextRpcRequestId' in connection) {
548
600
  const lastId = connection.nextRpcRequestId || 0;
549
601
  connection.nextRpcRequestId = lastId + 1;
550
602
  return this.storeConnection(connection);
@@ -554,7 +606,7 @@ class BridgeConnectionStorage {
554
606
  getNextRpcRequestId() {
555
607
  return __awaiter(this, void 0, void 0, function* () {
556
608
  const connection = yield this.getConnection();
557
- if (connection) {
609
+ if (connection && 'nextRpcRequestId' in connection) {
558
610
  return connection.nextRpcRequestId || 0;
559
611
  }
560
612
  return 0;
@@ -606,51 +658,62 @@ class BridgeProvider {
606
658
  return __awaiter(this, void 0, void 0, function* () {
607
659
  const bridgeConnectionStorage = new BridgeConnectionStorage(storage);
608
660
  const connection = yield bridgeConnectionStorage.getHttpConnection();
661
+ if (isPendingConnectionHttp(connection)) {
662
+ return new BridgeProvider(storage, connection.connectionSource);
663
+ }
609
664
  return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
610
665
  });
611
666
  }
612
667
  connect(message) {
613
668
  this.closeGateways();
614
669
  const sessionCrypto = new protocol.SessionCrypto();
615
- let bridgeUrl = '';
616
- let universalLink = this.standardUniversalLink;
617
- if (Array.isArray(this.walletConnectionSource)) {
618
- this.pendingGateways = this.walletConnectionSource.map(source => {
619
- const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
620
- console.error(e);
621
- });
622
- gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
623
- return gateway;
624
- });
625
- this.pendingGateways.forEach(bridge => bridge.registerSession());
626
- }
627
- else {
628
- bridgeUrl = this.walletConnectionSource.bridgeUrl;
629
- if (this.walletConnectionSource.universalLink) {
630
- universalLink = this.walletConnectionSource.universalLink;
631
- }
632
- this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
633
- this.gateway.registerSession();
634
- }
635
670
  this.session = {
636
671
  sessionCrypto,
637
- bridgeUrl
672
+ bridgeUrl: 'bridgeUrl' in this.walletConnectionSource
673
+ ? this.walletConnectionSource.bridgeUrl
674
+ : ''
638
675
  };
676
+ this.connectionStorage
677
+ .storeConnection({
678
+ type: 'http',
679
+ connectionSource: this.walletConnectionSource,
680
+ sessionCrypto
681
+ })
682
+ .then(() => this.openGateways(sessionCrypto));
683
+ const universalLink = 'universalLink' in this.walletConnectionSource &&
684
+ this.walletConnectionSource.universalLink
685
+ ? this.walletConnectionSource.universalLink
686
+ : this.standardUniversalLink;
639
687
  return this.generateUniversalLink(universalLink, message);
640
688
  }
641
689
  restoreConnection() {
642
690
  return __awaiter(this, void 0, void 0, function* () {
643
- if (Array.isArray(this.walletConnectionSource)) {
644
- throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
645
- }
646
691
  this.closeGateways();
647
692
  const storedConnection = yield this.connectionStorage.getHttpConnection();
648
693
  if (!storedConnection) {
649
694
  return;
650
695
  }
696
+ if (isPendingConnectionHttp(storedConnection)) {
697
+ this.session = {
698
+ sessionCrypto: storedConnection.sessionCrypto,
699
+ bridgeUrl: 'bridgeUrl' in this.walletConnectionSource
700
+ ? this.walletConnectionSource.bridgeUrl
701
+ : ''
702
+ };
703
+ return this.openGateways(storedConnection.sessionCrypto, { openingDeadlineMS: 5000 });
704
+ }
705
+ if (Array.isArray(this.walletConnectionSource)) {
706
+ throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
707
+ }
651
708
  this.session = storedConnection.session;
652
709
  this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
653
- yield this.gateway.registerSession();
710
+ try {
711
+ yield this.gateway.registerSession({ openingDeadlineMS: 5000 });
712
+ }
713
+ catch (e) {
714
+ yield this.disconnect();
715
+ return;
716
+ }
654
717
  this.listeners.forEach(listener => listener(storedConnection.connectEvent));
655
718
  });
656
719
  }
@@ -805,18 +868,30 @@ class BridgeProvider {
805
868
  generateTGUniversalLink(universalLink, message) {
806
869
  const urlToWrap = this.generateRegularUniversalLink('about:blank', message);
807
870
  const linkParams = urlToWrap.split('?')[1];
808
- const startattach = 'tonconnect-' +
809
- linkParams
810
- .replaceAll('.', '%2E')
811
- .replaceAll('-', '%2D')
812
- .replaceAll('_', '%5F')
813
- .replaceAll('&', '-')
814
- .replaceAll('=', '__')
815
- .replaceAll('%', '--');
871
+ const startattach = 'tonconnect-' + encodeTelegramUrlParameters(linkParams);
816
872
  const url = new URL(universalLink);
817
873
  url.searchParams.append('startattach', startattach);
818
874
  return url.toString();
819
875
  }
876
+ openGateways(sessionCrypto, options) {
877
+ return __awaiter(this, void 0, void 0, function* () {
878
+ if (Array.isArray(this.walletConnectionSource)) {
879
+ this.pendingGateways = this.walletConnectionSource.map(source => {
880
+ const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
881
+ console.error(e);
882
+ });
883
+ gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
884
+ return gateway;
885
+ });
886
+ yield Promise.allSettled(this.pendingGateways.map(bridge => bridge.registerSession(options)));
887
+ return;
888
+ }
889
+ else {
890
+ this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
891
+ return this.gateway.registerSession(options);
892
+ }
893
+ });
894
+ }
820
895
  closeGateways(options) {
821
896
  var _a;
822
897
  (_a = this.gateway) === null || _a === void 0 ? void 0 : _a.close();
@@ -1109,6 +1184,20 @@ function isWalletInfoInjected(value) {
1109
1184
  }
1110
1185
 
1111
1186
  const FALLBACK_WALLETS_LIST = [
1187
+ {
1188
+ app_name: 'telegram-wallet',
1189
+ name: 'Wallet',
1190
+ image: 'https://wallet.tg/images/logo-288.png',
1191
+ about_url: 'https://wallet.tg/',
1192
+ universal_url: 'https://t.me/wallet?attach=wallet',
1193
+ bridge: [
1194
+ {
1195
+ type: 'sse',
1196
+ url: 'https://bridge.tonapi.io/bridge'
1197
+ }
1198
+ ],
1199
+ platforms: ['ios', 'android', 'macos', 'windows', 'linux']
1200
+ },
1112
1201
  {
1113
1202
  app_name: 'tonkeeper',
1114
1203
  name: 'Tonkeeper',
@@ -1235,7 +1324,7 @@ class WalletsListManager {
1235
1324
  constructor(options) {
1236
1325
  this.walletsListCache = null;
1237
1326
  this.walletsListCacheCreationTimestamp = null;
1238
- this.walletsListSource = 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets.json';
1327
+ this.walletsListSource = 'https://raw.githubusercontent.com/ton-blockchain/wallets-list/main/wallets-v2.json';
1239
1328
  if (options === null || options === void 0 ? void 0 : options.walletsListSource) {
1240
1329
  this.walletsListSource = options.walletsListSource;
1241
1330
  }
@@ -1822,7 +1911,8 @@ exports.WalletNotConnectedError = WalletNotConnectedError;
1822
1911
  exports.WalletNotInjectedError = WalletNotInjectedError;
1823
1912
  exports.WalletsListManager = WalletsListManager;
1824
1913
  exports.WrongAddressError = WrongAddressError;
1825
- exports.default = TonConnect;
1914
+ exports["default"] = TonConnect;
1915
+ exports.encodeTelegramUrlParameters = encodeTelegramUrlParameters;
1826
1916
  exports.isTelegramUrl = isTelegramUrl;
1827
1917
  exports.isWalletInfoCurrentlyEmbedded = isWalletInfoCurrentlyEmbedded;
1828
1918
  exports.isWalletInfoCurrentlyInjected = isWalletInfoCurrentlyInjected;