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