@tezos-x/octez.connect-dapp 4.8.3 → 4.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -7
- package/dist/cjs/beacon-message-events.js.map +1 -1
- package/dist/cjs/dapp-client/DAppClient.d.ts +114 -6
- package/dist/cjs/dapp-client/DAppClient.js +986 -392
- package/dist/cjs/dapp-client/DAppClient.js.map +1 -1
- package/dist/cjs/dapp-client/DAppClientOptions.d.ts +17 -0
- package/dist/cjs/dapp-client/DAppClientOptions.js.map +1 -1
- package/dist/cjs/events.d.ts +29 -3
- package/dist/cjs/events.js +41 -37
- package/dist/cjs/events.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/transports/DappP2PTransport.d.ts +1 -1
- package/dist/cjs/transports/DappP2PTransport.js.map +1 -1
- package/dist/cjs/transports/DappPostMessageTransport.d.ts +1 -1
- package/dist/cjs/transports/DappPostMessageTransport.js.map +1 -1
- package/dist/cjs/transports/DappWalletConnectTransport.d.ts +1 -1
- package/dist/cjs/transports/DappWalletConnectTransport.js.map +1 -1
- package/dist/cjs/utils/available-transports.js.map +1 -1
- package/dist/cjs/utils/block-explorer.d.ts +2 -2
- package/dist/cjs/utils/block-explorer.js +5 -1
- package/dist/cjs/utils/block-explorer.js.map +1 -1
- package/dist/cjs/utils/get-instance.js +7 -1
- package/dist/cjs/utils/get-instance.js.map +1 -1
- package/dist/cjs/utils/shorten-string.js.map +1 -1
- package/dist/cjs/utils/tzkt-blockexplorer.d.ts +2 -2
- package/dist/cjs/utils/tzkt-blockexplorer.js +3 -17
- package/dist/cjs/utils/tzkt-blockexplorer.js.map +1 -1
- package/dist/esm/beacon-message-events.js.map +1 -1
- package/dist/esm/dapp-client/DAppClient.d.ts +114 -6
- package/dist/esm/dapp-client/DAppClient.js +991 -386
- package/dist/esm/dapp-client/DAppClient.js.map +1 -1
- package/dist/esm/dapp-client/DAppClientOptions.d.ts +17 -0
- package/dist/esm/dapp-client/DAppClientOptions.js.map +1 -1
- package/dist/esm/events.d.ts +29 -3
- package/dist/esm/events.js +6 -3
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/transports/DappP2PTransport.d.ts +1 -1
- package/dist/esm/transports/DappP2PTransport.js.map +1 -1
- package/dist/esm/transports/DappPostMessageTransport.d.ts +1 -1
- package/dist/esm/transports/DappPostMessageTransport.js.map +1 -1
- package/dist/esm/transports/DappWalletConnectTransport.d.ts +1 -1
- package/dist/esm/transports/DappWalletConnectTransport.js.map +1 -1
- package/dist/esm/utils/available-transports.js.map +1 -1
- package/dist/esm/utils/block-explorer.d.ts +2 -2
- package/dist/esm/utils/block-explorer.js +5 -1
- package/dist/esm/utils/block-explorer.js.map +1 -1
- package/dist/esm/utils/get-instance.js +7 -1
- package/dist/esm/utils/get-instance.js.map +1 -1
- package/dist/esm/utils/shorten-string.js.map +1 -1
- package/dist/esm/utils/tzkt-blockexplorer.d.ts +2 -2
- package/dist/esm/utils/tzkt-blockexplorer.js +3 -17
- package/dist/esm/utils/tzkt-blockexplorer.js.map +1 -1
- package/dist/octez.connect.dapp.min.js +1 -1066
- package/package.json +17 -13
- package/LICENCE +0 -19
- package/dist/walletbeacon.dapp.min.js +0 -1066
|
@@ -10,15 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.DAppClient = void 0;
|
|
13
|
-
const axios_1 = require("axios");
|
|
14
13
|
const bs58check_1 = require("bs58check");
|
|
15
|
-
const events_1 = require("../events");
|
|
16
14
|
const octez_connect_types_1 = require("@tezos-x/octez.connect-types");
|
|
17
15
|
const octez_connect_core_1 = require("@tezos-x/octez.connect-core");
|
|
18
16
|
const octez_connect_utils_1 = require("@tezos-x/octez.connect-utils");
|
|
19
17
|
const beacon_message_events_1 = require("../beacon-message-events");
|
|
18
|
+
const events_1 = require("../events");
|
|
20
19
|
const tzkt_blockexplorer_1 = require("../utils/tzkt-blockexplorer");
|
|
21
|
-
const octez_connect_dapp_1 = require("@tezos-x/octez.connect-dapp");
|
|
22
20
|
const DappPostMessageTransport_1 = require("../transports/DappPostMessageTransport");
|
|
23
21
|
const DappP2PTransport_1 = require("../transports/DappP2PTransport");
|
|
24
22
|
const DappWalletConnectTransport_1 = require("../transports/DappWalletConnectTransport");
|
|
@@ -26,6 +24,23 @@ const octez_connect_transport_postmessage_1 = require("@tezos-x/octez.connect-tr
|
|
|
26
24
|
const octez_connect_ui_1 = require("@tezos-x/octez.connect-ui");
|
|
27
25
|
const octez_connect_transport_walletconnect_1 = require("@tezos-x/octez.connect-transport-walletconnect");
|
|
28
26
|
const logger = new octez_connect_core_1.Logger('DAppClient');
|
|
27
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
|
|
28
|
+
const SESSION_UPDATE_REQUEST_ID = 'session_update';
|
|
29
|
+
const createLazyPromise = (factory) => {
|
|
30
|
+
let promise;
|
|
31
|
+
const getPromise = () => {
|
|
32
|
+
if (!promise) {
|
|
33
|
+
promise = factory();
|
|
34
|
+
}
|
|
35
|
+
return promise;
|
|
36
|
+
};
|
|
37
|
+
const lazyPromise = {
|
|
38
|
+
then: (onfulfilled, onrejected) => getPromise().then(onfulfilled, onrejected),
|
|
39
|
+
catch: (onrejected) => getPromise().catch(onrejected),
|
|
40
|
+
finally: (onfinally) => getPromise().finally(onfinally !== null && onfinally !== void 0 ? onfinally : undefined)
|
|
41
|
+
};
|
|
42
|
+
return lazyPromise;
|
|
43
|
+
};
|
|
29
44
|
/**
|
|
30
45
|
* @publicapi
|
|
31
46
|
*
|
|
@@ -36,15 +51,17 @@ const logger = new octez_connect_core_1.Logger('DAppClient');
|
|
|
36
51
|
*/
|
|
37
52
|
class DAppClient extends octez_connect_core_1.Client {
|
|
38
53
|
constructor(config) {
|
|
39
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
54
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
40
55
|
super(Object.assign({ storage: config && config.storage ? config.storage : new octez_connect_core_1.LocalStorage() }, config));
|
|
41
|
-
this.events = new
|
|
56
|
+
this.events = new events_1.BeaconEventHandler();
|
|
42
57
|
this.isGetActiveAccountHandled = false;
|
|
43
58
|
this.openRequestsOtherTabs = new Set();
|
|
44
59
|
/**
|
|
45
60
|
* A map of requests that are currently "open", meaning we have sent them to a wallet and are still awaiting a response.
|
|
46
61
|
*/
|
|
47
62
|
this.openRequests = new Map();
|
|
63
|
+
this.acknowledgedRequests = new Set();
|
|
64
|
+
this.openRequestTimeouts = new Map();
|
|
48
65
|
/**
|
|
49
66
|
* The currently active account. For all requests that are associated to a specific request (operation request, signing request),
|
|
50
67
|
* the active account is used to determine the network and destination wallet
|
|
@@ -54,44 +71,59 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
54
71
|
* The currently active peer. This is used to address a peer in case the active account is not set. (Eg. for permission requests)
|
|
55
72
|
*/
|
|
56
73
|
this._activePeer = new octez_connect_utils_1.ExposedPromise();
|
|
57
|
-
this.
|
|
74
|
+
this.destroyed = false;
|
|
58
75
|
this.beaconIDB = new octez_connect_core_1.IndexedDBStorage('beacon', ['bug_report', 'metrics']);
|
|
59
76
|
this.debounceSetActiveAccount = false;
|
|
77
|
+
// Constructor-time invalid storage recovery can race through multiple async paths.
|
|
78
|
+
// Keep this guard scoped to those startup paths.
|
|
79
|
+
this.hasEmittedInvalidAccountDeactivated = false;
|
|
80
|
+
this._disconnectNotifyPeers = false;
|
|
60
81
|
this.multiTabChannel = new octez_connect_core_1.MultiTabChannel('octez.connect-sdk-channel', this.onBCMessageHandler.bind(this), this.onElectedLeaderhandler.bind(this));
|
|
61
82
|
this.blockchains = new Map();
|
|
62
83
|
this.description = config.description;
|
|
63
|
-
this.
|
|
64
|
-
|
|
84
|
+
this.disableWalletConnect = (_a = config.disableWalletConnect) !== null && _a !== void 0 ? _a : false;
|
|
85
|
+
if (!this.disableWalletConnect) {
|
|
86
|
+
this.wcProjectId = ((_b = config.walletConnectOptions) === null || _b === void 0 ? void 0 : _b.projectId) || '24469fd0a06df227b6e5f7dc7de0ff4f';
|
|
87
|
+
this.wcRelayUrl = (_c = config.walletConnectOptions) === null || _c === void 0 ? void 0 : _c.relayUrl;
|
|
88
|
+
}
|
|
65
89
|
this.featuredWallets = config.featuredWallets;
|
|
66
|
-
this.events = new
|
|
67
|
-
this.blockExplorer = (
|
|
68
|
-
this.network = (
|
|
69
|
-
(0, octez_connect_ui_1.setColorMode)((
|
|
90
|
+
this.events = new events_1.BeaconEventHandler(config.eventHandlers, (_d = config.disableDefaultEvents) !== null && _d !== void 0 ? _d : false);
|
|
91
|
+
this.blockExplorer = (_e = config.blockExplorer) !== null && _e !== void 0 ? _e : new tzkt_blockexplorer_1.TzktBlockExplorer();
|
|
92
|
+
this.network = (_f = config.network) !== null && _f !== void 0 ? _f : { type: (_g = config.preferredNetwork) !== null && _g !== void 0 ? _g : octez_connect_types_1.NetworkType.MAINNET };
|
|
93
|
+
(0, octez_connect_ui_1.setColorMode)((_h = config.colorMode) !== null && _h !== void 0 ? _h : octez_connect_types_1.ColorMode.LIGHT);
|
|
70
94
|
this.disclaimerText = config.disclaimerText;
|
|
71
|
-
this.errorMessages = (
|
|
95
|
+
this.errorMessages = (_j = config.errorMessages) !== null && _j !== void 0 ? _j : {};
|
|
72
96
|
this.appMetadataManager = new octez_connect_core_1.AppMetadataManager(this.storage);
|
|
73
97
|
this.storageValidator = new octez_connect_core_1.StorageValidator(this.storage);
|
|
74
98
|
this.enableAppSwitching =
|
|
75
99
|
config.enableAppSwitching === undefined ? true : !!config.enableAppSwitching;
|
|
76
100
|
this.enableMetrics = config.enableMetrics ? true : false;
|
|
101
|
+
this.requestTimeoutMs = (_k = config.requestTimeoutMs) !== null && _k !== void 0 ? _k : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
77
102
|
// Subscribe to storage changes and update the active account if it changes on other tabs
|
|
78
103
|
this.storage.subscribeToStorageChanged((event) => __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
if (event.oldValue === event.newValue) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
79
107
|
if (event.eventType === 'storageCleared') {
|
|
80
|
-
this.setActiveAccount(undefined);
|
|
108
|
+
yield this.setActiveAccount(undefined);
|
|
81
109
|
return;
|
|
82
110
|
}
|
|
83
111
|
if (event.eventType === 'entryModified') {
|
|
84
112
|
if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT)) {
|
|
85
113
|
const accountIdentifier = event.newValue;
|
|
86
114
|
if (!accountIdentifier || accountIdentifier === 'undefined') {
|
|
87
|
-
this.setActiveAccount(undefined);
|
|
115
|
+
yield this.setActiveAccount(undefined);
|
|
88
116
|
}
|
|
89
117
|
else {
|
|
90
118
|
const account = yield this.getAccount(accountIdentifier);
|
|
91
|
-
this.setActiveAccount(account);
|
|
119
|
+
yield this.setActiveAccount(account);
|
|
92
120
|
}
|
|
93
121
|
return;
|
|
94
122
|
}
|
|
123
|
+
if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ACCOUNTS)) {
|
|
124
|
+
yield this.recoverActiveAccountFromAccountsChange();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
95
127
|
if (event.key === this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ENABLE_METRICS)) {
|
|
96
128
|
this.enableMetrics = !!(yield this.storage.get(octez_connect_types_1.StorageKey.ENABLE_METRICS));
|
|
97
129
|
return;
|
|
@@ -107,31 +139,43 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
107
139
|
this.activeAccountLoaded = this.storage
|
|
108
140
|
.get(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT)
|
|
109
141
|
.then((activeAccountIdentifier) => __awaiter(this, void 0, void 0, function* () {
|
|
142
|
+
const accounts = yield this.accountManager.getAccounts();
|
|
143
|
+
if (activeAccountIdentifier === 'undefined') {
|
|
144
|
+
// Non-normalizing storage backends can still surface legacy sentinel strings directly.
|
|
145
|
+
yield this.deactivateInvalidAccountState('missing_active_account');
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
110
148
|
if (activeAccountIdentifier) {
|
|
111
|
-
const account =
|
|
149
|
+
const account = accounts.find((storedAccount) => storedAccount.accountIdentifier === activeAccountIdentifier);
|
|
150
|
+
if (!account) {
|
|
151
|
+
yield this.deactivateInvalidAccountState('missing_active_account');
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
112
154
|
yield this.setActiveAccount(account);
|
|
113
155
|
return account;
|
|
114
156
|
}
|
|
115
|
-
|
|
116
|
-
yield this.
|
|
157
|
+
if (accounts.length > 0 && this.hasStoredActiveAccountPointer()) {
|
|
158
|
+
yield this.deactivateInvalidAccountState('missing_active_account');
|
|
117
159
|
return undefined;
|
|
118
160
|
}
|
|
161
|
+
yield this.setActiveAccount(undefined);
|
|
162
|
+
return undefined;
|
|
119
163
|
}))
|
|
120
164
|
.catch((storageError) => __awaiter(this, void 0, void 0, function* () {
|
|
121
165
|
logger.error(storageError);
|
|
122
|
-
yield this.
|
|
123
|
-
this.events.emit(events_1.BeaconEvent.INVALID_ACCOUNT_DEACTIVATED);
|
|
166
|
+
yield this.deactivateInvalidAccountState('invalid_active_account_storage');
|
|
124
167
|
return undefined;
|
|
125
168
|
}));
|
|
126
169
|
this.handleResponse = (message, connectionInfo) => __awaiter(this, void 0, void 0, function* () {
|
|
127
170
|
var _a;
|
|
128
|
-
const
|
|
171
|
+
const isV3WrappedMessage = message.version === '3' && 'message' in message;
|
|
172
|
+
const typedMessage = isV3WrappedMessage
|
|
129
173
|
? message.message
|
|
130
174
|
: message;
|
|
131
|
-
let appMetadata =
|
|
175
|
+
let appMetadata = isV3WrappedMessage
|
|
132
176
|
? (_a = typedMessage.blockchainData) === null || _a === void 0 ? void 0 : _a.appMetadata
|
|
133
177
|
: typedMessage.appMetadata;
|
|
134
|
-
if (!appMetadata &&
|
|
178
|
+
if (!appMetadata && isV3WrappedMessage) {
|
|
135
179
|
const storedMetadata = yield Promise.all([
|
|
136
180
|
this.storage.get(octez_connect_types_1.StorageKey.TRANSPORT_P2P_PEERS_DAPP),
|
|
137
181
|
this.storage.get(octez_connect_types_1.StorageKey.TRANSPORT_WALLETCONNECT_PEERS_DAPP),
|
|
@@ -160,8 +204,11 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
160
204
|
},
|
|
161
205
|
id: message.id
|
|
162
206
|
});
|
|
163
|
-
if (typedMessage.type
|
|
164
|
-
this.
|
|
207
|
+
if (typedMessage.type === octez_connect_types_1.BeaconMessageType.Acknowledge) {
|
|
208
|
+
this.clearOpenRequestTimeout(message.id);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.clearOpenRequest(message.id);
|
|
165
212
|
}
|
|
166
213
|
return;
|
|
167
214
|
}
|
|
@@ -189,15 +236,19 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
189
236
|
yield this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED);
|
|
190
237
|
});
|
|
191
238
|
if (openRequest && typedMessage.type === octez_connect_types_1.BeaconMessageType.Acknowledge) {
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
.
|
|
196
|
-
message
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
239
|
+
if (!this.acknowledgedRequests.has(message.id)) {
|
|
240
|
+
this.acknowledgedRequests.add(message.id);
|
|
241
|
+
this.clearOpenRequestTimeout(message.id);
|
|
242
|
+
this.analytics.track('event', 'DAppClient', 'Acknowledge received from Wallet');
|
|
243
|
+
logger.log('handleResponse', `acknowledge message received for ${message.id}`);
|
|
244
|
+
this.events
|
|
245
|
+
.emit(events_1.BeaconEvent.ACKNOWLEDGE_RECEIVED, {
|
|
246
|
+
message: typedMessage,
|
|
247
|
+
extraInfo: {},
|
|
248
|
+
walletInfo: yield this.getWalletInfo()
|
|
249
|
+
})
|
|
250
|
+
.catch((emitError) => logger.error('handleResponse', emitError));
|
|
251
|
+
}
|
|
201
252
|
}
|
|
202
253
|
else if (openRequest) {
|
|
203
254
|
if (typedMessage.type === octez_connect_types_1.BeaconMessageType.PermissionResponse && appMetadata) {
|
|
@@ -209,7 +260,8 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
209
260
|
else {
|
|
210
261
|
openRequest.resolve({ message, connectionInfo });
|
|
211
262
|
}
|
|
212
|
-
this.
|
|
263
|
+
this.clearOpenRequest(message.id);
|
|
264
|
+
this.acknowledgedRequests.delete(message.id);
|
|
213
265
|
}
|
|
214
266
|
else {
|
|
215
267
|
if (typedMessage.type === octez_connect_types_1.BeaconMessageType.Disconnect) {
|
|
@@ -218,16 +270,23 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
218
270
|
else if (typedMessage.type === octez_connect_types_1.BeaconMessageType.ChangeAccountRequest) {
|
|
219
271
|
yield this.onNewAccount(typedMessage, connectionInfo);
|
|
220
272
|
}
|
|
273
|
+
else {
|
|
274
|
+
logger.warn('handleResponse', 'received response for unknown or closed request', {
|
|
275
|
+
id: message.id,
|
|
276
|
+
type: typedMessage.type,
|
|
277
|
+
connectionInfo
|
|
278
|
+
});
|
|
279
|
+
}
|
|
221
280
|
}
|
|
222
281
|
if (this._transport.isResolved()) {
|
|
223
282
|
const transport = yield this.transport;
|
|
224
283
|
if (transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport &&
|
|
225
|
-
!this.openRequests.has(
|
|
226
|
-
this.openRequests.set(
|
|
284
|
+
!this.openRequests.has(SESSION_UPDATE_REQUEST_ID)) {
|
|
285
|
+
this.openRequests.set(SESSION_UPDATE_REQUEST_ID, new octez_connect_utils_1.ExposedPromise());
|
|
227
286
|
}
|
|
228
287
|
}
|
|
229
288
|
});
|
|
230
|
-
this.storageValidator
|
|
289
|
+
this.storageValidated = this.storageValidator
|
|
231
290
|
.validate()
|
|
232
291
|
.then((isValid) => __awaiter(this, void 0, void 0, function* () {
|
|
233
292
|
var _a, _b;
|
|
@@ -244,15 +303,22 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
244
303
|
url: info.deeplink
|
|
245
304
|
});
|
|
246
305
|
const nowValid = yield this.storageValidator.validate();
|
|
247
|
-
if (!nowValid) {
|
|
248
|
-
this.
|
|
306
|
+
if (!nowValid && account) {
|
|
307
|
+
yield this.deactivateInvalidAccountState('storage_validation_failed');
|
|
308
|
+
}
|
|
309
|
+
else if (!nowValid) {
|
|
310
|
+
yield this.resetInvalidState(false);
|
|
249
311
|
}
|
|
250
312
|
}
|
|
251
313
|
if (account && account.origin.type !== 'p2p') {
|
|
252
|
-
|
|
314
|
+
// Fire-and-forget eager init for stored sessions. init() can now
|
|
315
|
+
// reject (e.g. when an abort path settles _initPromise), so swallow
|
|
316
|
+
// here; downstream callers of init() handle rejection on their own.
|
|
317
|
+
this.init().catch((initError) => { var _a; return logger.error('eager init failed', (_a = initError === null || initError === void 0 ? void 0 : initError.message) !== null && _a !== void 0 ? _a : initError); });
|
|
253
318
|
}
|
|
254
319
|
}))
|
|
255
320
|
.catch((err) => logger.error(err.message));
|
|
321
|
+
this.retainStorageValidationPromise();
|
|
256
322
|
this.sendMetrics('enable-metrics?' + this.addQueryParam('version', octez_connect_core_1.SDK_VERSION), undefined, (res) => {
|
|
257
323
|
if (!res.ok) {
|
|
258
324
|
res.status === 426
|
|
@@ -330,11 +396,42 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
330
396
|
const transport = (yield this._transport.promise);
|
|
331
397
|
yield transport.waitForResolution();
|
|
332
398
|
this.openRequestsOtherTabs.add(message.id);
|
|
333
|
-
isV3
|
|
399
|
+
const requestPromise = isV3
|
|
334
400
|
? this.makeRequestV3(message.data, message.id)
|
|
335
401
|
: this.makeRequest(message.data, false, message.id);
|
|
402
|
+
requestPromise.catch((requestError) => {
|
|
403
|
+
const errorResponse = this.buildDelegatedRequestError(message.id, requestError);
|
|
404
|
+
this.multiTabChannel.postMessage({
|
|
405
|
+
type: 'RESPONSE',
|
|
406
|
+
data: {
|
|
407
|
+
message: errorResponse,
|
|
408
|
+
connectionInfo: {
|
|
409
|
+
origin: octez_connect_types_1.Origin.WALLETCONNECT,
|
|
410
|
+
id: ''
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
id: message.id
|
|
414
|
+
});
|
|
415
|
+
this.clearOpenRequest(message.id);
|
|
416
|
+
});
|
|
336
417
|
});
|
|
337
418
|
}
|
|
419
|
+
buildDelegatedRequestError(id, error) {
|
|
420
|
+
if (typeof error === 'object' &&
|
|
421
|
+
error !== null &&
|
|
422
|
+
'type' in error &&
|
|
423
|
+
'errorType' in error &&
|
|
424
|
+
error.type === octez_connect_types_1.BeaconMessageType.Error) {
|
|
425
|
+
return Object.assign(Object.assign({}, error), { id });
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
id,
|
|
429
|
+
type: octez_connect_types_1.BeaconMessageType.Error,
|
|
430
|
+
errorType: octez_connect_types_1.BeaconErrorType.UNKNOWN_ERROR,
|
|
431
|
+
senderId: '',
|
|
432
|
+
version: '2'
|
|
433
|
+
};
|
|
434
|
+
}
|
|
338
435
|
createStateSnapshot() {
|
|
339
436
|
return __awaiter(this, void 0, void 0, function* () {
|
|
340
437
|
if (!localStorage || !this.enableMetrics) {
|
|
@@ -365,10 +462,7 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
365
462
|
initInternalTransports() {
|
|
366
463
|
return __awaiter(this, void 0, void 0, function* () {
|
|
367
464
|
var _a, _b;
|
|
368
|
-
const seed = yield this.
|
|
369
|
-
if (!seed) {
|
|
370
|
-
throw new Error('Secret seed not found');
|
|
371
|
-
}
|
|
465
|
+
const seed = yield this.getOrCreateSDKSecretSeed();
|
|
372
466
|
const keyPair = yield (0, octez_connect_utils_1.getKeypairFromSeed)(seed);
|
|
373
467
|
if (this.postMessageTransport || this.p2pTransport || this.walletConnectTransport) {
|
|
374
468
|
return;
|
|
@@ -377,6 +471,11 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
377
471
|
yield this.addListener(this.postMessageTransport);
|
|
378
472
|
this.p2pTransport = new DappP2PTransport_1.DappP2PTransport(this.name, keyPair, this.storage, this.matrixNodes, this.iconUrl, this.appUrl);
|
|
379
473
|
yield this.addListener(this.p2pTransport);
|
|
474
|
+
// Skip WalletConnect entirely when disabled (e.g. inside a Firefox MV3 content-script
|
|
475
|
+
// compartment where the WC provider cannot run). postMessage + P2P are unaffected.
|
|
476
|
+
if (this.disableWalletConnect) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
380
479
|
const wcOptions = {
|
|
381
480
|
projectId: this.wcProjectId,
|
|
382
481
|
relayUrl: this.wcRelayUrl,
|
|
@@ -395,6 +494,41 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
395
494
|
yield this.addListener(this.walletConnectTransport);
|
|
396
495
|
});
|
|
397
496
|
}
|
|
497
|
+
getOrCreateSDKSecretSeed() {
|
|
498
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
499
|
+
if (this._sdkSecretSeedPromise) {
|
|
500
|
+
return this._sdkSecretSeedPromise;
|
|
501
|
+
}
|
|
502
|
+
this._sdkSecretSeedPromise = this.loadOrCreateSDKSecretSeed()
|
|
503
|
+
.finally(() => {
|
|
504
|
+
this._sdkSecretSeedPromise = undefined;
|
|
505
|
+
})
|
|
506
|
+
.catch((error) => {
|
|
507
|
+
throw error;
|
|
508
|
+
});
|
|
509
|
+
return this._sdkSecretSeedPromise;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
loadOrCreateSDKSecretSeed() {
|
|
513
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
514
|
+
const existingSeed = yield this.storage.get(octez_connect_types_1.StorageKey.BEACON_SDK_SECRET_SEED);
|
|
515
|
+
if (this.isValidSDKSecretSeed(existingSeed)) {
|
|
516
|
+
return existingSeed;
|
|
517
|
+
}
|
|
518
|
+
yield this.storage.delete(octez_connect_types_1.StorageKey.BEACON_SDK_SECRET_SEED);
|
|
519
|
+
this._keyPair = new octez_connect_utils_1.ExposedPromise();
|
|
520
|
+
this._beaconId = new octez_connect_utils_1.ExposedPromise();
|
|
521
|
+
yield this.initSDK();
|
|
522
|
+
const restoredSeed = yield this.storage.get(octez_connect_types_1.StorageKey.BEACON_SDK_SECRET_SEED);
|
|
523
|
+
if (this.isValidSDKSecretSeed(restoredSeed)) {
|
|
524
|
+
return restoredSeed;
|
|
525
|
+
}
|
|
526
|
+
throw new Error('Secret seed not found');
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
isValidSDKSecretSeed(seed) {
|
|
530
|
+
return typeof seed === 'string' && seed !== '' && seed !== 'undefined' && seed !== 'null';
|
|
531
|
+
}
|
|
398
532
|
initEvents() {
|
|
399
533
|
if (!this.walletConnectTransport) {
|
|
400
534
|
return;
|
|
@@ -412,6 +546,7 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
412
546
|
}
|
|
413
547
|
wcToastHandler(status) {
|
|
414
548
|
return __awaiter(this, void 0, void 0, function* () {
|
|
549
|
+
var _a;
|
|
415
550
|
const walletInfo = yield (() => __awaiter(this, void 0, void 0, function* () {
|
|
416
551
|
try {
|
|
417
552
|
return yield this.getWalletInfo();
|
|
@@ -429,22 +564,28 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
429
564
|
});
|
|
430
565
|
}
|
|
431
566
|
else {
|
|
432
|
-
this
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
567
|
+
// The WC transport reports session-proposal rejection through this event
|
|
568
|
+
// when there are no active listeners yet (no peer paired). Reject the
|
|
569
|
+
// in-flight init promise so `await dapp.requestPermissions()` unwinds
|
|
570
|
+
// through requestPermissions' catch -> handleRequestError, which both
|
|
571
|
+
// emits PERMISSION_REQUEST_ERROR and resets transport state. Without
|
|
572
|
+
// this, the dapp wedges with a pending `_initPromise`.
|
|
573
|
+
(_a = this._initReject) === null || _a === void 0 ? void 0 : _a.call(this, this.createAbortedError());
|
|
436
574
|
}
|
|
437
575
|
});
|
|
438
576
|
}
|
|
439
577
|
channelClosedHandler(type) {
|
|
440
578
|
return __awaiter(this, void 0, void 0, function* () {
|
|
579
|
+
if (!this._transport.isResolved()) {
|
|
580
|
+
yield this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
441
583
|
const transport = yield this.transport;
|
|
442
584
|
if (transport.type !== type) {
|
|
443
585
|
return;
|
|
444
586
|
}
|
|
445
587
|
yield this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED);
|
|
446
|
-
this.
|
|
447
|
-
yield this.disconnect();
|
|
588
|
+
yield this.disconnect({ notifyPeers: false });
|
|
448
589
|
});
|
|
449
590
|
}
|
|
450
591
|
/**
|
|
@@ -459,16 +600,81 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
459
600
|
destroy: { get: () => super.destroy }
|
|
460
601
|
});
|
|
461
602
|
return __awaiter(this, void 0, void 0, function* () {
|
|
603
|
+
this.destroyed = true;
|
|
462
604
|
yield this.createStateSnapshot();
|
|
605
|
+
yield this.destroyInternalTransports();
|
|
463
606
|
yield _super.destroy.call(this);
|
|
464
607
|
});
|
|
465
608
|
}
|
|
609
|
+
destroyInternalTransports() {
|
|
610
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
611
|
+
this.abortPendingInit();
|
|
612
|
+
const transports = [];
|
|
613
|
+
if (this.postMessageTransport) {
|
|
614
|
+
transports.push(this.postMessageTransport);
|
|
615
|
+
}
|
|
616
|
+
if (this.p2pTransport) {
|
|
617
|
+
transports.push(this.p2pTransport);
|
|
618
|
+
}
|
|
619
|
+
if (this.walletConnectTransport) {
|
|
620
|
+
transports.push(this.walletConnectTransport);
|
|
621
|
+
}
|
|
622
|
+
if (transports.length > 0) {
|
|
623
|
+
yield this.cleanup(transports);
|
|
624
|
+
yield Promise.all(transports.map((transport) => __awaiter(this, void 0, void 0, function* () {
|
|
625
|
+
yield transport.disconnect();
|
|
626
|
+
if ('doClientCleanup' in transport) {
|
|
627
|
+
yield transport.doClientCleanup();
|
|
628
|
+
}
|
|
629
|
+
})));
|
|
630
|
+
this.postMessageTransport = this.p2pTransport = this.walletConnectTransport = undefined;
|
|
631
|
+
yield this.setTransport(undefined);
|
|
632
|
+
}
|
|
633
|
+
yield this.multiTabChannel.close();
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
abortPendingInit() {
|
|
637
|
+
var _a;
|
|
638
|
+
(_a = this._initReject) === null || _a === void 0 ? void 0 : _a.call(this, this.createAbortedError());
|
|
639
|
+
this._initPromise = undefined;
|
|
640
|
+
this._initReject = undefined;
|
|
641
|
+
this._initSubstratePairing = undefined;
|
|
642
|
+
this._requestPermissionsPromise = undefined;
|
|
643
|
+
this._requestPermissionsKey = undefined;
|
|
644
|
+
}
|
|
645
|
+
createAbortedError(id = '') {
|
|
646
|
+
return {
|
|
647
|
+
type: octez_connect_types_1.BeaconMessageType.Error,
|
|
648
|
+
id,
|
|
649
|
+
senderId: '',
|
|
650
|
+
version: '2',
|
|
651
|
+
errorType: octez_connect_types_1.BeaconErrorType.ABORTED_ERROR
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* @internal
|
|
656
|
+
*/
|
|
657
|
+
isDestroyed() {
|
|
658
|
+
return this.destroyed;
|
|
659
|
+
}
|
|
660
|
+
assertNotDestroyed() {
|
|
661
|
+
if (this.destroyed) {
|
|
662
|
+
throw new Error('DAppClient has been destroyed and cannot be used again.');
|
|
663
|
+
}
|
|
664
|
+
}
|
|
466
665
|
init(transport, substratePairing) {
|
|
467
666
|
const _super = Object.create(null, {
|
|
468
667
|
init: { get: () => super.init }
|
|
469
668
|
});
|
|
470
669
|
return __awaiter(this, void 0, void 0, function* () {
|
|
670
|
+
this.assertNotDestroyed();
|
|
671
|
+
const requestedSubstratePairing = substratePairing === true;
|
|
471
672
|
if (this._initPromise) {
|
|
673
|
+
if (!transport &&
|
|
674
|
+
this._initReject &&
|
|
675
|
+
this._initSubstratePairing !== requestedSubstratePairing) {
|
|
676
|
+
throw new Error('Cannot start a permission request with different pairing options while another pairing is pending');
|
|
677
|
+
}
|
|
472
678
|
return this._initPromise;
|
|
473
679
|
}
|
|
474
680
|
try {
|
|
@@ -477,163 +683,260 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
477
683
|
catch (_a) {
|
|
478
684
|
//
|
|
479
685
|
}
|
|
480
|
-
this._initPromise = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
|
-
yield this.initInternalTransports();
|
|
503
|
-
if (!this.postMessageTransport || !this.p2pTransport || !this.walletConnectTransport) {
|
|
504
|
-
return;
|
|
686
|
+
this._initPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
687
|
+
this._initSubstratePairing = requestedSubstratePairing;
|
|
688
|
+
// Capture reject so abort paths (modal close, transport-level rejection)
|
|
689
|
+
// can unwedge a pending `await this.init()`. _initReject is cleared by
|
|
690
|
+
// the .finally below whether the promise resolves or rejects, so the
|
|
691
|
+
// field accurately means "currently rejectable" rather than "most recent
|
|
692
|
+
// rejector".
|
|
693
|
+
this._initReject = (reason) => {
|
|
694
|
+
this._initPromise = undefined;
|
|
695
|
+
reject(reason);
|
|
696
|
+
};
|
|
697
|
+
// The body uses `new Promise(async ...)` (an anti-pattern: unhandled
|
|
698
|
+
// throws are swallowed). Wrap it so any unexpected throw rejects the
|
|
699
|
+
// promise instead of stranding `await this.init()` callers forever.
|
|
700
|
+
// A proper structural fix would replace the async-executor entirely
|
|
701
|
+
// with chained promises; left as follow-up to keep this PR focused.
|
|
702
|
+
try {
|
|
703
|
+
if (transport) {
|
|
704
|
+
yield this.addListener(transport);
|
|
705
|
+
resolve(yield _super.init.call(this, transport));
|
|
505
706
|
}
|
|
506
|
-
this.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
// Select the transport that matches the active account
|
|
510
|
-
if (origin === octez_connect_types_1.Origin.EXTENSION) {
|
|
511
|
-
resolve(yield _super.init.call(this, this.postMessageTransport));
|
|
512
|
-
}
|
|
513
|
-
else if (origin === octez_connect_types_1.Origin.P2P) {
|
|
514
|
-
resolve(yield _super.init.call(this, this.p2pTransport));
|
|
515
|
-
}
|
|
516
|
-
else if (origin === octez_connect_types_1.Origin.WALLETCONNECT) {
|
|
517
|
-
resolve(yield _super.init.call(this, this.walletConnectTransport));
|
|
518
|
-
}
|
|
707
|
+
else if (this._transport.isSettled()) {
|
|
708
|
+
yield (yield this.transport).connect();
|
|
709
|
+
resolve(yield _super.init.call(this, yield this.transport));
|
|
519
710
|
}
|
|
520
711
|
else {
|
|
521
|
-
const
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
this.
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
this.
|
|
531
|
-
.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
.
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
712
|
+
const activeAccount = yield this.getActiveAccount();
|
|
713
|
+
const stopListening = () => {
|
|
714
|
+
const onError = (err) => logger.error('stopListeningForNewPeers', err);
|
|
715
|
+
if (this.postMessageTransport) {
|
|
716
|
+
this.postMessageTransport.stopListeningForNewPeers().catch(onError);
|
|
717
|
+
}
|
|
718
|
+
if (this.p2pTransport) {
|
|
719
|
+
this.p2pTransport.stopListeningForNewPeers().catch(onError);
|
|
720
|
+
}
|
|
721
|
+
if (this.walletConnectTransport) {
|
|
722
|
+
this.walletConnectTransport.stopListeningForNewPeers().catch(onError);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
yield this.initInternalTransports();
|
|
726
|
+
if (!this.postMessageTransport ||
|
|
727
|
+
!this.p2pTransport ||
|
|
728
|
+
(!this.disableWalletConnect && !this.walletConnectTransport)) {
|
|
729
|
+
// Bare return here used to strand the promise forever -- no UI is
|
|
730
|
+
// emitted, no peer ever pairs, no abort path fires. Reject explicitly
|
|
731
|
+
// so callers see a deterministic error. (WalletConnect is exempt when
|
|
732
|
+
// disableWalletConnect is set -- its transport is intentionally absent.)
|
|
733
|
+
const noTransportError = {
|
|
734
|
+
type: octez_connect_types_1.BeaconMessageType.Error,
|
|
735
|
+
id: '',
|
|
736
|
+
senderId: '',
|
|
737
|
+
version: '2',
|
|
738
|
+
errorType: octez_connect_types_1.BeaconErrorType.UNKNOWN_ERROR
|
|
739
|
+
};
|
|
740
|
+
reject(noTransportError);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
this.postMessageTransport.connect().then().catch(console.error);
|
|
744
|
+
if (activeAccount && activeAccount.origin) {
|
|
745
|
+
const origin = activeAccount.origin.type;
|
|
746
|
+
// Select the transport that matches the active account
|
|
747
|
+
if (origin === octez_connect_types_1.Origin.EXTENSION) {
|
|
748
|
+
resolve(yield _super.init.call(this, this.postMessageTransport));
|
|
749
|
+
}
|
|
750
|
+
else if (origin === octez_connect_types_1.Origin.P2P) {
|
|
751
|
+
resolve(yield _super.init.call(this, this.p2pTransport));
|
|
752
|
+
}
|
|
753
|
+
else if (origin === octez_connect_types_1.Origin.WALLETCONNECT && this.walletConnectTransport) {
|
|
754
|
+
resolve(yield _super.init.call(this, this.walletConnectTransport));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
const p2pTransport = this.p2pTransport;
|
|
759
|
+
const postMessageTransport = this.postMessageTransport;
|
|
760
|
+
const walletConnectTransport = this.walletConnectTransport;
|
|
761
|
+
postMessageTransport
|
|
762
|
+
.listenForNewPeer((peer) => {
|
|
763
|
+
logger.log('init', 'postmessage transport peer connected', peer);
|
|
764
|
+
this.analytics.track('event', 'DAppClient', 'Extension connected', {
|
|
765
|
+
peerName: peer.name
|
|
766
|
+
});
|
|
767
|
+
this.events
|
|
768
|
+
.emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
|
|
769
|
+
.catch((emitError) => console.warn(emitError));
|
|
770
|
+
this.setActivePeer(peer).catch(console.error);
|
|
771
|
+
this.setTransport(this.postMessageTransport).catch(console.error);
|
|
772
|
+
stopListening();
|
|
773
|
+
resolve(octez_connect_types_1.TransportType.POST_MESSAGE);
|
|
774
|
+
})
|
|
775
|
+
.catch(console.error);
|
|
776
|
+
p2pTransport
|
|
777
|
+
.listenForNewPeer((peer) => {
|
|
778
|
+
logger.log('init', 'p2p transport peer connected', peer);
|
|
779
|
+
this.analytics.track('event', 'DAppClient', 'octez.connect Wallet connected', {
|
|
780
|
+
peerName: peer.name
|
|
781
|
+
});
|
|
782
|
+
this.events
|
|
783
|
+
.emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
|
|
784
|
+
.catch((emitError) => console.warn(emitError));
|
|
785
|
+
this.setActivePeer(peer).catch(console.error);
|
|
786
|
+
this.setTransport(this.p2pTransport).catch(console.error);
|
|
787
|
+
stopListening();
|
|
788
|
+
resolve(octez_connect_types_1.TransportType.P2P);
|
|
789
|
+
})
|
|
790
|
+
.catch(console.error);
|
|
791
|
+
walletConnectTransport === null || walletConnectTransport === void 0 ? void 0 : walletConnectTransport.listenForNewPeer((peer) => {
|
|
792
|
+
logger.log('init', 'walletconnect transport peer connected', peer);
|
|
793
|
+
this.analytics.track('event', 'DAppClient', 'WalletConnect Wallet connected', {
|
|
794
|
+
peerName: peer.name
|
|
795
|
+
});
|
|
796
|
+
this.events
|
|
797
|
+
.emit(events_1.BeaconEvent.PAIR_SUCCESS, peer)
|
|
798
|
+
.catch((emitError) => console.warn(emitError));
|
|
799
|
+
this.setActivePeer(peer).catch(console.error);
|
|
800
|
+
this.setTransport(this.walletConnectTransport).catch(console.error);
|
|
801
|
+
stopListening();
|
|
802
|
+
resolve(octez_connect_types_1.TransportType.WALLETCONNECT);
|
|
803
|
+
}).catch(console.error);
|
|
804
|
+
octez_connect_transport_postmessage_1.PostMessageTransport.getAvailableExtensions()
|
|
805
|
+
.then((extensions) => __awaiter(this, void 0, void 0, function* () {
|
|
806
|
+
this.analytics.track('event', 'DAppClient', 'Extensions detected', { extensions });
|
|
807
|
+
}))
|
|
808
|
+
.catch((error) => {
|
|
809
|
+
this._initPromise = undefined;
|
|
810
|
+
console.error(error);
|
|
544
811
|
});
|
|
545
|
-
this
|
|
546
|
-
|
|
547
|
-
.
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
812
|
+
const abortHandler = () => __awaiter(this, void 0, void 0, function* () {
|
|
813
|
+
var _a;
|
|
814
|
+
logger.log('init', 'ABORTED');
|
|
815
|
+
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'abort'));
|
|
816
|
+
yield Promise.all([
|
|
817
|
+
postMessageTransport.disconnect(),
|
|
818
|
+
// p2pTransport.disconnect(), do not abort connection manually
|
|
819
|
+
walletConnectTransport === null || walletConnectTransport === void 0 ? void 0 : walletConnectTransport.disconnect()
|
|
820
|
+
]);
|
|
821
|
+
this.postMessageTransport = this.walletConnectTransport = this.p2pTransport = undefined;
|
|
822
|
+
this._activeAccount.isResolved() && this.clearActiveAccount();
|
|
823
|
+
// Reject _initPromise so any awaiter (makeRequest -> requestPermissions)
|
|
824
|
+
// unwinds via handleRequestError instead of hanging. _initReject
|
|
825
|
+
// also clears _initPromise as a side effect.
|
|
826
|
+
(_a = this._initReject) === null || _a === void 0 ? void 0 : _a.call(this, this.createAbortedError());
|
|
559
827
|
});
|
|
828
|
+
const serializer = new octez_connect_core_1.Serializer();
|
|
829
|
+
const p2pPeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
830
|
+
try {
|
|
831
|
+
yield p2pTransport.connect();
|
|
832
|
+
}
|
|
833
|
+
catch (err) {
|
|
834
|
+
logger.error(err);
|
|
835
|
+
yield this.hideUI(['alert']); // hide pairing alert
|
|
836
|
+
setTimeout(() => this.events.emit(events_1.BeaconEvent.GENERIC_ERROR, err.message), 1000);
|
|
837
|
+
abortHandler().catch((abortErr) => logger.warn('init', 'abortHandler', abortErr));
|
|
838
|
+
resolve('');
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
resolve(yield serializer.serialize(yield p2pTransport.getPairingRequestInfo()));
|
|
842
|
+
}));
|
|
843
|
+
const walletConnectPeerInfo = walletConnectTransport
|
|
844
|
+
? createLazyPromise(() => walletConnectTransport
|
|
845
|
+
.getPairingRequestInfo()
|
|
846
|
+
.then((pairingRequestInfo) => pairingRequestInfo.uri)
|
|
847
|
+
.catch((error) => {
|
|
848
|
+
logger.warn('init', 'walletconnect pairing request failed', error);
|
|
849
|
+
return '';
|
|
850
|
+
}))
|
|
851
|
+
: undefined;
|
|
852
|
+
const postmessagePeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
853
|
+
resolve(yield serializer.serialize(yield postMessageTransport.getPairingRequestInfo()));
|
|
854
|
+
}));
|
|
560
855
|
this.events
|
|
561
|
-
.emit(events_1.BeaconEvent.
|
|
856
|
+
.emit(events_1.BeaconEvent.PAIR_INIT, Object.assign(Object.assign({ p2pPeerInfo,
|
|
857
|
+
postmessagePeerInfo }, (walletConnectPeerInfo ? { walletConnectPeerInfo } : {})), { networkType: this.network.type, abortedHandler: abortHandler.bind(this), disclaimerText: this.disclaimerText, analytics: this.analytics, featuredWallets: this.featuredWallets, substratePairing }))
|
|
562
858
|
.catch((emitError) => console.warn(emitError));
|
|
563
|
-
|
|
564
|
-
this.setTransport(this.walletConnectTransport).catch(console.error);
|
|
565
|
-
stopListening();
|
|
566
|
-
resolve(octez_connect_types_1.TransportType.WALLETCONNECT);
|
|
567
|
-
})
|
|
568
|
-
.catch(console.error);
|
|
569
|
-
octez_connect_transport_postmessage_1.PostMessageTransport.getAvailableExtensions()
|
|
570
|
-
.then((extensions) => __awaiter(this, void 0, void 0, function* () {
|
|
571
|
-
this.analytics.track('event', 'DAppClient', 'Extensions detected', { extensions });
|
|
572
|
-
}))
|
|
573
|
-
.catch((error) => {
|
|
574
|
-
this._initPromise = undefined;
|
|
575
|
-
console.error(error);
|
|
576
|
-
});
|
|
577
|
-
const abortHandler = () => __awaiter(this, void 0, void 0, function* () {
|
|
578
|
-
logger.log('init', 'ABORTED');
|
|
579
|
-
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'abort'));
|
|
580
|
-
yield Promise.all([
|
|
581
|
-
postMessageTransport.disconnect(),
|
|
582
|
-
// p2pTransport.disconnect(), do not abort connection manually
|
|
583
|
-
walletConnectTransport.disconnect()
|
|
584
|
-
]);
|
|
585
|
-
this.postMessageTransport = this.walletConnectTransport = this.p2pTransport = undefined;
|
|
586
|
-
this._activeAccount.isResolved() && this.clearActiveAccount();
|
|
587
|
-
this._initPromise = undefined;
|
|
588
|
-
});
|
|
589
|
-
const serializer = new octez_connect_core_1.Serializer();
|
|
590
|
-
const p2pPeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
591
|
-
try {
|
|
592
|
-
yield p2pTransport.connect();
|
|
593
|
-
}
|
|
594
|
-
catch (err) {
|
|
595
|
-
logger.error(err);
|
|
596
|
-
yield this.hideUI(['alert']); // hide pairing alert
|
|
597
|
-
setTimeout(() => this.events.emit(events_1.BeaconEvent.GENERIC_ERROR, err.message), 1000);
|
|
598
|
-
abortHandler();
|
|
599
|
-
resolve('');
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
resolve(yield serializer.serialize(yield p2pTransport.getPairingRequestInfo()));
|
|
603
|
-
}));
|
|
604
|
-
const walletConnectPeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
605
|
-
resolve((yield walletConnectTransport.getPairingRequestInfo()).uri);
|
|
606
|
-
}));
|
|
607
|
-
const postmessagePeerInfo = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
608
|
-
resolve(yield serializer.serialize(yield postMessageTransport.getPairingRequestInfo()));
|
|
609
|
-
}));
|
|
610
|
-
this.events
|
|
611
|
-
.emit(events_1.BeaconEvent.PAIR_INIT, {
|
|
612
|
-
p2pPeerInfo,
|
|
613
|
-
postmessagePeerInfo,
|
|
614
|
-
walletConnectPeerInfo,
|
|
615
|
-
networkType: this.network.type,
|
|
616
|
-
abortedHandler: abortHandler.bind(this),
|
|
617
|
-
disclaimerText: this.disclaimerText,
|
|
618
|
-
analytics: this.analytics,
|
|
619
|
-
featuredWallets: this.featuredWallets,
|
|
620
|
-
substratePairing
|
|
621
|
-
})
|
|
622
|
-
.catch((emitError) => console.warn(emitError));
|
|
859
|
+
}
|
|
623
860
|
}
|
|
624
861
|
}
|
|
862
|
+
catch (err) {
|
|
863
|
+
// An async-executor throw would otherwise be silently swallowed,
|
|
864
|
+
// leaving _initPromise pending and every awaiter stranded.
|
|
865
|
+
reject(err);
|
|
866
|
+
}
|
|
625
867
|
}));
|
|
868
|
+
// Drop the _initReject reference whether init resolved or rejected, so the
|
|
869
|
+
// field is never stale. Using an explicit helper keeps the dangling
|
|
870
|
+
// observer chain out of statement position (which the lint rules forbid).
|
|
871
|
+
this.clearInitRejectOnSettle(this._initPromise);
|
|
626
872
|
return this._initPromise;
|
|
627
873
|
});
|
|
628
874
|
}
|
|
875
|
+
/**
|
|
876
|
+
* Attach a settle observer to {@link _initPromise} that drops
|
|
877
|
+
* {@link _initReject} once the promise settles (resolved or rejected).
|
|
878
|
+
* Errors on the observer chain are swallowed; only the original
|
|
879
|
+
* {@link _initPromise} surfaces them to its awaiters.
|
|
880
|
+
*/
|
|
881
|
+
clearInitRejectOnSettle(initPromise) {
|
|
882
|
+
initPromise
|
|
883
|
+
.finally(() => {
|
|
884
|
+
this._initReject = undefined;
|
|
885
|
+
this._initSubstratePairing = undefined;
|
|
886
|
+
})
|
|
887
|
+
.catch(() => {
|
|
888
|
+
// observer-only; original promise's rejection is delivered to awaiters
|
|
889
|
+
});
|
|
890
|
+
}
|
|
629
891
|
/**
|
|
630
892
|
* Returns the active account
|
|
631
893
|
*/
|
|
632
894
|
getActiveAccount() {
|
|
633
895
|
return __awaiter(this, void 0, void 0, function* () {
|
|
896
|
+
this.assertNotDestroyed();
|
|
634
897
|
return this._activeAccount.promise;
|
|
635
898
|
});
|
|
636
899
|
}
|
|
900
|
+
retainStorageValidationPromise() {
|
|
901
|
+
// Constructor validation is intentionally fire-and-forget, but retaining
|
|
902
|
+
// the promise gives tests a deterministic hook without changing public API.
|
|
903
|
+
this.storageValidated.catch((err) => logger.error(err.message));
|
|
904
|
+
}
|
|
905
|
+
deactivateInvalidAccountState(reason) {
|
|
906
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
907
|
+
if (this.hasEmittedInvalidAccountDeactivated) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
this.hasEmittedInvalidAccountDeactivated = true;
|
|
911
|
+
logger.log('deactivateInvalidAccountState', reason);
|
|
912
|
+
if (reason === 'missing_active_account') {
|
|
913
|
+
yield this.repairMissingActiveAccount();
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
yield this.resetInvalidState(false);
|
|
917
|
+
}
|
|
918
|
+
yield this.events.emit(events_1.BeaconEvent.INVALID_ACCOUNT_DEACTIVATED, { reason });
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
repairMissingActiveAccount() {
|
|
922
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
923
|
+
this._activeAccount = octez_connect_utils_1.ExposedPromise.resolve(undefined);
|
|
924
|
+
yield this.storage.delete(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT);
|
|
925
|
+
yield this.setActivePeer(undefined);
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
hasStoredActiveAccountPointer() {
|
|
929
|
+
// LocalStorage-specific repair: that backend is where literal sentinel strings were produced.
|
|
930
|
+
if (typeof localStorage === 'undefined') {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
try {
|
|
934
|
+
return localStorage.getItem(this.storage.getPrefixedKey(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT)) !== null;
|
|
935
|
+
}
|
|
936
|
+
catch (_a) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
637
940
|
isInvalidState(account) {
|
|
638
941
|
return __awaiter(this, void 0, void 0, function* () {
|
|
639
942
|
const activeAccount = yield this._activeAccount.promise;
|
|
@@ -645,11 +948,15 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
645
948
|
resetInvalidState() {
|
|
646
949
|
return __awaiter(this, arguments, void 0, function* (emit = true) {
|
|
647
950
|
var _a, _b;
|
|
648
|
-
this.accountManager.removeAllAccounts();
|
|
951
|
+
yield this.accountManager.removeAllAccounts();
|
|
649
952
|
this._activeAccount = octez_connect_utils_1.ExposedPromise.resolve(undefined);
|
|
650
|
-
this.storage.
|
|
651
|
-
|
|
652
|
-
|
|
953
|
+
yield this.storage.delete(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT);
|
|
954
|
+
if (emit) {
|
|
955
|
+
yield this.events.emit(events_1.BeaconEvent.INVALID_ACTIVE_ACCOUNT_STATE);
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
yield this.hideUI(['alert']);
|
|
959
|
+
}
|
|
653
960
|
yield Promise.all([
|
|
654
961
|
(_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
|
|
655
962
|
(_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
|
|
@@ -668,7 +975,8 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
668
975
|
setActiveAccount(account) {
|
|
669
976
|
return __awaiter(this, void 0, void 0, function* () {
|
|
670
977
|
var _a;
|
|
671
|
-
|
|
978
|
+
const activeAccountAlreadyCleared = !account && (yield this.isActiveAccountAlreadyCleared());
|
|
979
|
+
if (!activeAccountAlreadyCleared && !this.isGetActiveAccountHandled) {
|
|
672
980
|
console.warn(`An active account has been received, but no active subscription was found for BeaconEvent.ACTIVE_ACCOUNT_SET.`);
|
|
673
981
|
}
|
|
674
982
|
if (account && this._activeAccount.isSettled() && (yield this.isInvalidState(account))) {
|
|
@@ -680,9 +988,9 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
680
988
|
}
|
|
681
989
|
// when I'm resetting the activeAccount
|
|
682
990
|
if (!account && this._activeAccount.isResolved() && (yield this.getActiveAccount())) {
|
|
683
|
-
const transport = yield this.transport;
|
|
991
|
+
const transport = this._transport.isResolved() ? yield this.transport : undefined;
|
|
684
992
|
const activeAccount = yield this.getActiveAccount();
|
|
685
|
-
if (!
|
|
993
|
+
if (!activeAccount) {
|
|
686
994
|
return;
|
|
687
995
|
}
|
|
688
996
|
if (!this.debounceSetActiveAccount && transport instanceof octez_connect_transport_walletconnect_1.WalletConnectTransport) {
|
|
@@ -698,22 +1006,15 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
698
1006
|
type: 'DISCONNECT'
|
|
699
1007
|
});
|
|
700
1008
|
}
|
|
701
|
-
|
|
702
|
-
.filter(([id, _promise]) => id !== 'session_update')
|
|
703
|
-
.forEach(([id, promise]) => {
|
|
704
|
-
promise.reject({
|
|
705
|
-
type: octez_connect_types_1.BeaconMessageType.Error,
|
|
706
|
-
errorType: octez_connect_types_1.BeaconErrorType.ABORTED_ERROR,
|
|
707
|
-
id,
|
|
708
|
-
senderId: '',
|
|
709
|
-
version: '2'
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
this.openRequests.clear();
|
|
1009
|
+
this.abortOpenRequests();
|
|
713
1010
|
this.debounceSetActiveAccount = false;
|
|
714
1011
|
}
|
|
715
1012
|
}
|
|
716
|
-
if (
|
|
1013
|
+
if (activeAccountAlreadyCleared) {
|
|
1014
|
+
// Keep peer and transport cleanup below idempotent, but do not write storage or emit
|
|
1015
|
+
// another ACTIVE_ACCOUNT_SET(undefined) for an already-empty account.
|
|
1016
|
+
}
|
|
1017
|
+
else if (this._activeAccount.isSettled()) {
|
|
717
1018
|
// If the promise has already been resolved we need to create a new one.
|
|
718
1019
|
this._activeAccount = octez_connect_utils_1.ExposedPromise.resolve(account);
|
|
719
1020
|
}
|
|
@@ -754,11 +1055,42 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
754
1055
|
yield this.setActivePeer(undefined);
|
|
755
1056
|
yield this.setTransport(undefined);
|
|
756
1057
|
}
|
|
757
|
-
|
|
758
|
-
|
|
1058
|
+
if (account) {
|
|
1059
|
+
yield this.storage.set(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT, account.accountIdentifier);
|
|
1060
|
+
}
|
|
1061
|
+
else if (!activeAccountAlreadyCleared) {
|
|
1062
|
+
yield this.storage.delete(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT);
|
|
1063
|
+
}
|
|
1064
|
+
if (!activeAccountAlreadyCleared) {
|
|
1065
|
+
yield this.events.emit(events_1.BeaconEvent.ACTIVE_ACCOUNT_SET, account);
|
|
1066
|
+
}
|
|
759
1067
|
return;
|
|
760
1068
|
});
|
|
761
1069
|
}
|
|
1070
|
+
isActiveAccountAlreadyCleared() {
|
|
1071
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1072
|
+
return this._activeAccount.isResolved() && !(yield this.getActiveAccount());
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
recoverActiveAccountFromAccountsChange() {
|
|
1076
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1077
|
+
const activeAccountIdentifier = yield this.storage.get(octez_connect_types_1.StorageKey.ACTIVE_ACCOUNT);
|
|
1078
|
+
if (!activeAccountIdentifier || activeAccountIdentifier === 'undefined') {
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
if (this._activeAccount.isResolved()) {
|
|
1082
|
+
const activeAccount = yield this.getActiveAccount();
|
|
1083
|
+
if ((activeAccount === null || activeAccount === void 0 ? void 0 : activeAccount.accountIdentifier) === activeAccountIdentifier) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
const account = yield this.getAccount(activeAccountIdentifier);
|
|
1088
|
+
if (!account) {
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
yield this.setActiveAccount(account);
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
762
1094
|
/**
|
|
763
1095
|
* Clear the active account
|
|
764
1096
|
*/
|
|
@@ -848,32 +1180,16 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
848
1180
|
};
|
|
849
1181
|
});
|
|
850
1182
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
sendMetrics(uri, options, thenHandler, catchHandler) {
|
|
862
|
-
if (!this.enableMetrics && uri === 'performance-metrics/save') {
|
|
863
|
-
options && this.updateMetricsStorage(options.body);
|
|
864
|
-
}
|
|
865
|
-
if (!this.enableMetrics) {
|
|
866
|
-
return;
|
|
867
|
-
}
|
|
868
|
-
fetch(`${octez_connect_core_1.BACKEND_URL}/${uri}`, options)
|
|
869
|
-
.then((res) => thenHandler && thenHandler(res))
|
|
870
|
-
.catch((err) => {
|
|
871
|
-
console.warn('Network error encountered. Metrics sharing have been automatically disabled.');
|
|
872
|
-
logger.error(err.message);
|
|
873
|
-
this.enableMetrics = false; // in the event of a network error, stop sending metrics
|
|
874
|
-
catchHandler && catchHandler(err);
|
|
875
|
-
});
|
|
1183
|
+
// Metrics phone home to a Papers-controlled endpoint that the ECAD fork
|
|
1184
|
+
// does not control or ingest. The disabled path also queued payloads into
|
|
1185
|
+
// IndexedDB before the DB was ready, surfacing as unhandledRejection.
|
|
1186
|
+
// Hard-disabled here; full removal (option, storage key, IDB store,
|
|
1187
|
+
// BACKEND_URL constant, all call sites) tracked as a follow-up.
|
|
1188
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- hard-disabled stub keeps its signature for call-site type-safety; params are intentionally unused pending full removal. */
|
|
1189
|
+
sendMetrics(_uri, _options, _thenHandler, _catchHandler) {
|
|
1190
|
+
return;
|
|
876
1191
|
}
|
|
1192
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
877
1193
|
checkMakeRequest() {
|
|
878
1194
|
return __awaiter(this, void 0, void 0, function* () {
|
|
879
1195
|
const isResolved = this._transport.isResolved();
|
|
@@ -933,14 +1249,19 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
933
1249
|
* Remove all peers and all accounts that have been connected through those peers
|
|
934
1250
|
*/
|
|
935
1251
|
removeAllPeers() {
|
|
936
|
-
return __awaiter(this, arguments, void 0, function* (sendDisconnectToPeers = false) {
|
|
937
|
-
const transport = yield this.transport;
|
|
1252
|
+
return __awaiter(this, arguments, void 0, function* (sendDisconnectToPeers = false, options = {}) {
|
|
1253
|
+
const transport = (yield this.transport);
|
|
938
1254
|
const peers = yield transport.getPeers();
|
|
939
|
-
const removePeerResult = transport.removeAllPeers();
|
|
1255
|
+
const removePeerResult = yield transport.removeAllPeers();
|
|
940
1256
|
yield this.removeAccountsForPeers(peers);
|
|
941
1257
|
if (sendDisconnectToPeers) {
|
|
942
1258
|
const disconnectPromises = peers.map((peer) => this.sendDisconnectToPeer(peer, transport));
|
|
943
|
-
|
|
1259
|
+
if (options.ignoreDisconnectErrors) {
|
|
1260
|
+
yield Promise.allSettled(disconnectPromises);
|
|
1261
|
+
}
|
|
1262
|
+
else {
|
|
1263
|
+
yield Promise.all(disconnectPromises);
|
|
1264
|
+
}
|
|
944
1265
|
}
|
|
945
1266
|
return removePeerResult;
|
|
946
1267
|
});
|
|
@@ -1046,13 +1367,15 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1046
1367
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
|
|
1047
1368
|
const logId = `makeRequestV3 ${Date.now()}`;
|
|
1048
1369
|
logger.time(true, logId);
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1370
|
+
let resolved;
|
|
1371
|
+
try {
|
|
1372
|
+
resolved = yield this.makeRequestV3(request);
|
|
1373
|
+
}
|
|
1374
|
+
catch (requestError) {
|
|
1375
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1376
|
+
throw requestError;
|
|
1377
|
+
}
|
|
1378
|
+
const { message: response, connectionInfo } = resolved;
|
|
1056
1379
|
logger.time(false, logId);
|
|
1057
1380
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
|
|
1058
1381
|
logger.log('RESPONSE V3', response, connectionInfo);
|
|
@@ -1114,14 +1437,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1114
1437
|
const res = (yield this.checkMakeRequest())
|
|
1115
1438
|
? this.makeRequestV3(request)
|
|
1116
1439
|
: this.makeRequestBC(request);
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1440
|
+
let resolved;
|
|
1441
|
+
try {
|
|
1442
|
+
resolved = yield res;
|
|
1443
|
+
}
|
|
1444
|
+
catch (requestError) {
|
|
1445
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1446
|
+
throw requestError;
|
|
1447
|
+
}
|
|
1448
|
+
if (!resolved) {
|
|
1449
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1450
|
+
}
|
|
1451
|
+
const { message: response, connectionInfo } = resolved;
|
|
1125
1452
|
logger.time(false, logId);
|
|
1126
1453
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
|
|
1127
1454
|
yield blockchain.handleResponse({
|
|
@@ -1147,16 +1474,36 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1147
1474
|
*/
|
|
1148
1475
|
requestPermissions(input) {
|
|
1149
1476
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1150
|
-
|
|
1151
|
-
|
|
1477
|
+
this.assertNotDestroyed();
|
|
1478
|
+
const scopes = this.getPermissionRequestScopes(input);
|
|
1479
|
+
const requestPermissionsKey = this.getPermissionRequestKey(scopes);
|
|
1480
|
+
if (this._requestPermissionsPromise) {
|
|
1481
|
+
if (this._requestPermissionsKey !== requestPermissionsKey) {
|
|
1482
|
+
throw new Error('Cannot start a permission request with different scopes while another permission request is pending');
|
|
1483
|
+
}
|
|
1484
|
+
return this._requestPermissionsPromise;
|
|
1485
|
+
}
|
|
1486
|
+
const requestPermissionsPromise = this.requestPermissionsInternal(scopes);
|
|
1487
|
+
this._requestPermissionsPromise = requestPermissionsPromise;
|
|
1488
|
+
this._requestPermissionsKey = requestPermissionsKey;
|
|
1489
|
+
try {
|
|
1490
|
+
return yield requestPermissionsPromise;
|
|
1491
|
+
}
|
|
1492
|
+
finally {
|
|
1493
|
+
if (this._requestPermissionsPromise === requestPermissionsPromise) {
|
|
1494
|
+
this._requestPermissionsPromise = undefined;
|
|
1495
|
+
this._requestPermissionsKey = undefined;
|
|
1496
|
+
}
|
|
1152
1497
|
}
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
requestPermissionsInternal(scopes) {
|
|
1501
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1153
1502
|
const request = {
|
|
1154
1503
|
appMetadata: yield this.getOwnAppMetadata(),
|
|
1155
1504
|
type: octez_connect_types_1.BeaconMessageType.PermissionRequest,
|
|
1156
1505
|
network: this.network,
|
|
1157
|
-
scopes
|
|
1158
|
-
? input.scopes
|
|
1159
|
-
: [octez_connect_types_1.PermissionScope.OPERATION_REQUEST, octez_connect_types_1.PermissionScope.SIGN]
|
|
1506
|
+
scopes
|
|
1160
1507
|
};
|
|
1161
1508
|
this.analytics.track('event', 'DAppClient', 'Permission requested');
|
|
1162
1509
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'start'));
|
|
@@ -1165,14 +1512,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1165
1512
|
const res = (yield this.checkMakeRequest()) || !(yield this.getActiveAccount())
|
|
1166
1513
|
? this.makeRequest(request, undefined, undefined)
|
|
1167
1514
|
: this.makeRequestBC(request);
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1515
|
+
let resolved;
|
|
1516
|
+
try {
|
|
1517
|
+
resolved = yield res;
|
|
1518
|
+
}
|
|
1519
|
+
catch (requestError) {
|
|
1520
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1521
|
+
throw requestError;
|
|
1522
|
+
}
|
|
1523
|
+
if (!resolved) {
|
|
1524
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1525
|
+
}
|
|
1526
|
+
const { message, connectionInfo } = resolved;
|
|
1176
1527
|
logger.time(false, logId);
|
|
1177
1528
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('connect', 'success'));
|
|
1178
1529
|
logger.log('requestPermissions', '######## MESSAGE #######');
|
|
@@ -1195,6 +1546,17 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1195
1546
|
return output;
|
|
1196
1547
|
});
|
|
1197
1548
|
}
|
|
1549
|
+
getPermissionRequestScopes(input) {
|
|
1550
|
+
if (input && 'network' in input) {
|
|
1551
|
+
throw new Error('[BEACON] the "network" property is no longer accepted in input. Please provide it when instantiating DAppClient.');
|
|
1552
|
+
}
|
|
1553
|
+
return input && input.scopes
|
|
1554
|
+
? input.scopes
|
|
1555
|
+
: [octez_connect_types_1.PermissionScope.OPERATION_REQUEST, octez_connect_types_1.PermissionScope.SIGN];
|
|
1556
|
+
}
|
|
1557
|
+
getPermissionRequestKey(scopes) {
|
|
1558
|
+
return [...scopes].sort().join('|');
|
|
1559
|
+
}
|
|
1198
1560
|
/**
|
|
1199
1561
|
* Send a proof of event request to the wallet. The wallet will either accept or decline the challenge.
|
|
1200
1562
|
* If it is accepted, the challenge will be stored, meaning that even if the user refresh the page, the DAppClient will keep checking if the challenge has been fulfilled.
|
|
@@ -1222,14 +1584,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1222
1584
|
const res = (yield this.checkMakeRequest())
|
|
1223
1585
|
? this.makeRequest(request)
|
|
1224
1586
|
: this.makeRequestBC(request);
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1587
|
+
let resolved;
|
|
1588
|
+
try {
|
|
1589
|
+
resolved = yield res;
|
|
1590
|
+
}
|
|
1591
|
+
catch (requestError) {
|
|
1592
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1593
|
+
throw requestError;
|
|
1594
|
+
}
|
|
1595
|
+
if (!resolved) {
|
|
1596
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1597
|
+
}
|
|
1598
|
+
const { message, connectionInfo } = resolved;
|
|
1233
1599
|
logger.time(false, logId);
|
|
1234
1600
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
|
|
1235
1601
|
this.analytics.track('event', 'DAppClient', `Proof of event challenge ${message.isAccepted ? 'accepted' : 'refused'}`, { address: activeAccount.address });
|
|
@@ -1266,14 +1632,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1266
1632
|
const res = (yield this.checkMakeRequest())
|
|
1267
1633
|
? this.makeRequest(request)
|
|
1268
1634
|
: this.makeRequestBC(request);
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1635
|
+
let resolved;
|
|
1636
|
+
try {
|
|
1637
|
+
resolved = yield res;
|
|
1638
|
+
}
|
|
1639
|
+
catch (requestError) {
|
|
1640
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1641
|
+
throw requestError;
|
|
1642
|
+
}
|
|
1643
|
+
if (!resolved) {
|
|
1644
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1645
|
+
}
|
|
1646
|
+
const { message, connectionInfo } = resolved;
|
|
1277
1647
|
logger.time(false, logId);
|
|
1278
1648
|
this.analytics.track('event', 'DAppClient', `Simulated proof of event challenge ${!message.errorMessage ? 'accepted' : 'refused'}`, { address: activeAccount.address });
|
|
1279
1649
|
yield this.notifySuccess(request, {
|
|
@@ -1335,14 +1705,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1335
1705
|
const res = (yield this.checkMakeRequest())
|
|
1336
1706
|
? this.makeRequest(request)
|
|
1337
1707
|
: this.makeRequestBC(request);
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1708
|
+
let resolved;
|
|
1709
|
+
try {
|
|
1710
|
+
resolved = yield res;
|
|
1711
|
+
}
|
|
1712
|
+
catch (requestError) {
|
|
1713
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1714
|
+
throw requestError;
|
|
1715
|
+
}
|
|
1716
|
+
if (!resolved) {
|
|
1717
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1718
|
+
}
|
|
1719
|
+
const { message, connectionInfo } = resolved;
|
|
1346
1720
|
logger.time(false, logId);
|
|
1347
1721
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
|
|
1348
1722
|
yield this.notifySuccess(request, {
|
|
@@ -1432,14 +1806,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1432
1806
|
const res = (yield this.checkMakeRequest())
|
|
1433
1807
|
? this.makeRequest(request)
|
|
1434
1808
|
: this.makeRequestBC(request);
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1809
|
+
let resolved;
|
|
1810
|
+
try {
|
|
1811
|
+
resolved = yield res;
|
|
1812
|
+
}
|
|
1813
|
+
catch (requestError) {
|
|
1814
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1815
|
+
throw requestError;
|
|
1816
|
+
}
|
|
1817
|
+
if (!resolved) {
|
|
1818
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1819
|
+
}
|
|
1820
|
+
const { message, connectionInfo } = resolved;
|
|
1443
1821
|
logger.time(false, logId);
|
|
1444
1822
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
|
|
1445
1823
|
yield this.notifySuccess(request, {
|
|
@@ -1482,14 +1860,18 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1482
1860
|
const res = (yield this.checkMakeRequest())
|
|
1483
1861
|
? this.makeRequest(request)
|
|
1484
1862
|
: this.makeRequestBC(request);
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1863
|
+
let resolved;
|
|
1864
|
+
try {
|
|
1865
|
+
resolved = yield res;
|
|
1866
|
+
}
|
|
1867
|
+
catch (requestError) {
|
|
1868
|
+
yield this.runRequestErrorSideEffects(request, requestError, logId);
|
|
1869
|
+
throw requestError;
|
|
1870
|
+
}
|
|
1871
|
+
if (!resolved) {
|
|
1872
|
+
throw new Error('Internal error: makeRequest returned no result');
|
|
1873
|
+
}
|
|
1874
|
+
const { message, connectionInfo } = resolved;
|
|
1493
1875
|
logger.time(false, logId);
|
|
1494
1876
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'success'));
|
|
1495
1877
|
yield this.notifySuccess(request, {
|
|
@@ -1563,13 +1945,17 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1563
1945
|
*/
|
|
1564
1946
|
removeAccountsForPeers(peersToRemove) {
|
|
1565
1947
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1948
|
+
if (peersToRemove.length === 0) {
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1566
1951
|
const peerIdsToRemove = peersToRemove.map((peer) => peer.senderId);
|
|
1567
1952
|
return this.removeAccountsForPeerIds(peerIdsToRemove);
|
|
1568
1953
|
});
|
|
1569
1954
|
}
|
|
1570
1955
|
removeAccountsForPeerIds(peerIds) {
|
|
1571
1956
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1572
|
-
|
|
1957
|
+
var _a;
|
|
1958
|
+
const accounts = (_a = (yield this.accountManager.getAccounts())) !== null && _a !== void 0 ? _a : [];
|
|
1573
1959
|
// Remove all accounts with origin of the specified peer
|
|
1574
1960
|
const accountsToRemove = accounts.filter((account) => peerIds.includes(account.senderId));
|
|
1575
1961
|
const accountIdentifiersToRemove = accountsToRemove.map((accountInfo) => accountInfo.accountIdentifier);
|
|
@@ -1583,6 +1969,46 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1583
1969
|
}
|
|
1584
1970
|
});
|
|
1585
1971
|
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Run the standard request-error side effects (abort/error metric,
|
|
1974
|
+
* timer stop, {@link handleRequestError}) on a single awaited control
|
|
1975
|
+
* flow so callers can re-throw the original {@link ErrorResponse} without
|
|
1976
|
+
* leaking an UnhandledPromiseRejection.
|
|
1977
|
+
*
|
|
1978
|
+
* Why this exists: every request method historically used a fire-and-
|
|
1979
|
+
* forget `res.catch(handler)` whose handler did `throw await
|
|
1980
|
+
* this.handleRequestError(...)`. The catch returned a detached promise
|
|
1981
|
+
* nobody awaited; `handleRequestError`'s thrown wrapped error became an
|
|
1982
|
+
* unhandled rejection. The bug rarely surfaced before the dapp-init
|
|
1983
|
+
* promise was made rejectable, because pre-pairing rejection paths used
|
|
1984
|
+
* to hang instead of routing through these handlers. Once init started
|
|
1985
|
+
* rejecting reliably, the unhandled rejection started firing on every
|
|
1986
|
+
* WC session-proposal rejection. We swallow the wrapped throw here so
|
|
1987
|
+
* callers can re-throw the original `ErrorResponse`, matching the
|
|
1988
|
+
* post-pairing rejection contract at the openRequest path.
|
|
1989
|
+
*
|
|
1990
|
+
* @param request The request we sent
|
|
1991
|
+
* @param requestError The error we received
|
|
1992
|
+
* @param logId The {@link logger.time} label opened for this request
|
|
1993
|
+
*/
|
|
1994
|
+
runRequestErrorSideEffects(request, rawError, logId) {
|
|
1995
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1996
|
+
// V3 request shapes (PermissionRequestV3, BlockchainRequestV3) flow through
|
|
1997
|
+
// here too. They aren't part of BeaconRequestInputMessage, but
|
|
1998
|
+
// handleRequestError only inspects `.type` plus optional fields it already
|
|
1999
|
+
// guards on. Catch params are `unknown` under strict TS, same story.
|
|
2000
|
+
const typedRequest = request;
|
|
2001
|
+
const requestError = rawError;
|
|
2002
|
+
if (requestError.errorType === octez_connect_types_1.BeaconErrorType.ABORTED_ERROR) {
|
|
2003
|
+
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'abort'));
|
|
2004
|
+
}
|
|
2005
|
+
else {
|
|
2006
|
+
this.sendMetrics('performance-metrics/save', yield this.buildPayload('message', 'error'));
|
|
2007
|
+
}
|
|
2008
|
+
logger.time(false, logId);
|
|
2009
|
+
yield this.handleRequestError(typedRequest, requestError).catch(() => undefined);
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
1586
2012
|
/**
|
|
1587
2013
|
* This message handles errors that we receive from the wallet.
|
|
1588
2014
|
*
|
|
@@ -1765,20 +2191,10 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1765
2191
|
}
|
|
1766
2192
|
makeRequest(requestInput, skipResponse, otherTabMessageId) {
|
|
1767
2193
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1768
|
-
var _a
|
|
2194
|
+
var _a;
|
|
1769
2195
|
const messageId = otherTabMessageId !== null && otherTabMessageId !== void 0 ? otherTabMessageId : (yield (0, octez_connect_utils_1.generateGUID)());
|
|
1770
|
-
if (this._initPromise && this.isInitPending) {
|
|
1771
|
-
yield Promise.all([
|
|
1772
|
-
(_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
|
|
1773
|
-
(_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
|
|
1774
|
-
]);
|
|
1775
|
-
this._initPromise = undefined;
|
|
1776
|
-
this.hideUI(['toast']);
|
|
1777
|
-
}
|
|
1778
2196
|
logger.log('makeRequest', 'starting');
|
|
1779
|
-
this.isInitPending = true;
|
|
1780
2197
|
yield this.init();
|
|
1781
|
-
this.isInitPending = false;
|
|
1782
2198
|
logger.log('makeRequest', 'after init');
|
|
1783
2199
|
if (yield this.addRequestAndCheckIfRateLimited()) {
|
|
1784
2200
|
this.events
|
|
@@ -1799,20 +2215,34 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1799
2215
|
exposed = new octez_connect_utils_1.ExposedPromise();
|
|
1800
2216
|
this.addOpenRequest(request.id, exposed);
|
|
1801
2217
|
}
|
|
1802
|
-
const payload = yield new octez_connect_core_1.Serializer().serialize(request);
|
|
1803
|
-
const account = yield this.getActiveAccount();
|
|
1804
|
-
const peer = yield this.getPeer(account);
|
|
1805
|
-
const walletInfo = yield this.getWalletInfo(peer, account);
|
|
1806
|
-
logger.log('makeRequest', 'sending message', request);
|
|
1807
2218
|
try {
|
|
1808
|
-
;
|
|
1809
|
-
|
|
2219
|
+
const payload = yield new octez_connect_core_1.Serializer().serialize(request);
|
|
2220
|
+
const account = yield this.getActiveAccount();
|
|
2221
|
+
const peer = yield this.getPeer(account);
|
|
2222
|
+
const walletInfo = yield this.getWalletInfo(peer, account);
|
|
2223
|
+
logger.log('makeRequest', 'sending message', request);
|
|
2224
|
+
yield (yield this.transport).send(payload, peer);
|
|
1810
2225
|
if (request.type !== octez_connect_types_1.BeaconMessageType.PermissionRequest ||
|
|
1811
2226
|
(this._activeAccount.isResolved() && (yield this._activeAccount.promise))) {
|
|
1812
2227
|
this.tryToAppSwitch();
|
|
1813
2228
|
}
|
|
2229
|
+
if (!otherTabMessageId) {
|
|
2230
|
+
this.events
|
|
2231
|
+
.emit(beacon_message_events_1.messageEvents[requestInput.type].sent, {
|
|
2232
|
+
walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_a = walletInfo.name) !== null && _a !== void 0 ? _a : 'Wallet' }),
|
|
2233
|
+
extraInfo: {
|
|
2234
|
+
resetCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
2235
|
+
yield this.disconnect();
|
|
2236
|
+
})
|
|
2237
|
+
}
|
|
2238
|
+
})
|
|
2239
|
+
.catch((emitError) => logger.warn('makeRequest', emitError));
|
|
2240
|
+
}
|
|
1814
2241
|
}
|
|
1815
2242
|
catch (sendError) {
|
|
2243
|
+
if (!skipResponse) {
|
|
2244
|
+
this.clearOpenRequest(request.id);
|
|
2245
|
+
}
|
|
1816
2246
|
this.events.emit(events_1.BeaconEvent.INTERNAL_ERROR, {
|
|
1817
2247
|
text: 'Unable to send message. If this problem persists, please reset the connection and pair your wallet again.',
|
|
1818
2248
|
buttons: [
|
|
@@ -1827,18 +2257,6 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1827
2257
|
});
|
|
1828
2258
|
throw sendError;
|
|
1829
2259
|
}
|
|
1830
|
-
if (!otherTabMessageId) {
|
|
1831
|
-
this.events
|
|
1832
|
-
.emit(beacon_message_events_1.messageEvents[requestInput.type].sent, {
|
|
1833
|
-
walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_c = walletInfo.name) !== null && _c !== void 0 ? _c : 'Wallet' }),
|
|
1834
|
-
extraInfo: {
|
|
1835
|
-
resetCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
1836
|
-
this.disconnect();
|
|
1837
|
-
})
|
|
1838
|
-
}
|
|
1839
|
-
})
|
|
1840
|
-
.catch((emitError) => console.warn(emitError));
|
|
1841
|
-
}
|
|
1842
2260
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1843
2261
|
return exposed === null || exposed === void 0 ? void 0 : exposed.promise; // TODO: fix type
|
|
1844
2262
|
});
|
|
@@ -1853,20 +2271,10 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1853
2271
|
*/
|
|
1854
2272
|
makeRequestV3(requestInput, otherTabMessageId) {
|
|
1855
2273
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1856
|
-
var _a
|
|
1857
|
-
if (this._initPromise && this.isInitPending) {
|
|
1858
|
-
yield Promise.all([
|
|
1859
|
-
(_a = this.postMessageTransport) === null || _a === void 0 ? void 0 : _a.disconnect(),
|
|
1860
|
-
(_b = this.walletConnectTransport) === null || _b === void 0 ? void 0 : _b.disconnect()
|
|
1861
|
-
]);
|
|
1862
|
-
this._initPromise = undefined;
|
|
1863
|
-
this.hideUI(['toast']);
|
|
1864
|
-
}
|
|
2274
|
+
var _a;
|
|
1865
2275
|
const messageId = otherTabMessageId !== null && otherTabMessageId !== void 0 ? otherTabMessageId : (yield (0, octez_connect_utils_1.generateGUID)());
|
|
1866
2276
|
logger.log('makeRequest', 'starting');
|
|
1867
|
-
this.isInitPending = true;
|
|
1868
2277
|
yield this.init(undefined, true);
|
|
1869
|
-
this.isInitPending = false;
|
|
1870
2278
|
logger.log('makeRequest', 'after init');
|
|
1871
2279
|
if (yield this.addRequestAndCheckIfRateLimited()) {
|
|
1872
2280
|
this.events
|
|
@@ -1885,20 +2293,31 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1885
2293
|
};
|
|
1886
2294
|
const exposed = new octez_connect_utils_1.ExposedPromise();
|
|
1887
2295
|
this.addOpenRequest(request.id, exposed);
|
|
1888
|
-
const payload = yield new octez_connect_core_1.Serializer().serialize(request);
|
|
1889
|
-
const account = yield this.getActiveAccount();
|
|
1890
|
-
const peer = yield this.getPeer(account);
|
|
1891
|
-
const walletInfo = yield this.getWalletInfo(peer, account);
|
|
1892
|
-
logger.log('makeRequest', 'sending message', request);
|
|
1893
2296
|
try {
|
|
1894
|
-
;
|
|
1895
|
-
|
|
2297
|
+
const payload = yield new octez_connect_core_1.Serializer().serialize(request);
|
|
2298
|
+
const account = yield this.getActiveAccount();
|
|
2299
|
+
const peer = yield this.getPeer(account);
|
|
2300
|
+
const walletInfo = yield this.getWalletInfo(peer, account);
|
|
2301
|
+
logger.log('makeRequest', 'sending message', request);
|
|
2302
|
+
yield (yield this.transport).send(payload, peer);
|
|
1896
2303
|
if (request.message.type !== octez_connect_types_1.BeaconMessageType.PermissionRequest ||
|
|
1897
2304
|
(this._activeAccount.isResolved() && (yield this._activeAccount.promise))) {
|
|
1898
2305
|
this.tryToAppSwitch();
|
|
1899
2306
|
}
|
|
2307
|
+
const index = requestInput.type;
|
|
2308
|
+
this.events
|
|
2309
|
+
.emit(beacon_message_events_1.messageEvents[index].sent, {
|
|
2310
|
+
walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_a = walletInfo.name) !== null && _a !== void 0 ? _a : 'Wallet' }),
|
|
2311
|
+
extraInfo: {
|
|
2312
|
+
resetCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
2313
|
+
yield this.disconnect();
|
|
2314
|
+
})
|
|
2315
|
+
}
|
|
2316
|
+
})
|
|
2317
|
+
.catch((emitError) => logger.warn('makeRequestV3', emitError));
|
|
1900
2318
|
}
|
|
1901
2319
|
catch (sendError) {
|
|
2320
|
+
this.clearOpenRequest(request.id);
|
|
1902
2321
|
this.events.emit(events_1.BeaconEvent.INTERNAL_ERROR, {
|
|
1903
2322
|
text: 'Unable to send message. If this problem persists, please reset the connection and pair your wallet again.',
|
|
1904
2323
|
buttons: [
|
|
@@ -1913,17 +2332,6 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1913
2332
|
});
|
|
1914
2333
|
throw sendError;
|
|
1915
2334
|
}
|
|
1916
|
-
const index = requestInput.type;
|
|
1917
|
-
this.events
|
|
1918
|
-
.emit(beacon_message_events_1.messageEvents[index].sent, {
|
|
1919
|
-
walletInfo: Object.assign(Object.assign({}, walletInfo), { name: (_c = walletInfo.name) !== null && _c !== void 0 ? _c : 'Wallet' }),
|
|
1920
|
-
extraInfo: {
|
|
1921
|
-
resetCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
1922
|
-
this.disconnect();
|
|
1923
|
-
})
|
|
1924
|
-
}
|
|
1925
|
-
})
|
|
1926
|
-
.catch((emitError) => console.warn(emitError));
|
|
1927
2335
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1928
2336
|
return exposed.promise; // TODO: fix type
|
|
1929
2337
|
});
|
|
@@ -1966,27 +2374,149 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1966
2374
|
return exposed.promise;
|
|
1967
2375
|
});
|
|
1968
2376
|
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Disconnects all resolved transports (postMessage, P2P, WalletConnect), removes their peers,
|
|
2379
|
+
* and clears active account state. After calling, the DAppClient remains usable for a new
|
|
2380
|
+
* requestPermissions().
|
|
2381
|
+
*/
|
|
1969
2382
|
disconnect() {
|
|
2383
|
+
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
2384
|
+
const { notifyPeers = true } = options;
|
|
2385
|
+
if (!this._disconnectPromise) {
|
|
2386
|
+
this._disconnectNotifyPeers = false;
|
|
2387
|
+
}
|
|
2388
|
+
this._disconnectNotifyPeers = this._disconnectNotifyPeers || notifyPeers;
|
|
2389
|
+
if (this._disconnectPromise) {
|
|
2390
|
+
return this._disconnectPromise;
|
|
2391
|
+
}
|
|
2392
|
+
this._disconnectPromise = (() => __awaiter(this, void 0, void 0, function* () { return this.disconnectInternal(); }))().finally(() => {
|
|
2393
|
+
this._disconnectPromise = undefined;
|
|
2394
|
+
this._disconnectNotifyPeers = false;
|
|
2395
|
+
});
|
|
2396
|
+
return this._disconnectPromise;
|
|
2397
|
+
});
|
|
2398
|
+
}
|
|
2399
|
+
disconnectInternal() {
|
|
1970
2400
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2401
|
+
this.abortPendingInit();
|
|
1971
2402
|
if (!this._transport.isResolved()) {
|
|
1972
|
-
|
|
2403
|
+
const initializedTransports = this.getInitializedTransports();
|
|
2404
|
+
this.abortOpenRequests();
|
|
2405
|
+
yield this.removeAllPeersFromTransports(initializedTransports);
|
|
2406
|
+
yield this.clearActiveAccount();
|
|
2407
|
+
yield this.disconnectResolvedTransports(initializedTransports);
|
|
2408
|
+
this.clearInternalTransportReferences();
|
|
2409
|
+
return;
|
|
1973
2410
|
}
|
|
1974
|
-
const transport = yield this.transport;
|
|
2411
|
+
const transport = (yield this.transport);
|
|
1975
2412
|
if (transport.connectionStatus === octez_connect_types_1.TransportStatus.NOT_CONNECTED) {
|
|
1976
|
-
|
|
2413
|
+
yield this.clearActiveAccount();
|
|
2414
|
+
this.abortOpenRequests();
|
|
2415
|
+
return;
|
|
1977
2416
|
}
|
|
1978
2417
|
yield this.createStateSnapshot();
|
|
1979
2418
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('disconnect', 'start'));
|
|
2419
|
+
this.abortOpenRequests();
|
|
2420
|
+
const transports = this.getResolvedTransports(transport);
|
|
2421
|
+
yield this.removeAllPeersFromTransports(transports);
|
|
1980
2422
|
yield this.clearActiveAccount();
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
}
|
|
1984
|
-
this.postMessageTransport = undefined;
|
|
1985
|
-
this.p2pTransport = undefined;
|
|
1986
|
-
this.walletConnectTransport = undefined;
|
|
2423
|
+
yield this.disconnectResolvedTransports(transports);
|
|
2424
|
+
this.clearInternalTransportReferences();
|
|
1987
2425
|
this.sendMetrics('performance-metrics/save', yield this.buildPayload('disconnect', 'success'));
|
|
1988
2426
|
});
|
|
1989
2427
|
}
|
|
2428
|
+
getInitializedTransports() {
|
|
2429
|
+
const transports = [];
|
|
2430
|
+
const addTransport = (transport) => {
|
|
2431
|
+
if (transport && !transports.includes(transport)) {
|
|
2432
|
+
transports.push(transport);
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2435
|
+
addTransport(this.postMessageTransport);
|
|
2436
|
+
addTransport(this.p2pTransport);
|
|
2437
|
+
addTransport(this.walletConnectTransport);
|
|
2438
|
+
return transports;
|
|
2439
|
+
}
|
|
2440
|
+
getResolvedTransports(selectedTransport) {
|
|
2441
|
+
const transports = this.getInitializedTransports();
|
|
2442
|
+
const addTransport = (transport) => {
|
|
2443
|
+
if (transport && !transports.includes(transport)) {
|
|
2444
|
+
transports.push(transport);
|
|
2445
|
+
}
|
|
2446
|
+
};
|
|
2447
|
+
addTransport(this.postMessageTransport);
|
|
2448
|
+
addTransport(this.p2pTransport);
|
|
2449
|
+
addTransport(this.walletConnectTransport);
|
|
2450
|
+
addTransport(selectedTransport);
|
|
2451
|
+
return transports;
|
|
2452
|
+
}
|
|
2453
|
+
clearInternalTransportReferences() {
|
|
2454
|
+
this.postMessageTransport = undefined;
|
|
2455
|
+
this.p2pTransport = undefined;
|
|
2456
|
+
this.walletConnectTransport = undefined;
|
|
2457
|
+
}
|
|
2458
|
+
removeAllPeersFromTransports(transports) {
|
|
2459
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2460
|
+
const peersByTransport = yield Promise.all(transports.map((transport) => __awaiter(this, void 0, void 0, function* () {
|
|
2461
|
+
const transportPeers = yield transport.getPeers();
|
|
2462
|
+
return {
|
|
2463
|
+
transport,
|
|
2464
|
+
peers: transportPeers
|
|
2465
|
+
};
|
|
2466
|
+
})));
|
|
2467
|
+
yield Promise.all(peersByTransport.map(({ transport }) => transport.removeAllPeers()));
|
|
2468
|
+
const peersToRemove = peersByTransport.flatMap(({ peers: transportPeers }) => transportPeers);
|
|
2469
|
+
yield this.removeAccountsForPeers(peersToRemove);
|
|
2470
|
+
// If cleanup already removed peers, a late notify upgrade has nothing left to notify.
|
|
2471
|
+
const sendDisconnectToPeers = this._disconnectNotifyPeers;
|
|
2472
|
+
if (!sendDisconnectToPeers) {
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
yield Promise.allSettled(this.getUniquePeerNotifications(peersByTransport).map(({ transport, peer }) => this.sendDisconnectToPeer(peer, transport)));
|
|
2476
|
+
});
|
|
2477
|
+
}
|
|
2478
|
+
getUniquePeerNotifications(peersByTransport) {
|
|
2479
|
+
const notifications = [];
|
|
2480
|
+
const seen = new Set();
|
|
2481
|
+
peersByTransport.forEach(({ transport, peers: transportPeers }) => {
|
|
2482
|
+
transportPeers.forEach((peer) => {
|
|
2483
|
+
const key = this.getPeerNotificationKey(transport, peer);
|
|
2484
|
+
if (seen.has(key)) {
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
seen.add(key);
|
|
2488
|
+
notifications.push({ transport, peer });
|
|
2489
|
+
});
|
|
2490
|
+
});
|
|
2491
|
+
return notifications;
|
|
2492
|
+
}
|
|
2493
|
+
getPeerNotificationKey(transport, peer) {
|
|
2494
|
+
return [transport.type, peer.publicKey, peer.senderId, peer.id].filter(Boolean).join(':');
|
|
2495
|
+
}
|
|
2496
|
+
disconnectResolvedTransports(transports) {
|
|
2497
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2498
|
+
const results = yield Promise.allSettled(transports.map((transport) => __awaiter(this, void 0, void 0, function* () {
|
|
2499
|
+
if (this.isTransportConnected(transport)) {
|
|
2500
|
+
yield transport.disconnect();
|
|
2501
|
+
}
|
|
2502
|
+
if (this.hasClientCleanup(transport)) {
|
|
2503
|
+
yield transport.doClientCleanup();
|
|
2504
|
+
}
|
|
2505
|
+
})));
|
|
2506
|
+
results.forEach((result) => {
|
|
2507
|
+
if (result.status === 'rejected') {
|
|
2508
|
+
logger.warn('disconnectResolvedTransports', result.reason);
|
|
2509
|
+
}
|
|
2510
|
+
});
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
hasClientCleanup(transport) {
|
|
2514
|
+
const transportWithClientCleanup = transport;
|
|
2515
|
+
return typeof transportWithClientCleanup.doClientCleanup === 'function';
|
|
2516
|
+
}
|
|
2517
|
+
isTransportConnected(transport) {
|
|
2518
|
+
return transport.connectionStatus !== octez_connect_types_1.TransportStatus.NOT_CONNECTED;
|
|
2519
|
+
}
|
|
1990
2520
|
/**
|
|
1991
2521
|
* Adds a requests to the "openRequests" set so we know what messages have already been answered/handled.
|
|
1992
2522
|
*
|
|
@@ -1995,7 +2525,64 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
1995
2525
|
*/
|
|
1996
2526
|
addOpenRequest(id, promise) {
|
|
1997
2527
|
logger.log('addOpenRequest', this.name, `adding request ${id} and waiting for answer`);
|
|
2528
|
+
this.clearOpenRequestTimeout(id);
|
|
2529
|
+
this.openRequests.delete(id);
|
|
1998
2530
|
this.openRequests.set(id, promise);
|
|
2531
|
+
this.addOpenRequestTimeout(id, promise);
|
|
2532
|
+
}
|
|
2533
|
+
addOpenRequestTimeout(id, promise) {
|
|
2534
|
+
if (id === SESSION_UPDATE_REQUEST_ID) {
|
|
2535
|
+
return;
|
|
2536
|
+
}
|
|
2537
|
+
if (!Number.isFinite(this.requestTimeoutMs) || this.requestTimeoutMs <= 0) {
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
2540
|
+
const timeout = setTimeout(() => {
|
|
2541
|
+
if (this.openRequests.get(id) !== promise) {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
const errorResponse = {
|
|
2545
|
+
id,
|
|
2546
|
+
type: octez_connect_types_1.BeaconMessageType.Error,
|
|
2547
|
+
errorType: octez_connect_types_1.BeaconErrorType.PEER_UNREACHABLE,
|
|
2548
|
+
senderId: '',
|
|
2549
|
+
version: '2'
|
|
2550
|
+
};
|
|
2551
|
+
promise.reject(errorResponse);
|
|
2552
|
+
this.clearOpenRequest(id);
|
|
2553
|
+
this.events.emit(events_1.BeaconEvent.CHANNEL_CLOSED).catch((emitError) => {
|
|
2554
|
+
logger.error('addOpenRequestTimeout', emitError);
|
|
2555
|
+
});
|
|
2556
|
+
}, this.requestTimeoutMs);
|
|
2557
|
+
this.openRequestTimeouts.set(id, timeout);
|
|
2558
|
+
}
|
|
2559
|
+
clearOpenRequest(id) {
|
|
2560
|
+
this.clearOpenRequestTimeout(id);
|
|
2561
|
+
this.openRequests.delete(id);
|
|
2562
|
+
this.openRequestsOtherTabs.delete(id);
|
|
2563
|
+
}
|
|
2564
|
+
clearOpenRequestTimeout(id) {
|
|
2565
|
+
const timeout = this.openRequestTimeouts.get(id);
|
|
2566
|
+
if (timeout) {
|
|
2567
|
+
clearTimeout(timeout);
|
|
2568
|
+
this.openRequestTimeouts.delete(id);
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
clearAllOpenRequestTimeouts() {
|
|
2572
|
+
this.openRequestTimeouts.forEach((timeout) => clearTimeout(timeout));
|
|
2573
|
+
this.openRequestTimeouts.clear();
|
|
2574
|
+
}
|
|
2575
|
+
abortOpenRequests() {
|
|
2576
|
+
Array.from(this.openRequests.entries())
|
|
2577
|
+
.filter(([id]) => id !== SESSION_UPDATE_REQUEST_ID)
|
|
2578
|
+
.forEach(([id, promise]) => {
|
|
2579
|
+
promise.reject(this.createAbortedError(id));
|
|
2580
|
+
this.clearOpenRequest(id);
|
|
2581
|
+
});
|
|
2582
|
+
this.openRequests.clear();
|
|
2583
|
+
this.openRequestsOtherTabs.clear();
|
|
2584
|
+
this.acknowledgedRequests.clear();
|
|
2585
|
+
this.clearAllOpenRequestTimeouts();
|
|
1999
2586
|
}
|
|
2000
2587
|
sendNotificationWithAccessToken(notification) {
|
|
2001
2588
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -2018,21 +2605,28 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
2018
2605
|
const signature = yield (0, octez_connect_utils_1.signMessage)(payloadBytes, {
|
|
2019
2606
|
secretKey: Buffer.from(keypair.secretKey)
|
|
2020
2607
|
});
|
|
2021
|
-
const notificationResponse = yield
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
body
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2608
|
+
const notificationResponse = yield fetch(`${url}/send`, {
|
|
2609
|
+
method: 'POST',
|
|
2610
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2611
|
+
body: JSON.stringify({
|
|
2612
|
+
recipient,
|
|
2613
|
+
title,
|
|
2614
|
+
body,
|
|
2615
|
+
timestamp,
|
|
2616
|
+
payload,
|
|
2617
|
+
accessToken,
|
|
2618
|
+
protocolIdentifier,
|
|
2619
|
+
sender: {
|
|
2620
|
+
name: this.name,
|
|
2621
|
+
publicKey,
|
|
2622
|
+
signature
|
|
2623
|
+
}
|
|
2624
|
+
})
|
|
2034
2625
|
});
|
|
2035
|
-
|
|
2626
|
+
if (!notificationResponse.ok) {
|
|
2627
|
+
throw new Error(`sendNotification failed: ${notificationResponse.status} ${notificationResponse.statusText}`);
|
|
2628
|
+
}
|
|
2629
|
+
return notificationResponse.json();
|
|
2036
2630
|
});
|
|
2037
2631
|
}
|
|
2038
2632
|
onNewAccount(message, connectionInfo) {
|
|
@@ -2040,7 +2634,7 @@ class DAppClient extends octez_connect_core_1.Client {
|
|
|
2040
2634
|
var _a, _b, _c;
|
|
2041
2635
|
// TODO: Migration code. Remove sometime after 1.0.0 release.
|
|
2042
2636
|
const tempPK = message.publicKey || message.pubkey || message.pubKey;
|
|
2043
|
-
const publicKey =
|
|
2637
|
+
const publicKey = tempPK ? (0, octez_connect_utils_1.prefixPublicKey)(tempPK) : undefined;
|
|
2044
2638
|
if (!publicKey && !message.address) {
|
|
2045
2639
|
throw new Error('PublicKey or Address must be defined');
|
|
2046
2640
|
}
|