@tonconnect/sdk 3.0.0 → 3.0.1-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/dist/tonconnect-sdk.min.js +1 -1
- package/dist/tonconnect-sdk.min.js.map +1 -1
- package/lib/cjs/index.cjs +614 -161
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/index.mjs +614 -161
- 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,217 @@ function encodeTelegramUrlParameters(parameters) {
|
|
|
343
343
|
.replaceAll('%', '--');
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Delays the execution of code for a specified number of milliseconds.
|
|
348
|
+
* @param {number} timeout - The number of milliseconds to delay the execution.
|
|
349
|
+
* @param {DelayOptions} [options] - Optional configuration options for the delay.
|
|
350
|
+
* @return {Promise<void>} - A promise that resolves after the specified delay, or rejects if the delay is aborted.
|
|
351
|
+
*/
|
|
352
|
+
function delay(timeout, options) {
|
|
353
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
354
|
+
return new Promise((resolve, reject) => {
|
|
355
|
+
var _a, _b;
|
|
356
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
357
|
+
reject(new TonConnectError('Delay aborted'));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const timeoutId = setTimeout(() => resolve(), timeout);
|
|
361
|
+
(_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener('abort', () => {
|
|
362
|
+
clearTimeout(timeoutId);
|
|
363
|
+
reject(new TonConnectError('Delay aborted'));
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Creates an AbortController instance with an optional AbortSignal.
|
|
371
|
+
*
|
|
372
|
+
* @param {AbortSignal} [signal] - An optional AbortSignal to use for aborting the controller.
|
|
373
|
+
* @returns {AbortController} - An instance of AbortController.
|
|
374
|
+
*/
|
|
375
|
+
function createAbortController(signal) {
|
|
376
|
+
const abortController = new AbortController();
|
|
377
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
378
|
+
abortController.abort();
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', () => abortController.abort(), { once: true });
|
|
382
|
+
}
|
|
383
|
+
return abortController;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Function to call ton api until we get response.
|
|
388
|
+
* Because ton network is pretty unstable we need to make sure response is final.
|
|
389
|
+
* @param {T} fn - function to call
|
|
390
|
+
* @param {CallForSuccessOptions} [options] - optional configuration options
|
|
391
|
+
*/
|
|
392
|
+
function callForSuccess(fn, options) {
|
|
393
|
+
var _a, _b;
|
|
394
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
395
|
+
const attempts = (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : 10;
|
|
396
|
+
const delayMs = (_b = options === null || options === void 0 ? void 0 : options.delayMs) !== null && _b !== void 0 ? _b : 200;
|
|
397
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
398
|
+
if (typeof fn !== 'function') {
|
|
399
|
+
throw new TonConnectError(`Expected a function, got ${typeof fn}`);
|
|
400
|
+
}
|
|
401
|
+
let i = 0;
|
|
402
|
+
let lastError;
|
|
403
|
+
while (i < attempts) {
|
|
404
|
+
if (abortController.signal.aborted) {
|
|
405
|
+
throw new TonConnectError(`Aborted after attempts ${i}`);
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
return yield fn({ signal: abortController.signal });
|
|
409
|
+
}
|
|
410
|
+
catch (err) {
|
|
411
|
+
lastError = err;
|
|
412
|
+
i++;
|
|
413
|
+
if (i < attempts) {
|
|
414
|
+
yield delay(delayMs);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
throw lastError;
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function logDebug(...args) {
|
|
423
|
+
{
|
|
424
|
+
try {
|
|
425
|
+
console.debug('[TON_CONNECT_SDK]', ...args);
|
|
426
|
+
}
|
|
427
|
+
catch (_a) { }
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function logError(...args) {
|
|
431
|
+
{
|
|
432
|
+
try {
|
|
433
|
+
console.error('[TON_CONNECT_SDK]', ...args);
|
|
434
|
+
}
|
|
435
|
+
catch (_a) { }
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function logWarning(...args) {
|
|
439
|
+
{
|
|
440
|
+
try {
|
|
441
|
+
console.warn('[TON_CONNECT_SDK]', ...args);
|
|
442
|
+
}
|
|
443
|
+
catch (_a) { }
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Create a resource.
|
|
449
|
+
*
|
|
450
|
+
* @template T - The type of the resource.
|
|
451
|
+
* @template Args - The type of the arguments for creating the resource.
|
|
452
|
+
*
|
|
453
|
+
* @param {(...args: Args) => Promise<T>} createFn - A function that creates the resource.
|
|
454
|
+
* @param {(resource: T) => Promise<void>} [disposeFn] - An optional function that disposes the resource.
|
|
455
|
+
*/
|
|
456
|
+
function createResource(createFn, disposeFn) {
|
|
457
|
+
let currentResource = null;
|
|
458
|
+
let currentArgs = null;
|
|
459
|
+
let currentPromise = null;
|
|
460
|
+
let currentSignal = null;
|
|
461
|
+
let abortController = null;
|
|
462
|
+
// create a new resource
|
|
463
|
+
const create = (signal, ...args) => __awaiter(this, void 0, void 0, function* () {
|
|
464
|
+
currentSignal = signal !== null && signal !== void 0 ? signal : null;
|
|
465
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
466
|
+
abortController = createAbortController(signal);
|
|
467
|
+
if (abortController.signal.aborted) {
|
|
468
|
+
throw new TonConnectError('Resource creation was aborted');
|
|
469
|
+
}
|
|
470
|
+
currentArgs = args !== null && args !== void 0 ? args : null;
|
|
471
|
+
const promise = createFn(signal, ...args);
|
|
472
|
+
currentPromise = promise;
|
|
473
|
+
const resource = yield promise;
|
|
474
|
+
if (currentPromise !== promise) {
|
|
475
|
+
yield disposeFn(resource);
|
|
476
|
+
throw new TonConnectError('Resource creation was aborted by a new resource creation');
|
|
477
|
+
}
|
|
478
|
+
currentResource = resource;
|
|
479
|
+
return currentResource;
|
|
480
|
+
});
|
|
481
|
+
// get the current resource
|
|
482
|
+
const current = () => {
|
|
483
|
+
return currentResource !== null && currentResource !== void 0 ? currentResource : null;
|
|
484
|
+
};
|
|
485
|
+
// dispose the current resource
|
|
486
|
+
const dispose = () => __awaiter(this, void 0, void 0, function* () {
|
|
487
|
+
try {
|
|
488
|
+
const resource = currentResource;
|
|
489
|
+
currentResource = null;
|
|
490
|
+
const promise = currentPromise;
|
|
491
|
+
currentPromise = null;
|
|
492
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
493
|
+
yield Promise.allSettled([
|
|
494
|
+
resource ? disposeFn(resource) : Promise.resolve(),
|
|
495
|
+
promise ? disposeFn(yield promise) : Promise.resolve()
|
|
496
|
+
]);
|
|
497
|
+
}
|
|
498
|
+
catch (e) {
|
|
499
|
+
logError('Failed to dispose the resource', e);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
// recreate the current resource
|
|
503
|
+
const recreate = (delayMs) => __awaiter(this, void 0, void 0, function* () {
|
|
504
|
+
const resource = currentResource;
|
|
505
|
+
const promise = currentPromise;
|
|
506
|
+
const args = currentArgs;
|
|
507
|
+
const signal = currentSignal;
|
|
508
|
+
yield delay(delayMs);
|
|
509
|
+
if (resource === currentResource &&
|
|
510
|
+
promise === currentPromise &&
|
|
511
|
+
args === currentArgs &&
|
|
512
|
+
signal === currentSignal) {
|
|
513
|
+
return create(currentSignal, ...(args !== null && args !== void 0 ? args : []));
|
|
514
|
+
}
|
|
515
|
+
throw new TonConnectError('Resource recreation was aborted by a new resource creation');
|
|
516
|
+
});
|
|
517
|
+
return {
|
|
518
|
+
create,
|
|
519
|
+
current,
|
|
520
|
+
dispose,
|
|
521
|
+
recreate
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Executes a function and provides deferred behavior, allowing for a timeout and abort functionality.
|
|
527
|
+
*
|
|
528
|
+
* @param {Deferrable<T>} fn - The function to execute. It should return a promise that resolves with the desired result.
|
|
529
|
+
* @param {DeferOptions} options - Optional configuration options for the defer behavior.
|
|
530
|
+
* @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.
|
|
531
|
+
*/
|
|
532
|
+
function timeout(fn, options) {
|
|
533
|
+
const timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
534
|
+
const signal = options === null || options === void 0 ? void 0 : options.signal;
|
|
535
|
+
const abortController = createAbortController(signal);
|
|
536
|
+
return new Promise((resolve, reject) => {
|
|
537
|
+
if (abortController.signal.aborted) {
|
|
538
|
+
reject(new TonConnectError('Operation aborted'));
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
let timeoutId;
|
|
542
|
+
if (typeof timeout !== 'undefined') {
|
|
543
|
+
timeoutId = setTimeout(() => {
|
|
544
|
+
abortController.abort();
|
|
545
|
+
reject(new TonConnectError(`Timeout after ${timeout}ms`));
|
|
546
|
+
}, timeout);
|
|
547
|
+
}
|
|
548
|
+
abortController.signal.addEventListener('abort', () => {
|
|
549
|
+
clearTimeout(timeoutId);
|
|
550
|
+
reject(new TonConnectError('Operation aborted'));
|
|
551
|
+
}, { once: true });
|
|
552
|
+
const deferOptions = { timeout, abort: abortController.signal };
|
|
553
|
+
fn(resolve, reject, deferOptions).finally(() => clearTimeout(timeoutId));
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
346
557
|
class BridgeGateway {
|
|
347
558
|
constructor(storage, bridgeUrl, sessionId, listener, errorsListener) {
|
|
348
559
|
this.bridgeUrl = bridgeUrl;
|
|
@@ -353,67 +564,85 @@ class BridgeGateway {
|
|
|
353
564
|
this.postPath = 'message';
|
|
354
565
|
this.heartbeatMessage = 'heartbeat';
|
|
355
566
|
this.defaultTtl = 300;
|
|
356
|
-
this.
|
|
567
|
+
this.defaultReconnectDelay = 5000;
|
|
568
|
+
this.eventSource = createResource((signal, openingDeadlineMS) => __awaiter(this, void 0, void 0, function* () {
|
|
569
|
+
const eventSourceConfig = {
|
|
570
|
+
bridgeUrl: this.bridgeUrl,
|
|
571
|
+
ssePath: this.ssePath,
|
|
572
|
+
sessionId: this.sessionId,
|
|
573
|
+
bridgeGatewayStorage: this.bridgeGatewayStorage,
|
|
574
|
+
errorHandler: this.errorsHandler.bind(this),
|
|
575
|
+
messageHandler: this.messagesHandler.bind(this),
|
|
576
|
+
signal: signal,
|
|
577
|
+
openingDeadlineMS: openingDeadlineMS
|
|
578
|
+
};
|
|
579
|
+
return yield createEventSource(eventSourceConfig);
|
|
580
|
+
}), (resource) => __awaiter(this, void 0, void 0, function* () {
|
|
581
|
+
resource.close();
|
|
582
|
+
}));
|
|
357
583
|
this.bridgeGatewayStorage = new HttpBridgeGatewayStorage(storage, bridgeUrl);
|
|
358
584
|
}
|
|
585
|
+
get isReady() {
|
|
586
|
+
const eventSource = this.eventSource.current();
|
|
587
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.OPEN;
|
|
588
|
+
}
|
|
589
|
+
get isClosed() {
|
|
590
|
+
const eventSource = this.eventSource.current();
|
|
591
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) !== EventSource.OPEN;
|
|
592
|
+
}
|
|
593
|
+
get isConnecting() {
|
|
594
|
+
const eventSource = this.eventSource.current();
|
|
595
|
+
return (eventSource === null || eventSource === void 0 ? void 0 : eventSource.readyState) === EventSource.CONNECTING;
|
|
596
|
+
}
|
|
359
597
|
registerSession(options) {
|
|
360
598
|
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
|
-
});
|
|
599
|
+
yield this.eventSource.create(options === null || options === void 0 ? void 0 : options.signal, options === null || options === void 0 ? void 0 : options.openingDeadlineMS);
|
|
388
600
|
});
|
|
389
601
|
}
|
|
390
|
-
send(message, receiver, topic,
|
|
602
|
+
send(message, receiver, topic, ttlOrOptions) {
|
|
603
|
+
var _a;
|
|
391
604
|
return __awaiter(this, void 0, void 0, function* () {
|
|
605
|
+
// TODO: remove deprecated method
|
|
606
|
+
const options = {};
|
|
607
|
+
if (typeof ttlOrOptions === 'number') {
|
|
608
|
+
options.ttl = ttlOrOptions;
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
options.ttl = ttlOrOptions === null || ttlOrOptions === void 0 ? void 0 : ttlOrOptions.ttl;
|
|
612
|
+
options.signal = ttlOrOptions === null || ttlOrOptions === void 0 ? void 0 : ttlOrOptions.signal;
|
|
613
|
+
options.attempts = ttlOrOptions === null || ttlOrOptions === void 0 ? void 0 : ttlOrOptions.attempts;
|
|
614
|
+
}
|
|
392
615
|
const url = new URL(addPathToUrl(this.bridgeUrl, this.postPath));
|
|
393
616
|
url.searchParams.append('client_id', this.sessionId);
|
|
394
617
|
url.searchParams.append('to', receiver);
|
|
395
|
-
url.searchParams.append('ttl', (ttl || this.defaultTtl).toString());
|
|
618
|
+
url.searchParams.append('ttl', ((options === null || options === void 0 ? void 0 : options.ttl) || this.defaultTtl).toString());
|
|
396
619
|
url.searchParams.append('topic', topic);
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
body
|
|
620
|
+
const body = Base64.encode(message);
|
|
621
|
+
yield callForSuccess((options) => __awaiter(this, void 0, void 0, function* () {
|
|
622
|
+
const response = yield this.post(url, body, options.signal);
|
|
623
|
+
if (!response.ok) {
|
|
624
|
+
throw new TonConnectError(`Bridge send failed, status ${response.status}`);
|
|
625
|
+
}
|
|
626
|
+
}), {
|
|
627
|
+
attempts: (_a = options === null || options === void 0 ? void 0 : options.attempts) !== null && _a !== void 0 ? _a : Number.MAX_SAFE_INTEGER,
|
|
628
|
+
delayMs: 5000,
|
|
629
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
400
630
|
});
|
|
401
|
-
if (!response.ok) {
|
|
402
|
-
throw new TonConnectError(`Bridge send failed, status ${response.status}`);
|
|
403
|
-
}
|
|
404
631
|
});
|
|
405
632
|
}
|
|
406
633
|
pause() {
|
|
407
|
-
|
|
408
|
-
(_a = this.eventSource) === null || _a === void 0 ? void 0 : _a.close();
|
|
634
|
+
this.eventSource.dispose().catch(e => logError(`Bridge pause failed, ${e}`));
|
|
409
635
|
}
|
|
410
636
|
unPause() {
|
|
411
|
-
return this
|
|
637
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
638
|
+
const RECREATE_WITHOUT_DELAY = 0;
|
|
639
|
+
yield this.eventSource.recreate(RECREATE_WITHOUT_DELAY);
|
|
640
|
+
});
|
|
412
641
|
}
|
|
413
642
|
close() {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
643
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
644
|
+
yield this.eventSource.dispose().catch(e => logError(`Bridge close failed, ${e}`));
|
|
645
|
+
});
|
|
417
646
|
}
|
|
418
647
|
setListener(listener) {
|
|
419
648
|
this.listener = listener;
|
|
@@ -421,20 +650,38 @@ class BridgeGateway {
|
|
|
421
650
|
setErrorsListener(errorsListener) {
|
|
422
651
|
this.errorsListener = errorsListener;
|
|
423
652
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
653
|
+
post(url, body, signal) {
|
|
654
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
655
|
+
const response = yield fetch(url, {
|
|
656
|
+
method: 'post',
|
|
657
|
+
body: body,
|
|
658
|
+
signal: signal
|
|
659
|
+
});
|
|
660
|
+
if (!response.ok) {
|
|
661
|
+
throw new TonConnectError(`Bridge send failed, status ${response.status}`);
|
|
431
662
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
663
|
+
return response;
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
errorsHandler(e) {
|
|
667
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
668
|
+
try {
|
|
669
|
+
if (this.isConnecting) {
|
|
670
|
+
logError('Bridge error', JSON.stringify(e));
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (this.isReady) {
|
|
674
|
+
this.errorsListener(e);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (this.isClosed) {
|
|
678
|
+
logDebug(`Bridge reconnecting, ${this.defaultReconnectDelay}ms delay`);
|
|
679
|
+
yield this.eventSource.recreate(this.defaultReconnectDelay);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
435
682
|
}
|
|
436
|
-
|
|
437
|
-
}
|
|
683
|
+
catch (e) { }
|
|
684
|
+
});
|
|
438
685
|
}
|
|
439
686
|
messagesHandler(e) {
|
|
440
687
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -442,19 +689,71 @@ class BridgeGateway {
|
|
|
442
689
|
return;
|
|
443
690
|
}
|
|
444
691
|
yield this.bridgeGatewayStorage.storeLastEventId(e.lastEventId);
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
throw new TonConnectError(`Bridge message parse failed, message ${e.data}`);
|
|
452
|
-
}
|
|
453
|
-
this.listener(bridgeIncomingMessage);
|
|
692
|
+
if (this.isClosed) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
let bridgeIncomingMessage;
|
|
696
|
+
try {
|
|
697
|
+
bridgeIncomingMessage = JSON.parse(e.data);
|
|
454
698
|
}
|
|
699
|
+
catch (e) {
|
|
700
|
+
throw new TonConnectError(`Bridge message parse failed, message ${e.data}`);
|
|
701
|
+
}
|
|
702
|
+
this.listener(bridgeIncomingMessage);
|
|
455
703
|
});
|
|
456
704
|
}
|
|
457
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Creates an event source.
|
|
708
|
+
* @param {CreateEventSourceConfig} config - Configuration for creating an event source.
|
|
709
|
+
*/
|
|
710
|
+
function createEventSource(config) {
|
|
711
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
712
|
+
return yield timeout((resolve, reject, deferOptions) => __awaiter(this, void 0, void 0, function* () {
|
|
713
|
+
var _a;
|
|
714
|
+
const abortController = createAbortController(deferOptions.signal);
|
|
715
|
+
const signal = abortController.signal;
|
|
716
|
+
if (signal.aborted) {
|
|
717
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const url = new URL(addPathToUrl(config.bridgeUrl, config.ssePath));
|
|
721
|
+
url.searchParams.append('client_id', config.sessionId);
|
|
722
|
+
const lastEventId = yield config.bridgeGatewayStorage.getLastEventId();
|
|
723
|
+
if (lastEventId) {
|
|
724
|
+
url.searchParams.append('last_event_id', lastEventId);
|
|
725
|
+
}
|
|
726
|
+
if (signal.aborted) {
|
|
727
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
const eventSource = new EventSource(url.toString());
|
|
731
|
+
eventSource.onerror = (reason) => {
|
|
732
|
+
if (signal.aborted) {
|
|
733
|
+
eventSource.close();
|
|
734
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
config.errorHandler(reason);
|
|
738
|
+
};
|
|
739
|
+
eventSource.onopen = () => {
|
|
740
|
+
if (signal.aborted) {
|
|
741
|
+
eventSource.close();
|
|
742
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
resolve(eventSource);
|
|
746
|
+
};
|
|
747
|
+
eventSource.onmessage = (event) => {
|
|
748
|
+
config.messageHandler(event);
|
|
749
|
+
};
|
|
750
|
+
(_a = config.signal) === null || _a === void 0 ? void 0 : _a.addEventListener('abort', () => {
|
|
751
|
+
eventSource.close();
|
|
752
|
+
reject(new TonConnectError('Bridge connection aborted'));
|
|
753
|
+
});
|
|
754
|
+
}), { timeout: config.openingDeadlineMS, signal: config.signal });
|
|
755
|
+
});
|
|
756
|
+
}
|
|
458
757
|
|
|
459
758
|
function isPendingConnectionHttp(connection) {
|
|
460
759
|
return !('connectEvent' in connection);
|
|
@@ -619,31 +918,6 @@ class BridgeConnectionStorage {
|
|
|
619
918
|
|
|
620
919
|
const PROTOCOL_VERSION = 2;
|
|
621
920
|
|
|
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
921
|
class BridgeProvider {
|
|
648
922
|
constructor(storage, walletConnectionSource) {
|
|
649
923
|
this.storage = storage;
|
|
@@ -655,6 +929,7 @@ class BridgeProvider {
|
|
|
655
929
|
this.gateway = null;
|
|
656
930
|
this.pendingGateways = [];
|
|
657
931
|
this.listeners = [];
|
|
932
|
+
this.defaultOpeningDeadlineMS = 5000;
|
|
658
933
|
this.connectionStorage = new BridgeConnectionStorage(storage);
|
|
659
934
|
}
|
|
660
935
|
static fromStorage(storage) {
|
|
@@ -667,7 +942,11 @@ class BridgeProvider {
|
|
|
667
942
|
return new BridgeProvider(storage, { bridgeUrl: connection.session.bridgeUrl });
|
|
668
943
|
});
|
|
669
944
|
}
|
|
670
|
-
connect(message) {
|
|
945
|
+
connect(message, options) {
|
|
946
|
+
var _a;
|
|
947
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
948
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
949
|
+
this.abortController = abortController;
|
|
671
950
|
this.closeGateways();
|
|
672
951
|
const sessionCrypto = new SessionCrypto();
|
|
673
952
|
this.session = {
|
|
@@ -682,20 +961,43 @@ class BridgeProvider {
|
|
|
682
961
|
connectionSource: this.walletConnectionSource,
|
|
683
962
|
sessionCrypto
|
|
684
963
|
})
|
|
685
|
-
.then(() => this
|
|
964
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
965
|
+
if (abortController.signal.aborted) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
yield callForSuccess(_options => this.openGateways(sessionCrypto, {
|
|
969
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
970
|
+
signal: _options === null || _options === void 0 ? void 0 : _options.signal
|
|
971
|
+
}), {
|
|
972
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
973
|
+
delayMs: 5000,
|
|
974
|
+
signal: abortController.signal
|
|
975
|
+
});
|
|
976
|
+
}));
|
|
686
977
|
const universalLink = 'universalLink' in this.walletConnectionSource &&
|
|
687
978
|
this.walletConnectionSource.universalLink
|
|
688
979
|
? this.walletConnectionSource.universalLink
|
|
689
980
|
: this.standardUniversalLink;
|
|
690
981
|
return this.generateUniversalLink(universalLink, message);
|
|
691
982
|
}
|
|
692
|
-
restoreConnection() {
|
|
983
|
+
restoreConnection(options) {
|
|
984
|
+
var _a, _b;
|
|
693
985
|
return __awaiter(this, void 0, void 0, function* () {
|
|
986
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
987
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
988
|
+
this.abortController = abortController;
|
|
989
|
+
if (abortController.signal.aborted) {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
694
992
|
this.closeGateways();
|
|
695
993
|
const storedConnection = yield this.connectionStorage.getHttpConnection();
|
|
696
994
|
if (!storedConnection) {
|
|
697
995
|
return;
|
|
698
996
|
}
|
|
997
|
+
if (abortController.signal.aborted) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const openingDeadlineMS = (_b = options === null || options === void 0 ? void 0 : options.openingDeadlineMS) !== null && _b !== void 0 ? _b : this.defaultOpeningDeadlineMS;
|
|
699
1001
|
if (isPendingConnectionHttp(storedConnection)) {
|
|
700
1002
|
this.session = {
|
|
701
1003
|
sessionCrypto: storedConnection.sessionCrypto,
|
|
@@ -703,25 +1005,55 @@ class BridgeProvider {
|
|
|
703
1005
|
? this.walletConnectionSource.bridgeUrl
|
|
704
1006
|
: ''
|
|
705
1007
|
};
|
|
706
|
-
return this.openGateways(storedConnection.sessionCrypto, {
|
|
1008
|
+
return yield this.openGateways(storedConnection.sessionCrypto, {
|
|
1009
|
+
openingDeadlineMS: openingDeadlineMS,
|
|
1010
|
+
signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal
|
|
1011
|
+
});
|
|
707
1012
|
}
|
|
708
1013
|
if (Array.isArray(this.walletConnectionSource)) {
|
|
709
1014
|
throw new TonConnectError('Internal error. Connection source is array while WalletConnectionSourceHTTP was expected.');
|
|
710
1015
|
}
|
|
711
1016
|
this.session = storedConnection.session;
|
|
1017
|
+
if (this.gateway) {
|
|
1018
|
+
logDebug('Gateway is already opened, closing previous gateway');
|
|
1019
|
+
yield this.gateway.close();
|
|
1020
|
+
}
|
|
712
1021
|
this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, storedConnection.session.sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
|
|
1022
|
+
if (abortController.signal.aborted) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
// notify listeners about stored connection
|
|
1026
|
+
this.listeners.forEach(listener => listener(storedConnection.connectEvent));
|
|
1027
|
+
// wait for the connection to be opened
|
|
713
1028
|
try {
|
|
714
|
-
yield this.gateway.registerSession({
|
|
1029
|
+
yield callForSuccess(options => this.gateway.registerSession({
|
|
1030
|
+
openingDeadlineMS: openingDeadlineMS,
|
|
1031
|
+
signal: options.signal
|
|
1032
|
+
}), {
|
|
1033
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
1034
|
+
delayMs: 5000,
|
|
1035
|
+
signal: abortController.signal
|
|
1036
|
+
});
|
|
715
1037
|
}
|
|
716
1038
|
catch (e) {
|
|
717
|
-
yield this.disconnect();
|
|
1039
|
+
yield this.disconnect({ signal: abortController.signal });
|
|
718
1040
|
return;
|
|
719
1041
|
}
|
|
720
|
-
this.listeners.forEach(listener => listener(storedConnection.connectEvent));
|
|
721
1042
|
});
|
|
722
1043
|
}
|
|
723
|
-
sendRequest(request,
|
|
1044
|
+
sendRequest(request, optionsOrOnRequestSent) {
|
|
1045
|
+
// TODO: remove deprecated method
|
|
1046
|
+
const options = {};
|
|
1047
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
1048
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
1049
|
+
}
|
|
1050
|
+
else {
|
|
1051
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
1052
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
1053
|
+
options.attempts = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.attempts;
|
|
1054
|
+
}
|
|
724
1055
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
1056
|
+
var _a;
|
|
725
1057
|
if (!this.gateway || !this.session || !('walletPublicKey' in this.session)) {
|
|
726
1058
|
throw new TonConnectError('Trying to send bridge request without session');
|
|
727
1059
|
}
|
|
@@ -730,8 +1062,8 @@ class BridgeProvider {
|
|
|
730
1062
|
logDebug('Send http-bridge request:', Object.assign(Object.assign({}, request), { id }));
|
|
731
1063
|
const encodedRequest = this.session.sessionCrypto.encrypt(JSON.stringify(Object.assign(Object.assign({}, request), { id })), hexToByteArray(this.session.walletPublicKey));
|
|
732
1064
|
try {
|
|
733
|
-
yield this.gateway.send(encodedRequest, this.session.walletPublicKey, request.method);
|
|
734
|
-
|
|
1065
|
+
yield this.gateway.send(encodedRequest, this.session.walletPublicKey, request.method, { attempts: options === null || options === void 0 ? void 0 : options.attempts, signal: options === null || options === void 0 ? void 0 : options.signal });
|
|
1066
|
+
(_a = options === null || options === void 0 ? void 0 : options.onRequestSent) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
735
1067
|
this.pendingRequests.set(id.toString(), resolve);
|
|
736
1068
|
}
|
|
737
1069
|
catch (e) {
|
|
@@ -745,23 +1077,41 @@ class BridgeProvider {
|
|
|
745
1077
|
this.session = null;
|
|
746
1078
|
this.gateway = null;
|
|
747
1079
|
}
|
|
748
|
-
disconnect() {
|
|
1080
|
+
disconnect(options) {
|
|
749
1081
|
return __awaiter(this, void 0, void 0, function* () {
|
|
750
1082
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
751
1083
|
let called = false;
|
|
1084
|
+
let timeoutId = null;
|
|
752
1085
|
const onRequestSent = () => {
|
|
753
|
-
called
|
|
754
|
-
|
|
1086
|
+
if (!called) {
|
|
1087
|
+
called = true;
|
|
1088
|
+
this.removeBridgeAndSession().then(resolve);
|
|
1089
|
+
}
|
|
755
1090
|
};
|
|
756
1091
|
try {
|
|
757
|
-
|
|
1092
|
+
this.closeGateways();
|
|
1093
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
1094
|
+
timeoutId = setTimeout(() => {
|
|
1095
|
+
abortController.abort();
|
|
1096
|
+
}, this.defaultOpeningDeadlineMS);
|
|
1097
|
+
yield this.sendRequest({ method: 'disconnect', params: [] }, {
|
|
1098
|
+
onRequestSent: onRequestSent,
|
|
1099
|
+
signal: abortController.signal,
|
|
1100
|
+
attempts: 1,
|
|
1101
|
+
});
|
|
758
1102
|
}
|
|
759
1103
|
catch (e) {
|
|
760
|
-
|
|
1104
|
+
logDebug('Disconnect error:', e);
|
|
761
1105
|
if (!called) {
|
|
762
1106
|
this.removeBridgeAndSession().then(resolve);
|
|
763
1107
|
}
|
|
764
1108
|
}
|
|
1109
|
+
finally {
|
|
1110
|
+
if (timeoutId) {
|
|
1111
|
+
clearTimeout(timeoutId);
|
|
1112
|
+
}
|
|
1113
|
+
onRequestSent();
|
|
1114
|
+
}
|
|
765
1115
|
}));
|
|
766
1116
|
});
|
|
767
1117
|
}
|
|
@@ -786,10 +1136,14 @@ class BridgeProvider {
|
|
|
786
1136
|
pendingGatewaysListener(gateway, bridgeUrl, bridgeIncomingMessage) {
|
|
787
1137
|
return __awaiter(this, void 0, void 0, function* () {
|
|
788
1138
|
if (!this.pendingGateways.includes(gateway)) {
|
|
789
|
-
gateway.close();
|
|
1139
|
+
yield gateway.close();
|
|
790
1140
|
return;
|
|
791
1141
|
}
|
|
792
1142
|
this.closeGateways({ except: gateway });
|
|
1143
|
+
if (this.gateway) {
|
|
1144
|
+
logDebug('Gateway is already opened, closing previous gateway');
|
|
1145
|
+
yield this.gateway.close();
|
|
1146
|
+
}
|
|
793
1147
|
this.session.bridgeUrl = bridgeUrl;
|
|
794
1148
|
this.gateway = gateway;
|
|
795
1149
|
this.gateway.setErrorsListener(this.gatewayErrorsListener.bind(this));
|
|
@@ -828,6 +1182,7 @@ class BridgeProvider {
|
|
|
828
1182
|
yield this.updateSession(walletMessage, bridgeIncomingMessage.from);
|
|
829
1183
|
}
|
|
830
1184
|
if (walletMessage.event === 'disconnect') {
|
|
1185
|
+
logDebug(`Removing bridge and session: received disconnect event`);
|
|
831
1186
|
yield this.removeBridgeAndSession();
|
|
832
1187
|
}
|
|
833
1188
|
listeners.forEach(listener => listener(walletMessage));
|
|
@@ -893,6 +1248,9 @@ class BridgeProvider {
|
|
|
893
1248
|
openGateways(sessionCrypto, options) {
|
|
894
1249
|
return __awaiter(this, void 0, void 0, function* () {
|
|
895
1250
|
if (Array.isArray(this.walletConnectionSource)) {
|
|
1251
|
+
// close all gateways before opening new ones
|
|
1252
|
+
this.pendingGateways.map(bridge => bridge.close().catch(e => console.error(e)));
|
|
1253
|
+
// open new gateways
|
|
896
1254
|
this.pendingGateways = this.walletConnectionSource.map(source => {
|
|
897
1255
|
const gateway = new BridgeGateway(this.storage, source.bridgeUrl, sessionCrypto.sessionId, () => { }, e => {
|
|
898
1256
|
console.error(e);
|
|
@@ -900,12 +1258,31 @@ class BridgeProvider {
|
|
|
900
1258
|
gateway.setListener(message => this.pendingGatewaysListener(gateway, source.bridgeUrl, message));
|
|
901
1259
|
return gateway;
|
|
902
1260
|
});
|
|
903
|
-
yield Promise.allSettled(this.pendingGateways.map(bridge =>
|
|
1261
|
+
yield Promise.allSettled(this.pendingGateways.map(bridge => callForSuccess((_options) => {
|
|
1262
|
+
if (!this.pendingGateways.some(item => item === bridge)) {
|
|
1263
|
+
return bridge.close();
|
|
1264
|
+
}
|
|
1265
|
+
return bridge.registerSession({
|
|
1266
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
1267
|
+
signal: _options.signal
|
|
1268
|
+
});
|
|
1269
|
+
}, {
|
|
1270
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
1271
|
+
delayMs: 5000,
|
|
1272
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
1273
|
+
})));
|
|
904
1274
|
return;
|
|
905
1275
|
}
|
|
906
1276
|
else {
|
|
1277
|
+
if (this.gateway) {
|
|
1278
|
+
logDebug(`Gateway is already opened, closing previous gateway`);
|
|
1279
|
+
yield this.gateway.close();
|
|
1280
|
+
}
|
|
907
1281
|
this.gateway = new BridgeGateway(this.storage, this.walletConnectionSource.bridgeUrl, sessionCrypto.sessionId, this.gatewayListener.bind(this), this.gatewayErrorsListener.bind(this));
|
|
908
|
-
return this.gateway.registerSession(
|
|
1282
|
+
return yield this.gateway.registerSession({
|
|
1283
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
1284
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
1285
|
+
});
|
|
909
1286
|
}
|
|
910
1287
|
});
|
|
911
1288
|
}
|
|
@@ -1168,14 +1545,24 @@ class InjectedProvider {
|
|
|
1168
1545
|
this.listeners.push(eventsCallback);
|
|
1169
1546
|
return () => (this.listeners = this.listeners.filter(listener => listener !== eventsCallback));
|
|
1170
1547
|
}
|
|
1171
|
-
sendRequest(request,
|
|
1548
|
+
sendRequest(request, optionsOrOnRequestSent) {
|
|
1549
|
+
var _a;
|
|
1172
1550
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1551
|
+
// TODO: remove deprecated method
|
|
1552
|
+
const options = {};
|
|
1553
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
1554
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
1558
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
1559
|
+
}
|
|
1173
1560
|
const id = (yield this.connectionStorage.getNextRpcRequestId()).toString();
|
|
1174
1561
|
yield this.connectionStorage.increaseNextRpcRequestId();
|
|
1175
1562
|
logDebug('Send injected-bridge request:', Object.assign(Object.assign({}, request), { id }));
|
|
1176
1563
|
const result = this.injectedWallet.send(Object.assign(Object.assign({}, request), { id }));
|
|
1177
1564
|
result.then(response => logDebug('Wallet message received:', response));
|
|
1178
|
-
|
|
1565
|
+
(_a = options === null || options === void 0 ? void 0 : options.onRequestSent) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
1179
1566
|
return result;
|
|
1180
1567
|
});
|
|
1181
1568
|
}
|
|
@@ -1192,7 +1579,7 @@ class InjectedProvider {
|
|
|
1192
1579
|
this.listeners.forEach(listener => listener(connectEvent));
|
|
1193
1580
|
}
|
|
1194
1581
|
catch (e) {
|
|
1195
|
-
logDebug(e);
|
|
1582
|
+
logDebug('Injected Provider connect error:', e);
|
|
1196
1583
|
const connectEventError = {
|
|
1197
1584
|
event: 'connect_error',
|
|
1198
1585
|
payload: {
|
|
@@ -1321,19 +1708,6 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1321
1708
|
],
|
|
1322
1709
|
platforms: ['ios', 'android', 'chrome', 'firefox', 'macos']
|
|
1323
1710
|
},
|
|
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
1711
|
{
|
|
1338
1712
|
app_name: 'mytonwallet',
|
|
1339
1713
|
name: 'MyTonWallet',
|
|
@@ -1350,7 +1724,20 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1350
1724
|
url: 'https://tonconnectbridge.mytonwallet.org/bridge/'
|
|
1351
1725
|
}
|
|
1352
1726
|
],
|
|
1353
|
-
platforms: ['chrome', 'windows', 'macos', 'linux']
|
|
1727
|
+
platforms: ['chrome', 'windows', 'macos', 'linux', 'ios', 'android', 'firefox']
|
|
1728
|
+
},
|
|
1729
|
+
{
|
|
1730
|
+
app_name: 'openmask',
|
|
1731
|
+
name: 'OpenMask',
|
|
1732
|
+
image: 'https://raw.githubusercontent.com/OpenProduct/openmask-extension/main/public/openmask-logo-288.png',
|
|
1733
|
+
about_url: 'https://www.openmask.app/',
|
|
1734
|
+
bridge: [
|
|
1735
|
+
{
|
|
1736
|
+
type: 'js',
|
|
1737
|
+
key: 'openmask'
|
|
1738
|
+
}
|
|
1739
|
+
],
|
|
1740
|
+
platforms: ['chrome']
|
|
1354
1741
|
},
|
|
1355
1742
|
{
|
|
1356
1743
|
app_name: 'tonhub',
|
|
@@ -1370,19 +1757,6 @@ const FALLBACK_WALLETS_LIST = [
|
|
|
1370
1757
|
],
|
|
1371
1758
|
platforms: ['ios', 'android']
|
|
1372
1759
|
},
|
|
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
1760
|
{
|
|
1387
1761
|
app_name: 'dewallet',
|
|
1388
1762
|
name: 'DeWallet',
|
|
@@ -1689,59 +2063,128 @@ class TonConnect {
|
|
|
1689
2063
|
}
|
|
1690
2064
|
};
|
|
1691
2065
|
}
|
|
1692
|
-
connect(wallet,
|
|
1693
|
-
var _a;
|
|
2066
|
+
connect(wallet, requestOrOptions) {
|
|
2067
|
+
var _a, _b;
|
|
2068
|
+
// TODO: remove deprecated method
|
|
2069
|
+
const options = {};
|
|
2070
|
+
if (typeof requestOrOptions === 'object' && 'tonProof' in requestOrOptions) {
|
|
2071
|
+
options.request = requestOrOptions;
|
|
2072
|
+
}
|
|
2073
|
+
if (typeof requestOrOptions === 'object' &&
|
|
2074
|
+
('openingDeadlineMS' in requestOrOptions ||
|
|
2075
|
+
'signal' in requestOrOptions ||
|
|
2076
|
+
'request' in requestOrOptions)) {
|
|
2077
|
+
options.request = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.request;
|
|
2078
|
+
options.openingDeadlineMS = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.openingDeadlineMS;
|
|
2079
|
+
options.signal = requestOrOptions === null || requestOrOptions === void 0 ? void 0 : requestOrOptions.signal;
|
|
2080
|
+
}
|
|
1694
2081
|
if (this.connected) {
|
|
1695
2082
|
throw new WalletAlreadyConnectedError();
|
|
1696
2083
|
}
|
|
1697
|
-
|
|
2084
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2085
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
2086
|
+
this.abortController = abortController;
|
|
2087
|
+
if (abortController.signal.aborted) {
|
|
2088
|
+
throw new TonConnectError('Connection was aborted');
|
|
2089
|
+
}
|
|
2090
|
+
(_b = this.provider) === null || _b === void 0 ? void 0 : _b.closeConnection();
|
|
1698
2091
|
this.provider = this.createProvider(wallet);
|
|
1699
|
-
|
|
2092
|
+
abortController.signal.addEventListener('abort', () => {
|
|
2093
|
+
var _a;
|
|
2094
|
+
(_a = this.provider) === null || _a === void 0 ? void 0 : _a.closeConnection();
|
|
2095
|
+
this.provider = null;
|
|
2096
|
+
});
|
|
2097
|
+
return this.provider.connect(this.createConnectRequest(options === null || options === void 0 ? void 0 : options.request), {
|
|
2098
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
2099
|
+
signal: abortController.signal
|
|
2100
|
+
});
|
|
1700
2101
|
}
|
|
1701
2102
|
/**
|
|
1702
2103
|
* Try to restore existing session and reconnect to the corresponding wallet. Call it immediately when your app is loaded.
|
|
1703
2104
|
*/
|
|
1704
|
-
restoreConnection() {
|
|
2105
|
+
restoreConnection(options) {
|
|
2106
|
+
var _a, _b;
|
|
1705
2107
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2108
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2109
|
+
(_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
2110
|
+
this.abortController = abortController;
|
|
2111
|
+
if (abortController.signal.aborted) {
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
// TODO: potentially race condition here
|
|
1706
2115
|
const [bridgeConnectionType, embeddedWallet] = yield Promise.all([
|
|
1707
2116
|
this.bridgeConnectionStorage.storedConnectionType(),
|
|
1708
2117
|
this.walletsList.getEmbeddedWallet()
|
|
1709
2118
|
]);
|
|
2119
|
+
if (abortController.signal.aborted) {
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2122
|
+
let provider = null;
|
|
1710
2123
|
try {
|
|
1711
2124
|
switch (bridgeConnectionType) {
|
|
1712
2125
|
case 'http':
|
|
1713
|
-
|
|
2126
|
+
provider = yield BridgeProvider.fromStorage(this.dappSettings.storage);
|
|
1714
2127
|
break;
|
|
1715
2128
|
case 'injected':
|
|
1716
|
-
|
|
2129
|
+
provider = yield InjectedProvider.fromStorage(this.dappSettings.storage);
|
|
1717
2130
|
break;
|
|
1718
2131
|
default:
|
|
1719
2132
|
if (embeddedWallet) {
|
|
1720
|
-
|
|
2133
|
+
provider = this.createProvider(embeddedWallet);
|
|
1721
2134
|
}
|
|
1722
2135
|
else {
|
|
1723
2136
|
return;
|
|
1724
2137
|
}
|
|
1725
2138
|
}
|
|
1726
2139
|
}
|
|
1727
|
-
catch (
|
|
2140
|
+
catch (_c) {
|
|
1728
2141
|
yield this.bridgeConnectionStorage.removeConnection();
|
|
1729
|
-
|
|
2142
|
+
provider === null || provider === void 0 ? void 0 : provider.closeConnection();
|
|
2143
|
+
provider = null;
|
|
1730
2144
|
return;
|
|
1731
2145
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
2146
|
+
if (abortController.signal.aborted) {
|
|
2147
|
+
provider === null || provider === void 0 ? void 0 : provider.closeConnection();
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2150
|
+
if (!provider) {
|
|
2151
|
+
logError('Provider is not restored');
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
(_b = this.provider) === null || _b === void 0 ? void 0 : _b.closeConnection();
|
|
2155
|
+
this.provider = provider;
|
|
2156
|
+
provider.listen(this.walletEventsListener.bind(this));
|
|
2157
|
+
abortController.signal.addEventListener('abort', () => {
|
|
2158
|
+
provider === null || provider === void 0 ? void 0 : provider.closeConnection();
|
|
2159
|
+
provider = null;
|
|
2160
|
+
});
|
|
2161
|
+
return yield callForSuccess((_options) => __awaiter(this, void 0, void 0, function* () {
|
|
2162
|
+
return provider === null || provider === void 0 ? void 0 : provider.restoreConnection({
|
|
2163
|
+
openingDeadlineMS: options === null || options === void 0 ? void 0 : options.openingDeadlineMS,
|
|
2164
|
+
signal: _options.signal
|
|
2165
|
+
});
|
|
2166
|
+
}), {
|
|
2167
|
+
attempts: Number.MAX_SAFE_INTEGER,
|
|
2168
|
+
delayMs: 5000,
|
|
2169
|
+
signal: options === null || options === void 0 ? void 0 : options.signal
|
|
2170
|
+
});
|
|
1734
2171
|
});
|
|
1735
2172
|
}
|
|
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) {
|
|
2173
|
+
sendTransaction(transaction, optionsOrOnRequestSent) {
|
|
1744
2174
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2175
|
+
// TODO: remove deprecated method
|
|
2176
|
+
const options = {};
|
|
2177
|
+
if (typeof optionsOrOnRequestSent === 'function') {
|
|
2178
|
+
options.onRequestSent = optionsOrOnRequestSent;
|
|
2179
|
+
}
|
|
2180
|
+
else {
|
|
2181
|
+
options.onRequestSent = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.onRequestSent;
|
|
2182
|
+
options.signal = optionsOrOnRequestSent === null || optionsOrOnRequestSent === void 0 ? void 0 : optionsOrOnRequestSent.signal;
|
|
2183
|
+
}
|
|
2184
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2185
|
+
if (abortController.signal.aborted) {
|
|
2186
|
+
throw new TonConnectError('Transaction sending was aborted');
|
|
2187
|
+
}
|
|
1745
2188
|
this.checkConnection();
|
|
1746
2189
|
checkSendTransactionSupport(this.wallet.device.features, {
|
|
1747
2190
|
requiredMessagesNumber: transaction.messages.length
|
|
@@ -1750,7 +2193,7 @@ class TonConnect {
|
|
|
1750
2193
|
const from = transaction.from || this.account.address;
|
|
1751
2194
|
const network = transaction.network || this.account.chain;
|
|
1752
2195
|
const response = yield this.provider.sendRequest(sendTransactionParser.convertToRpcRequest(Object.assign(Object.assign({}, tx), { valid_until: validUntil, from,
|
|
1753
|
-
network })), onRequestSent);
|
|
2196
|
+
network })), { onRequestSent: options.onRequestSent, signal: abortController.signal });
|
|
1754
2197
|
if (sendTransactionParser.isError(response)) {
|
|
1755
2198
|
return sendTransactionParser.parseAndThrowError(response);
|
|
1756
2199
|
}
|
|
@@ -1760,13 +2203,23 @@ class TonConnect {
|
|
|
1760
2203
|
/**
|
|
1761
2204
|
* Disconnect form thw connected wallet and drop current session.
|
|
1762
2205
|
*/
|
|
1763
|
-
disconnect() {
|
|
2206
|
+
disconnect(options) {
|
|
2207
|
+
var _a;
|
|
1764
2208
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1765
2209
|
if (!this.connected) {
|
|
1766
2210
|
throw new WalletNotConnectedError();
|
|
1767
2211
|
}
|
|
1768
|
-
|
|
2212
|
+
const abortController = createAbortController(options === null || options === void 0 ? void 0 : options.signal);
|
|
2213
|
+
const prevAbortController = this.abortController;
|
|
2214
|
+
this.abortController = abortController;
|
|
2215
|
+
if (abortController.signal.aborted) {
|
|
2216
|
+
throw new TonConnectError('Disconnect was aborted');
|
|
2217
|
+
}
|
|
1769
2218
|
this.onWalletDisconnected();
|
|
2219
|
+
yield ((_a = this.provider) === null || _a === void 0 ? void 0 : _a.disconnect({
|
|
2220
|
+
signal: abortController.signal
|
|
2221
|
+
}));
|
|
2222
|
+
prevAbortController === null || prevAbortController === void 0 ? void 0 : prevAbortController.abort();
|
|
1770
2223
|
});
|
|
1771
2224
|
}
|
|
1772
2225
|
/**
|
|
@@ -1801,12 +2254,12 @@ class TonConnect {
|
|
|
1801
2254
|
this.pauseConnection();
|
|
1802
2255
|
}
|
|
1803
2256
|
else {
|
|
1804
|
-
this.unPauseConnection();
|
|
2257
|
+
this.unPauseConnection().catch(e => logError('Cannot unpause connection', e));
|
|
1805
2258
|
}
|
|
1806
2259
|
});
|
|
1807
2260
|
}
|
|
1808
2261
|
catch (e) {
|
|
1809
|
-
|
|
2262
|
+
logError('Cannot subscribe to the document.visibilitychange: ', e);
|
|
1810
2263
|
}
|
|
1811
2264
|
}
|
|
1812
2265
|
createProvider(wallet) {
|