@tonconnect/sdk 3.0.0 → 3.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tonconnect-sdk.min.js +1 -1
- package/dist/tonconnect-sdk.min.js.map +1 -1
- package/lib/cjs/index.cjs +538 -154
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.mjs +538 -154
- package/lib/esm/index.mjs.map +1 -1
- package/lib/types/index.d.ts +38 -7
- package/package.json +1 -1
package/lib/esm/index.mjs
CHANGED
|
@@ -343,6 +343,194 @@ function encodeTelegramUrlParameters(parameters) {
|
|
|
343
343
|
.replaceAll('%', '--');
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Creates an AbortController instance with an optional AbortSignal.
|
|
348
|
+
*
|
|
349
|
+
* @param {AbortSignal} [signal] - An optional AbortSignal to use for aborting the controller.
|
|
350
|
+
* @returns {AbortController} - An instance of AbortController.
|
|
351
|
+
*/
|
|
352
|
+
function createAbortController(signal) {
|
|
353
|
+
const abortController = new AbortController();
|
|
354
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
355
|
+
abortController.abort();
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', () => abortController.abort(), { once: true });
|
|
359
|
+
}
|
|
360
|
+
return abortController;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Executes a function and provides deferred behavior, allowing for a timeout and abort functionality.
|
|
364
|
+
*
|
|
365
|
+
* @param {Deferrable<T>} fn - The function to execute. It should return a promise that resolves with the desired result.
|
|
366
|
+
* @param {DeferOptions} options - Optional configuration options for the defer behavior.
|
|
367
|
+
* @returns {Promise<T>} - A promise that resolves with the result of the executed function, or rejects with an error if it times out or is aborted.
|
|
368
|
+
*/
|
|
369
|
+
function defer(fn, options) {
|
|
370
|
+
const timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
371
|
+
const signal = options === null || options === void 0 ? void 0 : options.signal;
|
|
372
|
+
const abortController = createAbortController(signal);
|
|
373
|
+
return new Promise((resolve, reject) => {
|
|
374
|
+
if (abortController.signal.aborted) {
|
|
375
|
+
reject(new TonConnectError('Operation aborted'));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
let timeoutId;
|
|
379
|
+
if (typeof timeout !== 'undefined') {
|
|
380
|
+
timeoutId = setTimeout(() => {
|
|
381
|
+
reject(new TonConnectError(`Timeout after ${timeout}ms`));
|
|
382
|
+
abortController.abort();
|
|
383
|
+
}, timeout);
|
|
384
|
+
}
|
|
385
|
+
abortController.signal.addEventListener('abort', () => {
|
|
386
|
+
clearTimeout(timeoutId);
|
|
387
|
+
reject(new TonConnectError('Operation aborted'));
|
|
388
|
+
}, { once: true });
|
|
389
|
+
const deferOptions = { timeout, abort: abortController.signal };
|
|
390
|
+
fn(resolve, reject, deferOptions).finally(() => clearTimeout(timeoutId));
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Delays the execution of code for a specified number of milliseconds.
|
|
396
|
+
* @param {number} timeout - The number of milliseconds to delay the execution.
|
|
397
|
+
* @param {DelayOptions} [options] - Optional configuration options for the delay.
|
|
398
|
+
* @return {Promise<void>} - A promise that resolves after the specified delay, or rejects if the delay is aborted.
|
|
399
|
+
*/
|
|
400
|
+
function delay(timeout, options) {
|
|
401
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
402
|
+
return yield defer((resolve, reject, options) => __awaiter(this, void 0, void 0, function* () {
|
|
403
|
+
var _a, _b;
|
|
404
|
+
if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
405
|
+
reject(new TonConnectError('Delay aborted'));
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const timeoutId = setTimeout(() => resolve(), timeout);
|
|
409
|
+
(_b = options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', () => {
|
|
410
|
+
clearTimeout(timeoutId);
|
|
411
|
+
reject(new TonConnectError('Delay aborted'));
|
|
412
|
+
});
|
|
413
|
+
}), { signal: options === null || options === void 0 ? void 0 : options.signal });
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Function to call ton api until we get response.
|
|
419
|
+
* Because ton network is pretty unstable we need to make sure response is final.
|
|
420
|
+
* @param {T} fn - function to call
|
|
421
|
+
* @param {CallForSuccessOptions} [options] - optional configuration options
|
|
422
|
+
*/
|
|
423
|
+
function callForSuccess(fn, options) {
|
|
424
|
+
var _a, _b;
|
|
425
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
426
|
+
const attempts = (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : 10;
|
|
427
|
+
const delayMs = (_b = options === null || options === void 0 ? void 0 : options.delayMs) !== null && _b !== void 0 ? _b : 200;
|
|
428
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
429
|
+
if (typeof fn !== 'function') {
|
|
430
|
+
throw new TonConnectError(`Expected a function, got ${typeof fn}`);
|
|
431
|
+
}
|
|
432
|
+
let i = 0;
|
|
433
|
+
let lastError;
|
|
434
|
+
while (i < attempts) {
|
|
435
|
+
if (abortController.signal.aborted) {
|
|
436
|
+
throw new TonConnectError(`Aborted after attempts ${i}`);
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
return yield fn({ signal: abortController.signal });
|
|
440
|
+
}
|
|
441
|
+
catch (err) {
|
|
442
|
+
lastError = err;
|
|
443
|
+
i++;
|
|
444
|
+
yield delay(delayMs);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
throw lastError;
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function logDebug(...args) {
|
|
452
|
+
{
|
|
453
|
+
try {
|
|
454
|
+
console.debug('[TON_CONNECT_SDK]', ...args);
|
|
455
|
+
}
|
|
456
|
+
catch (_a) { }
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function logError(...args) {
|
|
460
|
+
{
|
|
461
|
+
try {
|
|
462
|
+
console.error('[TON_CONNECT_SDK]', ...args);
|
|
463
|
+
}
|
|
464
|
+
catch (_a) { }
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function logWarning(...args) {
|
|
468
|
+
{
|
|
469
|
+
try {
|
|
470
|
+
console.warn('[TON_CONNECT_SDK]', ...args);
|
|
471
|
+
}
|
|
472
|
+
catch (_a) { }
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Create a resource.
|
|
478
|
+
*
|
|
479
|
+
* @template T - The type of the resource.
|
|
480
|
+
* @template Args - The type of the arguments for creating the resource.
|
|
481
|
+
*
|
|
482
|
+
* @param {(...args: Args) => Promise<T>} createFn - A function that creates the resource.
|
|
483
|
+
* @param {(resource: T) => Promise<void>} [disposeFn] - An optional function that disposes the resource.
|
|
484
|
+
*/
|
|
485
|
+
function createResource(createFn, disposeFn) {
|
|
486
|
+
let currentResource = null;
|
|
487
|
+
let currentArgs = null;
|
|
488
|
+
let currentPromise = null;
|
|
489
|
+
let abortController = null;
|
|
490
|
+
// create a new resource
|
|
491
|
+
const create = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
492
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
493
|
+
abortController = createAbortController();
|
|
494
|
+
currentArgs = args;
|
|
495
|
+
const promise = createFn(abortController.signal, ...args);
|
|
496
|
+
currentPromise = promise;
|
|
497
|
+
const resource = yield promise;
|
|
498
|
+
if (currentPromise !== promise) {
|
|
499
|
+
yield disposeFn(resource);
|
|
500
|
+
throw new TonConnectError('Resource creation was aborted by a new resource creation');
|
|
501
|
+
}
|
|
502
|
+
currentResource = resource;
|
|
503
|
+
return currentResource;
|
|
504
|
+
});
|
|
505
|
+
// get the current resource
|
|
506
|
+
const current = () => {
|
|
507
|
+
return currentResource !== null && currentResource !== void 0 ? currentResource : null;
|
|
508
|
+
};
|
|
509
|
+
// dispose the current resource
|
|
510
|
+
const dispose = () => __awaiter(this, void 0, void 0, function* () {
|
|
511
|
+
const resource = currentResource;
|
|
512
|
+
currentResource = null;
|
|
513
|
+
const promise = currentPromise;
|
|
514
|
+
currentPromise = null;
|
|
515
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
516
|
+
yield Promise.allSettled([
|
|
517
|
+
resource ? disposeFn(resource) : Promise.resolve(),
|
|
518
|
+
promise ? disposeFn(yield promise) : Promise.resolve()
|
|
519
|
+
]);
|
|
520
|
+
});
|
|
521
|
+
// recreate the current resource
|
|
522
|
+
const recreate = () => __awaiter(this, void 0, void 0, function* () {
|
|
523
|
+
yield dispose();
|
|
524
|
+
return create(...(currentArgs !== null && currentArgs !== void 0 ? currentArgs : []));
|
|
525
|
+
});
|
|
526
|
+
return {
|
|
527
|
+
create,
|
|
528
|
+
current,
|
|
529
|
+
dispose,
|
|
530
|
+
recreate
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
346
534
|
class BridgeGateway {
|
|
347
535
|
constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
|
|
348
536
|
this.bridgeUrl = bridgeUrl;
|
|
@@ -353,67 +541,77 @@ class BridgeGateway {
|
|
|
353
541
|
this.postPath = 'message';
|
|
354
542
|
this.heartbeatMessage = 'heartbeat';
|
|
355
543
|
this.defaultTtl = 300;
|
|
356
|
-
this.
|
|
544
|
+
this.eventSource = createResource((signal, options) => __awaiter(this, void 0, void 0, function* () {
|
|
545
|
+
const eventSourceConfig = {
|
|
546
|
+
bridgeUrl: this.bridgeUrl,
|
|
547
|
+
ssePath: this.ssePath,
|
|
548
|
+
sessionId: this.sessionId,
|
|
549
|
+
bridgeGatewayStorage: this.bridgeGatewayStorage,
|
|
550
|
+
errorHandler: this.errorsHandler.bind(this),
|
|
551
|
+
messageHandler: this.messagesHandler.bind(this),
|
|
552
|
+
signal: signal
|
|
553
|
+
};
|
|
554
|
+
return yield createEventSource(eventSourceConfig, options);
|
|
555
|
+
}), (resource) => __awaiter(this, void 0, void 0, function* () {
|
|
556
|
+
resource.close();
|
|
557
|
+
}));
|
|
357
558
|
this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
|
|
358
559
|
}
|
|
560
|
+
get isReady() {
|
|
561
|
+
const eventSource = this.eventSource.current();
|
|
562
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
|
|
563
|
+
}
|
|
564
|
+
get isClosed() {
|
|
565
|
+
const eventSource = this.eventSource.current();
|
|
566
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
|
|
567
|
+
}
|
|
568
|
+
get isConnecting() {
|
|
569
|
+
const eventSource = this.eventSource.current();
|
|
570
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
|
|
571
|
+
}
|
|
359
572
|
registerSession(options) {
|
|
360
573
|
return __awaiter(this, void 0, void 0, function* () {
|
|
361
|
-
|
|
362
|
-
url.searchParams.append('client_id', this.sessionId);
|
|
363
|
-
const lastEventId = yield this.bridgeGatewayStorage.getLastEventId();
|
|
364
|
-
if (this.isClosed) {
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
if (lastEventId) {
|
|
368
|
-
url.searchParams.append('last_event_id', lastEventId);
|
|
369
|
-
}
|
|
370
|
-
this.eventSource = new EventSource(url.toString());
|
|
371
|
-
return new Promise((resolve, 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;
|
|
380
|
-
this.eventSource.onopen = () => {
|
|
381
|
-
clearTimeout(timeout);
|
|
382
|
-
this.isClosed = false;
|
|
383
|
-
this.eventSource.onerror = this.errorsHandler.bind(this);
|
|
384
|
-
this.eventSource.onmessage = this.messagesHandler.bind(this);
|
|
385
|
-
resolve();
|
|
386
|
-
};
|
|
387
|
-
});
|
|
574
|
+
yield this.eventSource.create(options);
|
|
388
575
|
});
|
|
389
576
|
}
|
|
390
|
-
send(message, receiver, topic,
|
|
577
|
+
send(message, receiver, topic, ttlOrOptions) {
|
|
391
578
|
return __awaiter(this, void 0, void 0, function* () {
|
|
579
|
+
// TODO: remove deprecated method
|
|
580
|
+
const options = {};
|
|
581
|
+
if (typeof ttlOrOptions === 'number') {
|
|
582
|
+
options.ttl = ttlOrOptions;
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
options.ttl = ttlOrOptions === null || ttlOrOptions === void 0 ? void 0 : ttlOrOptions.ttl;
|
|
586
|
+
options.signal = ttlOrOptions === null || ttlOrOptions === void 0 ? void 0 : ttlOrOptions.signal;
|
|
587
|
+
}
|
|
392
588
|
const url = new URL(addPathToUrl(this.bridgeUrl, this.postPath));
|
|
393
589
|
url.searchParams.append('client_id', this.sessionId);
|
|
394
590
|
url.searchParams.append('to', receiver);
|
|
395
|
-
url.searchParams.append('ttl', (ttl || this.defaultTtl).toString());
|
|
591
|
+
url.searchParams.append('ttl', ((options === null || options === void 0 ? void 0 : options.ttl) || this.defaultTtl).toString());
|
|
396
592
|
url.searchParams.append('topic', topic);
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
body
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
593
|
+
const body = Base64.encode(message);
|
|
594
|
+
yield callForSuccess((options) => __awaiter(this, void 0, void 0, function* () {
|
|
595
|
+
const response = yield this.post(url, body, options.signal);
|
|
596
|
+
if (!response.ok) {
|
|
597
|
+
throw new TonConnectError(`Bridge send failed, status ${response.status}`);
|
|
598
|
+
}
|
|
599
|
+
}), { attempts: Number.MAX_SAFE_INTEGER, delayMs: 5000, signal: options === null || options === void 0 ? void 0 : options.signal });
|
|
404
600
|
});
|
|
405
601
|
}
|
|
406
602
|
pause() {
|
|
407
603
|
var _a;
|
|
408
|
-
(_a = this.eventSource) === null || _a === void 0 ? void 0 : _a.
|
|
604
|
+
(_a = this.eventSource) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
409
605
|
}
|
|
410
606
|
unPause() {
|
|
411
|
-
return this
|
|
607
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
608
|
+
yield this.eventSource.recreate();
|
|
609
|
+
});
|
|
412
610
|
}
|
|
413
611
|
close() {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
612
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
613
|
+
yield this.eventSource.dispose();
|
|
614
|
+
});
|
|
417
615
|
}
|
|
418
616
|
setListener(listener) {
|
|
419
617
|
this.listener = listener;
|
|
@@ -421,20 +619,36 @@ class BridgeGateway {
|
|
|
421
619
|
setErrorsListener(errorsListener) {
|
|
422
620
|
this.errorsListener = errorsListener;
|
|
423
621
|
}
|
|
622
|
+
post(url, body, signal) {
|
|
623
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
624
|
+
const response = yield fetch(url, {
|
|
625
|
+
method: 'post',
|
|
626
|
+
body: body,
|
|
627
|
+
signal: signal
|
|
628
|
+
});
|
|
629
|
+
if (!response.ok) {
|
|
630
|
+
throw new TonConnectError(`Bridge send failed, status ${response.status}`);
|
|
631
|
+
}
|
|
632
|
+
return response;
|
|
633
|
+
});
|
|
634
|
+
}
|
|
424
635
|
errorsHandler(e) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
this.eventSource.close();
|
|
429
|
-
this.registerSession();
|
|
636
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
637
|
+
if (this.isConnecting) {
|
|
638
|
+
logError('Bridge error', JSON.stringify(e));
|
|
430
639
|
return;
|
|
431
640
|
}
|
|
432
|
-
if (
|
|
433
|
-
|
|
641
|
+
if (this.isReady) {
|
|
642
|
+
this.errorsListener(e);
|
|
434
643
|
return;
|
|
435
644
|
}
|
|
436
|
-
this.
|
|
437
|
-
|
|
645
|
+
if (this.isClosed) {
|
|
646
|
+
logDebug('Bridge reconnecting, 200ms delay');
|
|
647
|
+
yield delay(200);
|
|
648
|
+
yield this.eventSource.recreate();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
});
|
|
438
652
|
}
|
|
439
653
|
messagesHandler(e) {
|
|
440
654
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -442,19 +656,66 @@ class BridgeGateway {
|
|
|
442
656
|
return;
|
|
443
657
|
}
|
|
444
658
|
yield this.bridgeGatewayStorage.storeLastEventId(e.lastEventId);
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
659
|
+
if (this.isClosed) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
let bridgeIncomingMessage;
|
|
663
|
+
try {
|
|
664
|
+
bridgeIncomingMessage = JSON.parse(e.data);
|
|
665
|
+
}
|
|
666
|
+
catch (e) {
|
|
667
|
+
throw new TonConnectError(`Bridge message parse failed, message ${e.data}`);
|
|
454
668
|
}
|
|
669
|
+
this.listener(bridgeIncomingMessage);
|
|
455
670
|
});
|
|
456
671
|
}
|
|
457
672
|
}
|
|
673
|
+
function createEventSource(config, options) {
|
|
674
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
675
|
+
return yield defer((resolve, reject, deferOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
676
|
+
var _a;
|
|
677
|
+
const abortController = createAbortController(deferOptions.signal);
|
|
678
|
+
const signal = abortController.signal;
|
|
679
|
+
if (signal.aborted) {
|
|
680
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const url = new URL(addPathToUrl(config.bridgeUrl, config.ssePath));
|
|
684
|
+
url.searchParams.append('client_id', config.sessionId);
|
|
685
|
+
const lastEventId = yield config.bridgeGatewayStorage.getLastEventId();
|
|
686
|
+
if (lastEventId) {
|
|
687
|
+
url.searchParams.append('last_event_id', lastEventId);
|
|
688
|
+
}
|
|
689
|
+
if (signal.aborted) {
|
|
690
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const eventSource = new EventSource(url.toString());
|
|
694
|
+
eventSource.onerror = (reason) => {
|
|
695
|
+
if (signal.aborted) {
|
|
696
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
config.errorHandler(reason);
|
|
700
|
+
};
|
|
701
|
+
eventSource.onopen = () => {
|
|
702
|
+
if (signal.aborted) {
|
|
703
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
resolve(eventSource);
|
|
707
|
+
};
|
|
708
|
+
eventSource.onmessage = (event) => {
|
|
709
|
+
config.messageHandler(event);
|
|
710
|
+
};
|
|
711
|
+
(_a = config === null || config === void 0 ? void 0 : config.signal) === null || _a === void 0 ? void 0 : _a.addEventListener('abort', () => {
|
|
712
|
+
logError('Bridge connection aborted');
|
|
713
|
+
eventSource.close();
|
|
714
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
715
|
+
});
|
|
716
|
+
}), { timeout: options === null || options === void 0 ? void 0 : options.openingDeadlineMS, signal: config === null || config === void 0 ? void 0 : config.signal });
|
|
717
|
+
});
|
|
718
|
+
}
|
|
458
719
|
|
|
459
720
|
function isPendingConnectionHttp(connection) {
|
|
460
721
|
return !('connectEvent' in connection);
|
|
@@ -619,31 +880,6 @@ class BridgeConnectionStorage {
|
|
|
619
880
|
|
|
620
881
|
const PROTOCOL_VERSION = 2;
|
|
621
882
|
|
|
622
|
-
function logDebug(...args) {
|
|
623
|
-
{
|
|
624
|
-
try {
|
|
625
|
-
console.debug('[TON_CONNECT_SDK]', ...args);
|
|
626
|
-
}
|
|
627
|
-
catch (_a) { }
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
function logError(...args) {
|
|
631
|
-
{
|
|
632
|
-
try {
|
|
633
|
-
console.error('[TON_CONNECT_SDK]', ...args);
|
|
634
|
-
}
|
|
635
|
-
catch (_a) { }
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
function logWarning(...args) {
|
|
639
|
-
{
|
|
640
|
-
try {
|
|
641
|
-
console.warn('[TON_CONNECT_SDK]', ...args);
|
|
642
|
-
}
|
|
643
|
-
catch (_a) { }
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
883
|
class BridgeProvider {
|
|
648
884
|
constructor(storage, walletConnectionSource) {
|
|
649
885
|
this.storage = storage;
|
|
@@ -655,6 +891,7 @@ class BridgeProvider {
|
|
|
655
891
|
this.gateway = null;
|
|
656
892
|
this.pendingGateways = [];
|
|
657
893
|
this.listeners = [];
|
|
894
|
+
this.defaultOpeningDeadlineMS = 5000;
|
|
658
895
|
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
659
896
|
}
|
|
660
897
|
static fromStorage(storage) {
|
|
@@ -667,7 +904,7 @@ class BridgeProvider {
|
|
|
667
904
|
return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
|
|
668
905
|
});
|
|
669
906
|
}
|
|
670
|
-
connect(message) {
|
|
907
|
+
connect(message, options) {
|
|
671
908
|
this.closeGateways();
|
|
672
909
|
const sessionCrypto = new SessionCrypto();
|
|
673
910
|
this.session = {
|
|
@@ -682,20 +919,40 @@ class BridgeProvider {
|
|
|
682
919
|
connectionSource: this.walletConnectionSource,
|
|
683
920
|
sessionCrypto
|
|
684
921
|
})
|
|
685
|
-
.then(() => this
|
|
922
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
923
|
+
yield callForSuccess(_options => this.openGateways(sessionCrypto, {
|
|
924
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
925
|
+
signal: _options === null || _options === void 0 ? void 0 : _options.signal
|
|
926
|
+
}), {
|
|
927
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
928
|
+
delayMs: 5000,
|
|
929
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
930
|
+
});
|
|
931
|
+
}));
|
|
686
932
|
const universalLink = 'universalLink' in this.walletConnectionSource &&
|
|
687
933
|
this.walletConnectionSource.universalLink
|
|
688
934
|
? this.walletConnectionSource.universalLink
|
|
689
935
|
: this.standardUniversalLink;
|
|
690
936
|
return this.generateUniversalLink(universalLink, message);
|
|
691
937
|
}
|
|
692
|
-
restoreConnection() {
|
|
938
|
+
restoreConnection(options) {
|
|
939
|
+
var _a, _b;
|
|
693
940
|
return __awaiter(this, void 0, void 0, function* () {
|
|
941
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
942
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
943
|
+
this.abortController = abortController;
|
|
944
|
+
if (abortController.signal.aborted) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
694
947
|
this.closeGateways();
|
|
695
948
|
const storedConnection = yield this.connectionStorage.getHttpConnection();
|
|
696
949
|
if (!storedConnection) {
|
|
697
950
|
return;
|
|
698
951
|
}
|
|
952
|
+
if (abortController.signal.aborted) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
const openingDeadlineMS = (_b = options === null || options === void 0 ? void 0 : options.openingDeadlineMS) !== null && _b !== void 0 ? _b : this.defaultOpeningDeadlineMS;
|
|
699
956
|
if (isPendingConnectionHttp(storedConnection)) {
|
|
700
957
|
this.session = {
|
|
701
958
|
sessionCrypto: storedConnection.sessionCrypto,
|
|
@@ -703,25 +960,54 @@ class BridgeProvider {
|
|
|
703
960
|
? this.walletConnectionSource.bridgeUrl
|
|
704
961
|
: ''
|
|
705
962
|
};
|
|
706
|
-
return this.openGateways(storedConnection.sessionCrypto, {
|
|
963
|
+
return yield this.openGateways(storedConnection.sessionCrypto, {
|
|
964
|
+
openingDeadlineMS: openingDeadlineMS,
|
|
965
|
+
signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal
|
|
966
|
+
});
|
|
707
967
|
}
|
|
708
968
|
if (Array.isArray(this.walletConnectionSource)) {
|
|
709
969
|
throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
|
|
710
970
|
}
|
|
711
971
|
this.session = storedConnection.session;
|
|
972
|
+
if (this.gateway) {
|
|
973
|
+
logDebug('Gateway is already opened, closing previous gateway');
|
|
974
|
+
yield this.gateway.close();
|
|
975
|
+
}
|
|
712
976
|
this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
|
|
977
|
+
if (abortController.signal.aborted) {
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
// notify listeners about stored connection
|
|
981
|
+
this.listeners.forEach(listener => listener(storedConnection.connectEvent));
|
|
982
|
+
// wait for the connection to be opened
|
|
713
983
|
try {
|
|
714
|
-
yield this.gateway.registerSession({
|
|
984
|
+
yield callForSuccess(options => this.gateway.registerSession({
|
|
985
|
+
openingDeadlineMS: openingDeadlineMS,
|
|
986
|
+
signal: options.signal
|
|
987
|
+
}), {
|
|
988
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
989
|
+
delayMs: 5000,
|
|
990
|
+
signal: abortController.signal
|
|
991
|
+
});
|
|
715
992
|
}
|
|
716
993
|
catch (e) {
|
|
717
|
-
yield this.disconnect();
|
|
994
|
+
yield this.disconnect({ signal: abortController.signal });
|
|
718
995
|
return;
|
|
719
996
|
}
|
|
720
|
-
this.listeners.forEach(listener => listener(storedConnection.connectEvent));
|
|
721
997
|
});
|
|
722
998
|
}
|
|
723
|
-
sendRequest(request,
|
|
999
|
+
sendRequest(request, optionsOrOnRequestSent) {
|
|
1000
|
+
// TODO: remove deprecated method
|
|
1001
|
+
const options = {};
|
|
1002
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
1003
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
1004
|
+
}
|
|
1005
|
+
else {
|
|
1006
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
1007
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
1008
|
+
}
|
|
724
1009
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
1010
|
+
var _a;
|
|
725
1011
|
if (!this.gateway || !this.session || !('walletPublicKey' in this.session)) {
|
|
726
1012
|
throw new TonConnectError('Trying to send bridge request without session');
|
|
727
1013
|
}
|
|
@@ -730,8 +1016,8 @@ class BridgeProvider {
|
|
|
730
1016
|
logDebug('Send http-bridge request:', Object.assign(Object.assign({}, request), { id }));
|
|
731
1017
|
const encodedRequest = this.session.sessionCrypto.encrypt(JSON.stringify(Object.assign(Object.assign({}, request), { id })), hexToByteArray(this.session.walletPublicKey));
|
|
732
1018
|
try {
|
|
733
|
-
yield this.gateway.send(encodedRequest, this.session.walletPublicKey, request.method);
|
|
734
|
-
|
|
1019
|
+
yield this.gateway.send(encodedRequest, this.session.walletPublicKey, request.method, { signal: options === null || options === void 0 ? void 0 : options.signal });
|
|
1020
|
+
(_a = options === null || options === void 0 ? void 0 : options.onRequestSent) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
735
1021
|
this.pendingRequests.set(id.toString(), resolve);
|
|
736
1022
|
}
|
|
737
1023
|
catch (e) {
|
|
@@ -745,7 +1031,7 @@ class BridgeProvider {
|
|
|
745
1031
|
this.session = null;
|
|
746
1032
|
this.gateway = null;
|
|
747
1033
|
}
|
|
748
|
-
disconnect() {
|
|
1034
|
+
disconnect(options) {
|
|
749
1035
|
return __awaiter(this, void 0, void 0, function* () {
|
|
750
1036
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
751
1037
|
let called = false;
|
|
@@ -754,10 +1040,14 @@ class BridgeProvider {
|
|
|
754
1040
|
this.removeBridgeAndSession().then(resolve);
|
|
755
1041
|
};
|
|
756
1042
|
try {
|
|
757
|
-
|
|
1043
|
+
this.closeGateways();
|
|
1044
|
+
yield this.sendRequest({ method: 'disconnect', params: [] }, {
|
|
1045
|
+
onRequestSent: onRequestSent,
|
|
1046
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
1047
|
+
});
|
|
758
1048
|
}
|
|
759
1049
|
catch (e) {
|
|
760
|
-
|
|
1050
|
+
logDebug('Disconnect error:', e);
|
|
761
1051
|
if (!called) {
|
|
762
1052
|
this.removeBridgeAndSession().then(resolve);
|
|
763
1053
|
}
|
|
@@ -786,10 +1076,14 @@ class BridgeProvider {
|
|
|
786
1076
|
pendingGatewaysListener(gateway, bridgeUrl, bridgeIncomingMessage) {
|
|
787
1077
|
return __awaiter(this, void 0, void 0, function* () {
|
|
788
1078
|
if (!this.pendingGateways.includes(gateway)) {
|
|
789
|
-
gateway.close();
|
|
1079
|
+
yield gateway.close();
|
|
790
1080
|
return;
|
|
791
1081
|
}
|
|
792
1082
|
this.closeGateways({ except: gateway });
|
|
1083
|
+
if (this.gateway) {
|
|
1084
|
+
logDebug('Gateway is already opened, closing previous gateway');
|
|
1085
|
+
yield this.gateway.close();
|
|
1086
|
+
}
|
|
793
1087
|
this.session.bridgeUrl = bridgeUrl;
|
|
794
1088
|
this.gateway = gateway;
|
|
795
1089
|
this.gateway.setErrorsListener(this.gatewayErrorsListener.bind(this));
|
|
@@ -828,6 +1122,7 @@ class BridgeProvider {
|
|
|
828
1122
|
yield this.updateSession(walletMessage, bridgeIncomingMessage.from);
|
|
829
1123
|
}
|
|
830
1124
|
if (walletMessage.event === 'disconnect') {
|
|
1125
|
+
logDebug(`Removing bridge and session: received disconnect event`);
|
|
831
1126
|
yield this.removeBridgeAndSession();
|
|
832
1127
|
}
|
|
833
1128
|
listeners.forEach(listener => listener(walletMessage));
|
|
@@ -891,8 +1186,15 @@ class BridgeProvider {
|
|
|
891
1186
|
return url.toString();
|
|
892
1187
|
}
|
|
893
1188
|
openGateways(sessionCrypto, options) {
|
|
1189
|
+
var _a;
|
|
894
1190
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1191
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
1192
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
1193
|
+
this.abortController = abortController;
|
|
895
1194
|
if (Array.isArray(this.walletConnectionSource)) {
|
|
1195
|
+
// close all gateways before opening new ones
|
|
1196
|
+
this.pendingGateways.map(bridge => bridge.close().catch(e => console.error(e)));
|
|
1197
|
+
// open new gateways
|
|
896
1198
|
this.pendingGateways = this.walletConnectionSource.map(source => {
|
|
897
1199
|
const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
|
|
898
1200
|
console.error(e);
|
|
@@ -900,12 +1202,28 @@ class BridgeProvider {
|
|
|
900
1202
|
gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
|
|
901
1203
|
return gateway;
|
|
902
1204
|
});
|
|
903
|
-
yield Promise.allSettled(this.pendingGateways.map(bridge =>
|
|
1205
|
+
yield Promise.allSettled(this.pendingGateways.map(bridge => callForSuccess((_options) => {
|
|
1206
|
+
return bridge.registerSession({
|
|
1207
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
1208
|
+
signal: _options.signal
|
|
1209
|
+
});
|
|
1210
|
+
}, {
|
|
1211
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
1212
|
+
delayMs: 5000,
|
|
1213
|
+
signal: abortController.signal
|
|
1214
|
+
})));
|
|
904
1215
|
return;
|
|
905
1216
|
}
|
|
906
1217
|
else {
|
|
1218
|
+
if (this.gateway) {
|
|
1219
|
+
logDebug(`Gateway is already opened, closing previous gateway`);
|
|
1220
|
+
yield this.gateway.close();
|
|
1221
|
+
}
|
|
907
1222
|
this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
|
|
908
|
-
return this.gateway.registerSession(
|
|
1223
|
+
return yield this.gateway.registerSession({
|
|
1224
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
1225
|
+
signal: abortController.signal
|
|
1226
|
+
});
|
|
909
1227
|
}
|
|
910
1228
|
});
|
|
911
1229
|
}
|
|
@@ -1168,14 +1486,24 @@ class InjectedProvider {
|
|
|
1168
1486
|
this.listeners.push(eventsCallback);
|
|
1169
1487
|
return () => (this.listeners = this.listeners.filter(listener => listener !== eventsCallback));
|
|
1170
1488
|
}
|
|
1171
|
-
sendRequest(request,
|
|
1489
|
+
sendRequest(request, optionsOrOnRequestSent) {
|
|
1490
|
+
var _a;
|
|
1172
1491
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1492
|
+
// TODO: remove deprecated method
|
|
1493
|
+
const options = {};
|
|
1494
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
1495
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
1496
|
+
}
|
|
1497
|
+
else {
|
|
1498
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
1499
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
1500
|
+
}
|
|
1173
1501
|
const id = (yield this.connectionStorage.getNextRpcRequestId()).toString();
|
|
1174
1502
|
yield this.connectionStorage.increaseNextRpcRequestId();
|
|
1175
1503
|
logDebug('Send injected-bridge request:', Object.assign(Object.assign({}, request), { id }));
|
|
1176
1504
|
const result = this.injectedWallet.send(Object.assign(Object.assign({}, request), { id }));
|
|
1177
1505
|
result.then(response => logDebug('Wallet message received:', response));
|
|
1178
|
-
|
|
1506
|
+
(_a = options === null || options === void 0 ? void 0 : options.onRequestSent) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
1179
1507
|
return result;
|
|
1180
1508
|
});
|
|
1181
1509
|
}
|
|
@@ -1192,7 +1520,7 @@ class InjectedProvider {
|
|
|
1192
1520
|
this.listeners.forEach(listener => listener(connectEvent));
|
|
1193
1521
|
}
|
|
1194
1522
|
catch (e) {
|
|
1195
|
-
logDebug(e);
|
|
1523
|
+
logDebug('Injected Provider connect error:', e);
|
|
1196
1524
|
const connectEventError = {
|
|
1197
1525
|
event: 'connect_error',
|
|
1198
1526
|
payload: {
|
|
@@ -1321,19 +1649,6 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1321
1649
|
],
|
|
1322
1650
|
platforms: ['ios', 'android', 'chrome', 'firefox', 'macos']
|
|
1323
1651
|
},
|
|
1324
|
-
{
|
|
1325
|
-
app_name: 'openmask',
|
|
1326
|
-
name: 'OpenMask',
|
|
1327
|
-
image: 'https://raw.githubusercontent.com/OpenProduct/openmask-extension/main/public/openmask-logo-288.png',
|
|
1328
|
-
about_url: 'https://www.openmask.app/',
|
|
1329
|
-
bridge: [
|
|
1330
|
-
{
|
|
1331
|
-
type: 'js',
|
|
1332
|
-
key: 'openmask'
|
|
1333
|
-
}
|
|
1334
|
-
],
|
|
1335
|
-
platforms: ['chrome']
|
|
1336
|
-
},
|
|
1337
1652
|
{
|
|
1338
1653
|
app_name: 'mytonwallet',
|
|
1339
1654
|
name: 'MyTonWallet',
|
|
@@ -1350,7 +1665,20 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1350
1665
|
url: 'https://tonconnectbridge.mytonwallet.org/bridge/'
|
|
1351
1666
|
}
|
|
1352
1667
|
],
|
|
1353
|
-
platforms: ['chrome', 'windows', 'macos', 'linux']
|
|
1668
|
+
platforms: ['chrome', 'windows', 'macos', 'linux', 'ios', 'android', 'firefox']
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
app_name: 'openmask',
|
|
1672
|
+
name: 'OpenMask',
|
|
1673
|
+
image: 'https://raw.githubusercontent.com/OpenProduct/openmask-extension/main/public/openmask-logo-288.png',
|
|
1674
|
+
about_url: 'https://www.openmask.app/',
|
|
1675
|
+
bridge: [
|
|
1676
|
+
{
|
|
1677
|
+
type: 'js',
|
|
1678
|
+
key: 'openmask'
|
|
1679
|
+
}
|
|
1680
|
+
],
|
|
1681
|
+
platforms: ['chrome']
|
|
1354
1682
|
},
|
|
1355
1683
|
{
|
|
1356
1684
|
app_name: 'tonhub',
|
|
@@ -1370,19 +1698,6 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1370
1698
|
],
|
|
1371
1699
|
platforms: ['ios', 'android']
|
|
1372
1700
|
},
|
|
1373
|
-
{
|
|
1374
|
-
app_name: 'tonflow',
|
|
1375
|
-
name: 'TonFlow',
|
|
1376
|
-
image: 'https://tonflow.net/assets/images/tonflow_ico_192.png',
|
|
1377
|
-
about_url: 'https://tonflow.net',
|
|
1378
|
-
bridge: [
|
|
1379
|
-
{
|
|
1380
|
-
type: 'js',
|
|
1381
|
-
key: 'tonflow'
|
|
1382
|
-
}
|
|
1383
|
-
],
|
|
1384
|
-
platforms: ['chrome']
|
|
1385
|
-
},
|
|
1386
1701
|
{
|
|
1387
1702
|
app_name: 'dewallet',
|
|
1388
1703
|
name: 'DeWallet',
|
|
@@ -1689,59 +2004,119 @@ class TonConnect {
|
|
|
1689
2004
|
}
|
|
1690
2005
|
};
|
|
1691
2006
|
}
|
|
1692
|
-
connect(wallet,
|
|
1693
|
-
var _a;
|
|
2007
|
+
connect(wallet, requestOrOptions) {
|
|
2008
|
+
var _a, _b;
|
|
2009
|
+
// TODO: remove deprecated method
|
|
2010
|
+
const options = {};
|
|
2011
|
+
if (typeof requestOrOptions === 'object' && 'tonProof' in requestOrOptions) {
|
|
2012
|
+
options.request = requestOrOptions;
|
|
2013
|
+
}
|
|
2014
|
+
if (typeof requestOrOptions === 'object' &&
|
|
2015
|
+
('openingDeadlineMS' in requestOrOptions ||
|
|
2016
|
+
'signal' in requestOrOptions ||
|
|
2017
|
+
'request' in requestOrOptions)) {
|
|
2018
|
+
options.request = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.request;
|
|
2019
|
+
options.openingDeadlineMS = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.openingDeadlineMS;
|
|
2020
|
+
options.signal = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.signal;
|
|
2021
|
+
}
|
|
1694
2022
|
if (this.connected) {
|
|
1695
2023
|
throw new WalletAlreadyConnectedError();
|
|
1696
2024
|
}
|
|
1697
|
-
|
|
2025
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2026
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
2027
|
+
this.abortController = abortController;
|
|
2028
|
+
if (abortController.signal.aborted) {
|
|
2029
|
+
throw new TonConnectError('Connection was aborted');
|
|
2030
|
+
}
|
|
2031
|
+
(_b = this.provider) === null || _b === void 0 ? void 0 : _b.closeConnection();
|
|
1698
2032
|
this.provider = this.createProvider(wallet);
|
|
1699
|
-
return this.provider.connect(this.createConnectRequest(request)
|
|
2033
|
+
return this.provider.connect(this.createConnectRequest(options === null || options === void 0 ? void 0 : options.request), {
|
|
2034
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
2035
|
+
signal: abortController.signal
|
|
2036
|
+
});
|
|
1700
2037
|
}
|
|
1701
2038
|
/**
|
|
1702
2039
|
* Try to restore existing session and reconnect to the corresponding wallet. Call it immediately when your app is loaded.
|
|
1703
2040
|
*/
|
|
1704
|
-
restoreConnection() {
|
|
2041
|
+
restoreConnection(options) {
|
|
2042
|
+
var _a, _b;
|
|
1705
2043
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2044
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2045
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
2046
|
+
this.abortController = abortController;
|
|
2047
|
+
if (abortController.signal.aborted) {
|
|
2048
|
+
return;
|
|
2049
|
+
}
|
|
2050
|
+
// TODO: potentially race condition here
|
|
1706
2051
|
const [bridgeConnectionType, embeddedWallet] = yield Promise.all([
|
|
1707
2052
|
this.bridgeConnectionStorage.storedConnectionType(),
|
|
1708
2053
|
this.walletsList.getEmbeddedWallet()
|
|
1709
2054
|
]);
|
|
2055
|
+
if (abortController.signal.aborted) {
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
let provider = null;
|
|
1710
2059
|
try {
|
|
1711
2060
|
switch (bridgeConnectionType) {
|
|
1712
2061
|
case 'http':
|
|
1713
|
-
|
|
2062
|
+
provider = yield BridgeProvider.fromStorage(this.dappSettings.storage);
|
|
1714
2063
|
break;
|
|
1715
2064
|
case 'injected':
|
|
1716
|
-
|
|
2065
|
+
provider = yield InjectedProvider.fromStorage(this.dappSettings.storage);
|
|
1717
2066
|
break;
|
|
1718
2067
|
default:
|
|
1719
2068
|
if (embeddedWallet) {
|
|
1720
|
-
|
|
2069
|
+
provider = this.createProvider(embeddedWallet);
|
|
1721
2070
|
}
|
|
1722
2071
|
else {
|
|
1723
2072
|
return;
|
|
1724
2073
|
}
|
|
1725
2074
|
}
|
|
1726
2075
|
}
|
|
1727
|
-
catch (
|
|
2076
|
+
catch (_c) {
|
|
1728
2077
|
yield this.bridgeConnectionStorage.removeConnection();
|
|
1729
|
-
|
|
2078
|
+
provider === null || provider === void 0 ? void 0 : provider.closeConnection();
|
|
2079
|
+
provider = null;
|
|
1730
2080
|
return;
|
|
1731
2081
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
2082
|
+
if (abortController.signal.aborted) {
|
|
2083
|
+
provider === null || provider === void 0 ? void 0 : provider.closeConnection();
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
if (!provider) {
|
|
2087
|
+
logError('Provider is not restored');
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
(_b = this.provider) === null || _b === void 0 ? void 0 : _b.closeConnection();
|
|
2091
|
+
this.provider = provider;
|
|
2092
|
+
provider.listen(this.walletEventsListener.bind(this));
|
|
2093
|
+
return yield callForSuccess((_options) => __awaiter(this, void 0, void 0, function* () {
|
|
2094
|
+
return provider === null || provider === void 0 ? void 0 : provider.restoreConnection({
|
|
2095
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
2096
|
+
signal: _options.signal
|
|
2097
|
+
});
|
|
2098
|
+
}), {
|
|
2099
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
2100
|
+
delayMs: 5000,
|
|
2101
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
2102
|
+
});
|
|
1734
2103
|
});
|
|
1735
2104
|
}
|
|
1736
|
-
|
|
1737
|
-
* Asks connected wallet to sign and send the transaction.
|
|
1738
|
-
* @param transaction transaction to send.
|
|
1739
|
-
* @param onRequestSent (optional) will be called after the transaction is sent to the wallet.
|
|
1740
|
-
* @returns signed transaction boc that allows you to find the transaction in the blockchain.
|
|
1741
|
-
* If user rejects transaction, method will throw the corresponding error.
|
|
1742
|
-
*/
|
|
1743
|
-
sendTransaction(transaction, onRequestSent) {
|
|
2105
|
+
sendTransaction(transaction, optionsOrOnRequestSent) {
|
|
1744
2106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2107
|
+
// TODO: remove deprecated method
|
|
2108
|
+
const options = {};
|
|
2109
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
2110
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
2111
|
+
}
|
|
2112
|
+
else {
|
|
2113
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
2114
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
2115
|
+
}
|
|
2116
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2117
|
+
if (abortController.signal.aborted) {
|
|
2118
|
+
throw new TonConnectError('Transaction sending was aborted');
|
|
2119
|
+
}
|
|
1745
2120
|
this.checkConnection();
|
|
1746
2121
|
checkSendTransactionSupport(this.wallet.device.features, {
|
|
1747
2122
|
requiredMessagesNumber: transaction.messages.length
|
|
@@ -1750,7 +2125,7 @@ class TonConnect {
|
|
|
1750
2125
|
const from = transaction.from || this.account.address;
|
|
1751
2126
|
const network = transaction.network || this.account.chain;
|
|
1752
2127
|
const response = yield this.provider.sendRequest(sendTransactionParser.convertToRpcRequest(Object.assign(Object.assign({}, tx), { valid_until: validUntil, from,
|
|
1753
|
-
network })), onRequestSent);
|
|
2128
|
+
network })), { onRequestSent: options.onRequestSent, signal: abortController.signal });
|
|
1754
2129
|
if (sendTransactionParser.isError(response)) {
|
|
1755
2130
|
return sendTransactionParser.parseAndThrowError(response);
|
|
1756
2131
|
}
|
|
@@ -1760,13 +2135,22 @@ class TonConnect {
|
|
|
1760
2135
|
/**
|
|
1761
2136
|
* Disconnect form thw connected wallet and drop current session.
|
|
1762
2137
|
*/
|
|
1763
|
-
disconnect() {
|
|
2138
|
+
disconnect(options) {
|
|
2139
|
+
var _a, _b;
|
|
1764
2140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1765
2141
|
if (!this.connected) {
|
|
1766
2142
|
throw new WalletNotConnectedError();
|
|
1767
2143
|
}
|
|
1768
|
-
|
|
2144
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2145
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
2146
|
+
this.abortController = abortController;
|
|
2147
|
+
if (abortController.signal.aborted) {
|
|
2148
|
+
throw new TonConnectError('Disconnect was aborted');
|
|
2149
|
+
}
|
|
1769
2150
|
this.onWalletDisconnected();
|
|
2151
|
+
yield ((_b = this.provider) === null || _b === void 0 ? void 0 : _b.disconnect({
|
|
2152
|
+
signal: abortController.signal
|
|
2153
|
+
}));
|
|
1770
2154
|
});
|
|
1771
2155
|
}
|
|
1772
2156
|
/**
|