@metamask-previews/keyring-controller 19.0.5-preview-43593c4e → 19.0.5-preview-37653b42
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/KeyringController.cjs +98 -28
- package/dist/KeyringController.cjs.map +1 -1
- package/dist/KeyringController.d.cts +40 -29
- package/dist/KeyringController.d.cts.map +1 -1
- package/dist/KeyringController.d.mts +40 -29
- package/dist/KeyringController.d.mts.map +1 -1
- package/dist/KeyringController.mjs +97 -30
- package/dist/KeyringController.mjs.map +1 -1
- package/dist/constants.cjs +1 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +2 -1
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +2 -1
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +1 -0
- package/dist/constants.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders,
|
|
12
|
+
var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_checkForDuplicate, _KeyringController_setUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
|
|
13
13
|
function $importDefault(module) {
|
|
14
14
|
if (module?.__esModule) {
|
|
15
15
|
return module.default;
|
|
@@ -19,8 +19,7 @@ function $importDefault(module) {
|
|
|
19
19
|
import { isValidPrivate, toBuffer, getBinarySize } from "@ethereumjs/util";
|
|
20
20
|
import { BaseController } from "@metamask/base-controller";
|
|
21
21
|
import * as encryptorUtils from "@metamask/browser-passworder";
|
|
22
|
-
import
|
|
23
|
-
const HDKeyring = $importDefault($HDKeyring);
|
|
22
|
+
import HDKeyring from "@metamask/eth-hd-keyring";
|
|
24
23
|
import { normalize as ethNormalize } from "@metamask/eth-sig-util";
|
|
25
24
|
import $SimpleKeyring from "@metamask/eth-simple-keyring";
|
|
26
25
|
const SimpleKeyring = $importDefault($SimpleKeyring);
|
|
@@ -36,18 +35,31 @@ const name = 'KeyringController';
|
|
|
36
35
|
*/
|
|
37
36
|
export var KeyringTypes;
|
|
38
37
|
(function (KeyringTypes) {
|
|
38
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
39
40
|
KeyringTypes["simple"] = "Simple Key Pair";
|
|
41
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
40
43
|
KeyringTypes["hd"] = "HD Key Tree";
|
|
44
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
41
46
|
KeyringTypes["qr"] = "QR Hardware Wallet Device";
|
|
47
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
42
49
|
KeyringTypes["trezor"] = "Trezor Hardware";
|
|
50
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
43
52
|
KeyringTypes["ledger"] = "Ledger Hardware";
|
|
53
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
44
55
|
KeyringTypes["lattice"] = "Lattice Hardware";
|
|
56
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
45
58
|
KeyringTypes["snap"] = "Snap Keyring";
|
|
46
59
|
})(KeyringTypes || (KeyringTypes = {}));
|
|
47
60
|
/**
|
|
48
61
|
* Custody keyring types are a special case, as they are not a single type
|
|
49
62
|
* but they all start with the prefix "Custody".
|
|
50
|
-
*
|
|
51
63
|
* @param keyringType - The type of the keyring.
|
|
52
64
|
* @returns Whether the keyring type is a custody keyring.
|
|
53
65
|
*/
|
|
@@ -59,7 +71,11 @@ export const isCustodyKeyring = (keyringType) => {
|
|
|
59
71
|
*/
|
|
60
72
|
export var AccountImportStrategy;
|
|
61
73
|
(function (AccountImportStrategy) {
|
|
74
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
62
76
|
AccountImportStrategy["privateKey"] = "privateKey";
|
|
77
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
63
79
|
AccountImportStrategy["json"] = "json";
|
|
64
80
|
})(AccountImportStrategy || (AccountImportStrategy = {}));
|
|
65
81
|
/**
|
|
@@ -158,15 +174,35 @@ function isSerializedKeyringsArray(array) {
|
|
|
158
174
|
* @param keyring - The keyring to display.
|
|
159
175
|
* @returns A keyring display object, with type and accounts properties.
|
|
160
176
|
*/
|
|
161
|
-
async function displayForKeyring(keyring) {
|
|
177
|
+
export async function displayForKeyring(keyring) {
|
|
162
178
|
const accounts = await keyring.getAccounts();
|
|
163
179
|
return {
|
|
164
180
|
type: keyring.type,
|
|
165
181
|
// Cast to `string[]` here is safe here because `accounts` has no nullish
|
|
166
182
|
// values, and `normalize` returns `string` unless given a nullish value
|
|
167
183
|
accounts: accounts.map(normalize),
|
|
184
|
+
// @ts-expect-error TODO: update type in @metamask/utils
|
|
185
|
+
fingerprint: await keyring?.getFingerprint?.(),
|
|
168
186
|
};
|
|
169
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Retrieves a keyring from an array of keyrings based on its fingerprint.
|
|
190
|
+
*
|
|
191
|
+
* @param keyrings - Array of keyrings to search through.
|
|
192
|
+
* @param fingerprint - The fingerprint to match against.
|
|
193
|
+
* @returns Promise resolving to the matching keyring, or undefined if not found.
|
|
194
|
+
*/
|
|
195
|
+
export async function getKeyringByFingerprint(keyrings, fingerprint) {
|
|
196
|
+
// Do not attempt to return a keyring if the fingerprint is not provided
|
|
197
|
+
if (!fingerprint) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
const fingerprints = await Promise.all(
|
|
201
|
+
// @ts-expect-error TODO: update type in @metamask/utils
|
|
202
|
+
keyrings.map((kr) => kr?.getFingerprint?.()));
|
|
203
|
+
const index = fingerprints.indexOf(fingerprint);
|
|
204
|
+
return keyrings[index];
|
|
205
|
+
}
|
|
170
206
|
/**
|
|
171
207
|
* Check if address is an ethereum address
|
|
172
208
|
*
|
|
@@ -237,11 +273,11 @@ export class KeyringController extends BaseController {
|
|
|
237
273
|
_KeyringController_controllerOperationMutex.set(this, new Mutex());
|
|
238
274
|
_KeyringController_vaultOperationMutex.set(this, new Mutex());
|
|
239
275
|
_KeyringController_keyringBuilders.set(this, void 0);
|
|
276
|
+
_KeyringController_keyrings.set(this, void 0);
|
|
240
277
|
_KeyringController_unsupportedKeyrings.set(this, void 0);
|
|
278
|
+
_KeyringController_password.set(this, void 0);
|
|
241
279
|
_KeyringController_encryptor.set(this, void 0);
|
|
242
280
|
_KeyringController_cacheEncryptionKey.set(this, void 0);
|
|
243
|
-
_KeyringController_keyrings.set(this, void 0);
|
|
244
|
-
_KeyringController_password.set(this, void 0);
|
|
245
281
|
_KeyringController_qrKeyringStateListener.set(this, void 0);
|
|
246
282
|
__classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
|
|
247
283
|
? keyringBuilders.concat(defaultKeyringBuilders)
|
|
@@ -343,7 +379,6 @@ export class KeyringController extends BaseController {
|
|
|
343
379
|
* If there is a pre-existing locked vault, it will be replaced.
|
|
344
380
|
*
|
|
345
381
|
* @param password - Password to unlock the new vault.
|
|
346
|
-
* @returns Promise resolving when the operation ends successfully.
|
|
347
382
|
*/
|
|
348
383
|
async createNewVaultAndKeychain(password) {
|
|
349
384
|
return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
|
|
@@ -393,12 +428,27 @@ export class KeyringController extends BaseController {
|
|
|
393
428
|
* Gets the seed phrase of the HD keyring.
|
|
394
429
|
*
|
|
395
430
|
* @param password - Password of the keyring.
|
|
431
|
+
* @param keyringId - The keyring identifier.
|
|
396
432
|
* @returns Promise resolving to the seed phrase.
|
|
397
433
|
*/
|
|
398
|
-
async exportSeedPhrase(password) {
|
|
434
|
+
async exportSeedPhrase(password, keyringId) {
|
|
399
435
|
await this.verifyPassword(password);
|
|
400
|
-
|
|
401
|
-
|
|
436
|
+
let keyring;
|
|
437
|
+
if (keyringId) {
|
|
438
|
+
keyring = await getKeyringByFingerprint(__classPrivateFieldGet(this, _KeyringController_keyrings, "f"), keyringId);
|
|
439
|
+
if (!keyring) {
|
|
440
|
+
throw new Error(KeyringControllerError.KeyringNotFound);
|
|
441
|
+
}
|
|
442
|
+
if (keyring.type !== KeyringTypes.hd) {
|
|
443
|
+
throw new Error(KeyringControllerError.UnsupportedExportSeedPhrase);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
// There will always be an HD keyring
|
|
448
|
+
keyring = this.getKeyringsByType(KeyringTypes.hd)[0];
|
|
449
|
+
}
|
|
450
|
+
assertHasUint8ArrayMnemonic(keyring);
|
|
451
|
+
return keyring.mnemonic;
|
|
402
452
|
}
|
|
403
453
|
/**
|
|
404
454
|
* Gets the private key from the keyring controlling an address.
|
|
@@ -524,7 +574,7 @@ export class KeyringController extends BaseController {
|
|
|
524
574
|
return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
|
|
525
575
|
let privateKey;
|
|
526
576
|
switch (strategy) {
|
|
527
|
-
case
|
|
577
|
+
case 'privateKey':
|
|
528
578
|
const [importedKey] = args;
|
|
529
579
|
if (!importedKey) {
|
|
530
580
|
throw new Error('Cannot import an empty key.');
|
|
@@ -544,7 +594,7 @@ export class KeyringController extends BaseController {
|
|
|
544
594
|
}
|
|
545
595
|
privateKey = remove0x(prefixed);
|
|
546
596
|
break;
|
|
547
|
-
case
|
|
597
|
+
case 'json':
|
|
548
598
|
let wallet;
|
|
549
599
|
const [input, password] = args;
|
|
550
600
|
try {
|
|
@@ -556,7 +606,7 @@ export class KeyringController extends BaseController {
|
|
|
556
606
|
privateKey = bytesToHex(wallet.getPrivateKey());
|
|
557
607
|
break;
|
|
558
608
|
default:
|
|
559
|
-
throw new Error(`Unexpected import strategy: '${
|
|
609
|
+
throw new Error(`Unexpected import strategy: '${strategy}'`);
|
|
560
610
|
}
|
|
561
611
|
const newKeyring = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, KeyringTypes.simple, [
|
|
562
612
|
privateKey,
|
|
@@ -581,6 +631,7 @@ export class KeyringController extends BaseController {
|
|
|
581
631
|
}
|
|
582
632
|
// The `removeAccount` method of snaps keyring is async. We have to update
|
|
583
633
|
// the interface of the other keyrings to be async as well.
|
|
634
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
584
635
|
// FIXME: We do cast to `Hex` to makes the type checker happy here, and
|
|
585
636
|
// because `Keyring<State>.removeAccount` requires address to be `Hex`. Those
|
|
586
637
|
// type would need to be updated for a full non-EVM support.
|
|
@@ -811,6 +862,9 @@ export class KeyringController extends BaseController {
|
|
|
811
862
|
if ('address' in selector) {
|
|
812
863
|
keyring = (await this.getKeyringForAccount(selector.address));
|
|
813
864
|
}
|
|
865
|
+
else if ('fingerprint' in selector) {
|
|
866
|
+
keyring = (await getKeyringByFingerprint(__classPrivateFieldGet(this, _KeyringController_keyrings, "f"), selector.fingerprint));
|
|
867
|
+
}
|
|
814
868
|
else {
|
|
815
869
|
keyring = this.getKeyringsByType(selector.type)[selector.index || 0];
|
|
816
870
|
if (!keyring && options.createIfMissing) {
|
|
@@ -1015,7 +1069,7 @@ export class KeyringController extends BaseController {
|
|
|
1015
1069
|
});
|
|
1016
1070
|
}
|
|
1017
1071
|
}
|
|
1018
|
-
_KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(),
|
|
1072
|
+
_KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
|
|
1019
1073
|
this.messagingSystem.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
|
|
1020
1074
|
this.messagingSystem.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
|
|
1021
1075
|
this.messagingSystem.registerActionHandler(`${name}:signTypedMessage`, this.signTypedMessage.bind(this));
|
|
@@ -1350,6 +1404,9 @@ async function _KeyringController_newKeyring(type, data) {
|
|
|
1350
1404
|
// NOTE: Not all keyrings implement this method in a asynchronous-way. Using `await` for
|
|
1351
1405
|
// non-thenable will still be valid (despite not being really useful). It allows us to cover both
|
|
1352
1406
|
// cases and allow retro-compatibility too.
|
|
1407
|
+
// FIXME: For some reason, it seems that eslint is complaining about this call being non-thenable
|
|
1408
|
+
// even though it is... For now, we just disable it:
|
|
1409
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
1353
1410
|
await keyring.generateRandomMnemonic();
|
|
1354
1411
|
await keyring.addAccounts(1);
|
|
1355
1412
|
}
|
|
@@ -1464,12 +1521,14 @@ async function _KeyringController_checkForDuplicate(type, newAccountArray) {
|
|
|
1464
1521
|
* and save the keyrings to state after it, or rollback to their
|
|
1465
1522
|
* previous state in case of error.
|
|
1466
1523
|
*
|
|
1467
|
-
* @param
|
|
1524
|
+
* @param fn - The function to execute.
|
|
1468
1525
|
* @returns The result of the function.
|
|
1469
1526
|
*/
|
|
1470
|
-
|
|
1527
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
1528
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1529
|
+
async function _KeyringController_persistOrRollback(fn) {
|
|
1471
1530
|
return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async ({ releaseLock }) => {
|
|
1472
|
-
const callbackResult = await
|
|
1531
|
+
const callbackResult = await fn({ releaseLock });
|
|
1473
1532
|
// State is committed only if the operation is successful
|
|
1474
1533
|
await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
|
|
1475
1534
|
return callbackResult;
|
|
@@ -1479,15 +1538,17 @@ async function _KeyringController_persistOrRollback(callback) {
|
|
|
1479
1538
|
* Execute the given function after acquiring the controller lock
|
|
1480
1539
|
* and rollback keyrings and password states in case of error.
|
|
1481
1540
|
*
|
|
1482
|
-
* @param
|
|
1541
|
+
* @param fn - The function to execute atomically.
|
|
1483
1542
|
* @returns The result of the function.
|
|
1484
1543
|
*/
|
|
1485
|
-
|
|
1544
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
1545
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1546
|
+
async function _KeyringController_withRollback(fn) {
|
|
1486
1547
|
return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
|
|
1487
1548
|
const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
|
|
1488
1549
|
const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
|
|
1489
1550
|
try {
|
|
1490
|
-
return await
|
|
1551
|
+
return await fn({ releaseLock });
|
|
1491
1552
|
}
|
|
1492
1553
|
catch (e) {
|
|
1493
1554
|
// Keyrings and password are restored to their previous state
|
|
@@ -1510,11 +1571,13 @@ async function _KeyringController_withRollback(callback) {
|
|
|
1510
1571
|
* controller and that changes its state is executed in a mutually exclusive way,
|
|
1511
1572
|
* preventing unsafe concurrent access that could lead to unpredictable behavior.
|
|
1512
1573
|
*
|
|
1513
|
-
* @param
|
|
1574
|
+
* @param fn - The function to execute while the controller mutex is locked.
|
|
1514
1575
|
* @returns The result of the function.
|
|
1515
1576
|
*/
|
|
1516
|
-
|
|
1517
|
-
|
|
1577
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
1578
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1579
|
+
async function _KeyringController_withControllerLock(fn) {
|
|
1580
|
+
return withLock(__classPrivateFieldGet(this, _KeyringController_controllerOperationMutex, "f"), fn);
|
|
1518
1581
|
}, _KeyringController_withVaultLock =
|
|
1519
1582
|
/**
|
|
1520
1583
|
* Lock the vault mutex before executing the given function,
|
|
@@ -1524,12 +1587,14 @@ async function _KeyringController_withControllerLock(callback) {
|
|
|
1524
1587
|
* This ensures that each operation that interacts with the vault
|
|
1525
1588
|
* is executed in a mutually exclusive way.
|
|
1526
1589
|
*
|
|
1527
|
-
* @param
|
|
1590
|
+
* @param fn - The function to execute while the vault mutex is locked.
|
|
1528
1591
|
* @returns The result of the function.
|
|
1529
1592
|
*/
|
|
1530
|
-
|
|
1593
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
1594
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1595
|
+
async function _KeyringController_withVaultLock(fn) {
|
|
1531
1596
|
__classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
|
|
1532
|
-
return withLock(__classPrivateFieldGet(this, _KeyringController_vaultOperationMutex, "f"),
|
|
1597
|
+
return withLock(__classPrivateFieldGet(this, _KeyringController_vaultOperationMutex, "f"), fn);
|
|
1533
1598
|
};
|
|
1534
1599
|
/**
|
|
1535
1600
|
* Lock the given mutex before executing the given function,
|
|
@@ -1537,13 +1602,15 @@ async function _KeyringController_withVaultLock(callback) {
|
|
|
1537
1602
|
* error is thrown.
|
|
1538
1603
|
*
|
|
1539
1604
|
* @param mutex - The mutex to lock.
|
|
1540
|
-
* @param
|
|
1605
|
+
* @param fn - The function to execute while the mutex is locked.
|
|
1541
1606
|
* @returns The result of the function.
|
|
1542
1607
|
*/
|
|
1543
|
-
|
|
1608
|
+
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
|
|
1609
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1610
|
+
async function withLock(mutex, fn) {
|
|
1544
1611
|
const releaseLock = await mutex.acquire();
|
|
1545
1612
|
try {
|
|
1546
|
-
return await
|
|
1613
|
+
return await fn({ releaseLock });
|
|
1547
1614
|
}
|
|
1548
1615
|
finally {
|
|
1549
1616
|
releaseLock();
|