@metamask-previews/keyring-controller 22.0.2-preview-3636a128 → 22.0.2-preview-d7c00b1

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.
@@ -36,7 +36,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
36
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
- var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
39
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.KeyringController = exports.getDefaultKeyringState = exports.keyringBuilderFactory = exports.SignTypedDataVersion = exports.AccountImportStrategy = exports.isCustodyKeyring = exports.KeyringTypes = void 0;
42
42
  const util_1 = require("@ethereumjs/util");
@@ -168,6 +168,17 @@ function assertIsValidPassword(password) {
168
168
  throw new Error(constants_1.KeyringControllerError.InvalidEmptyPassword);
169
169
  }
170
170
  }
171
+ /**
172
+ * Assert that the provided encryption key is a valid non-empty string.
173
+ *
174
+ * @param encryptionKey - The encryption key to check.
175
+ * @throws If the encryption key is not a valid string.
176
+ */
177
+ function assertIsEncryptionKeySet(encryptionKey) {
178
+ if (!encryptionKey) {
179
+ throw new Error(constants_1.KeyringControllerError.EncryptionKeyNotSet);
180
+ }
181
+ }
171
182
  /**
172
183
  * Checks if the provided value is a serialized keyrings array.
173
184
  *
@@ -274,7 +285,6 @@ class KeyringController extends base_controller_1.BaseController {
274
285
  _KeyringController_keyrings.set(this, void 0);
275
286
  _KeyringController_unsupportedKeyrings.set(this, void 0);
276
287
  _KeyringController_password.set(this, void 0);
277
- _KeyringController_qrKeyringStateListener.set(this, void 0);
278
288
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
279
289
  ? keyringBuilders.concat(defaultKeyringBuilders)
280
290
  : defaultKeyringBuilders, "f");
@@ -399,9 +409,6 @@ class KeyringController extends base_controller_1.BaseController {
399
409
  */
400
410
  async addNewKeyring(type, opts) {
401
411
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
402
- if (type === KeyringTypes.qr) {
403
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringMetadata).call(this, await this.getOrAddQRKeyring());
404
- }
405
412
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getKeyringMetadata).call(this, await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, type, opts)));
406
413
  }
407
414
  /**
@@ -660,7 +667,6 @@ class KeyringController extends base_controller_1.BaseController {
660
667
  async setLocked() {
661
668
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
662
669
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
663
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unsubscribeFromQRKeyringsEvents).call(this);
664
670
  __classPrivateFieldSet(this, _KeyringController_password, undefined, "f");
665
671
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
666
672
  this.update((state) => {
@@ -843,6 +849,10 @@ class KeyringController extends base_controller_1.BaseController {
843
849
  */
844
850
  changePassword(password) {
845
851
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
852
+ // If the password is the same, do nothing.
853
+ if (__classPrivateFieldGet(this, _KeyringController_password, "f") === password) {
854
+ return Promise.resolve();
855
+ }
846
856
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
847
857
  assertIsValidPassword(password);
848
858
  __classPrivateFieldSet(this, _KeyringController_password, password, "f");
@@ -894,27 +904,11 @@ class KeyringController extends base_controller_1.BaseController {
894
904
  */
895
905
  async exportEncryptionKey() {
896
906
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
897
- // There is a case where the controller is unlocked but the encryption key
898
- // is not set, even when #cacheEncryptionKey is true. This happens when
899
- // calling changePassword with the existing password. In this case, the
900
- // encryption key is deleted, but the state is not recreated, because the
901
- // session state does not change in this case, and #updateVault is not
902
- // called in #persistOrRollback.
903
- if (!this.state.encryptionKey) {
904
- assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
905
- assertIsValidPassword(__classPrivateFieldGet(this, _KeyringController_password, "f"));
906
- const result = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(__classPrivateFieldGet(this, _KeyringController_password, "f"),
907
- // Ignoring undefined. Assuming vault is set when unlocked.
908
- this.state.vault);
909
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
910
- this.update((state) => {
911
- state.encryptionKey = result.exportedKeyString;
912
- state.encryptionSalt = result.salt;
913
- });
914
- }
915
- return result.exportedKeyString;
916
- }
917
- return this.state.encryptionKey;
907
+ return await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => {
908
+ const { encryptionKey } = this.state;
909
+ assertIsEncryptionKeySet(encryptionKey);
910
+ return encryptionKey;
911
+ });
918
912
  }
919
913
  /**
920
914
  * Attempts to decrypt the current vault and load its keyrings,
@@ -990,206 +984,14 @@ class KeyringController extends base_controller_1.BaseController {
990
984
  return result;
991
985
  });
992
986
  }
993
- // QR Hardware related methods
994
- /**
995
- * Get QR Hardware keyring.
996
- *
997
- * @returns The QR Keyring if defined, otherwise undefined
998
- * @deprecated Use `withKeyring` instead.
999
- */
1000
- getQRKeyring() {
1001
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1002
- // QRKeyring is not yet compatible with Keyring type from @metamask/utils
1003
- return this.getKeyringsByType(KeyringTypes.qr)[0];
1004
- }
1005
- /**
1006
- * Get QR hardware keyring. If it doesn't exist, add it.
1007
- *
1008
- * @returns The added keyring
1009
- * @deprecated Use `addNewKeyring` and `withKeyring` instead.
1010
- */
1011
- async getOrAddQRKeyring() {
1012
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1013
- return (this.getQRKeyring() ||
1014
- (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_addQRKeyring).call(this))));
1015
- }
1016
- /**
1017
- * Restore QR keyring from serialized data.
1018
- *
1019
- * @param serialized - Serialized data to restore the keyring from.
1020
- * @returns Promise resolving when the operation completes.
1021
- * @deprecated Use `withKeyring` instead.
1022
- */
1023
- // TODO: Replace `any` with type
1024
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1025
- async restoreQRKeyring(serialized) {
1026
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1027
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
1028
- const keyring = this.getQRKeyring() || (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_addQRKeyring).call(this));
1029
- keyring.deserialize(serialized);
1030
- });
1031
- }
1032
- /**
1033
- * Reset QR keyring state.
1034
- *
1035
- * @returns Promise resolving when the operation completes.
1036
- * @deprecated Use `withKeyring` instead.
1037
- */
1038
- async resetQRKeyringState() {
1039
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1040
- (await this.getOrAddQRKeyring()).resetStore();
1041
- }
1042
- /**
1043
- * Get QR keyring state.
1044
- *
1045
- * @returns Promise resolving to the keyring state.
1046
- * @deprecated Use `withKeyring` or subscribe to `"KeyringController:qrKeyringStateChange"`
1047
- * instead.
1048
- */
1049
- async getQRKeyringState() {
1050
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1051
- return (await this.getOrAddQRKeyring()).getMemStore();
1052
- }
1053
- /**
1054
- * Submit QR hardware wallet public HDKey.
1055
- *
1056
- * @param cryptoHDKey - The key to submit.
1057
- * @returns Promise resolving when the operation completes.
1058
- * @deprecated Use `withKeyring` instead.
1059
- */
1060
- async submitQRCryptoHDKey(cryptoHDKey) {
1061
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1062
- (await this.getOrAddQRKeyring()).submitCryptoHDKey(cryptoHDKey);
1063
- }
1064
- /**
1065
- * Submit QR hardware wallet account.
1066
- *
1067
- * @param cryptoAccount - The account to submit.
1068
- * @returns Promise resolving when the operation completes.
1069
- * @deprecated Use `withKeyring` instead.
1070
- */
1071
- async submitQRCryptoAccount(cryptoAccount) {
1072
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1073
- (await this.getOrAddQRKeyring()).submitCryptoAccount(cryptoAccount);
1074
- }
1075
- /**
1076
- * Submit QR hardware wallet signature.
1077
- *
1078
- * @param requestId - The request ID.
1079
- * @param ethSignature - The signature to submit.
1080
- * @returns Promise resolving when the operation completes.
1081
- * @deprecated Use `withKeyring` instead.
1082
- */
1083
- async submitQRSignature(requestId, ethSignature) {
1084
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1085
- (await this.getOrAddQRKeyring()).submitSignature(requestId, ethSignature);
1086
- }
1087
- /**
1088
- * Cancel QR sign request.
1089
- *
1090
- * @returns Promise resolving when the operation completes.
1091
- * @deprecated Use `withKeyring` instead.
1092
- */
1093
- async cancelQRSignRequest() {
1094
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1095
- (await this.getOrAddQRKeyring()).cancelSignRequest();
1096
- }
1097
- /**
1098
- * Cancels qr keyring sync.
1099
- *
1100
- * @returns Promise resolving when the operation completes.
1101
- * @deprecated Use `withKeyring` instead.
1102
- */
1103
- async cancelQRSynchronization() {
1104
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1105
- (await this.getOrAddQRKeyring()).cancelSync();
1106
- }
1107
- /**
1108
- * Connect to QR hardware wallet.
1109
- *
1110
- * @param page - The page to connect to.
1111
- * @returns Promise resolving to the connected accounts.
1112
- * @deprecated Use of this method is discouraged as it creates a dangling promise
1113
- * internal to the `QRKeyring`, which can lead to unpredictable deadlocks. Please use
1114
- * `withKeyring` instead.
1115
- */
1116
- async connectQRHardware(page) {
1117
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1118
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
1119
- try {
1120
- const keyring = this.getQRKeyring() || (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_addQRKeyring).call(this));
1121
- let accounts;
1122
- switch (page) {
1123
- case -1:
1124
- accounts = await keyring.getPreviousPage();
1125
- break;
1126
- case 1:
1127
- accounts = await keyring.getNextPage();
1128
- break;
1129
- default:
1130
- accounts = await keyring.getFirstPage();
1131
- }
1132
- // TODO: Replace `any` with type
1133
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1134
- return accounts.map((account) => {
1135
- return {
1136
- ...account,
1137
- balance: '0x0',
1138
- };
1139
- });
1140
- }
1141
- catch (e) {
1142
- // TODO: Add test case for when keyring throws
1143
- /* istanbul ignore next */
1144
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
1145
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
1146
- throw new Error(`Unspecified error when connect QR Hardware, ${e}`);
1147
- }
1148
- });
1149
- }
1150
- /**
1151
- * Unlock a QR hardware wallet account.
1152
- *
1153
- * @param index - The index of the account to unlock.
1154
- * @returns Promise resolving when the operation completes.
1155
- * @deprecated Use `withKeyring` instead.
1156
- */
1157
- async unlockQRHardwareWalletAccount(index) {
1158
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1159
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
1160
- const keyring = this.getQRKeyring() || (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_addQRKeyring).call(this));
1161
- keyring.setAccountToUnlock(index);
1162
- await keyring.addAccounts(1);
1163
- });
1164
- }
1165
987
  async getAccountKeyringType(account) {
1166
988
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1167
989
  const keyring = (await this.getKeyringForAccount(account));
1168
990
  return keyring.type;
1169
991
  }
1170
- /**
1171
- * Forget the QR hardware wallet.
1172
- *
1173
- * @returns Promise resolving to the removed accounts and the remaining accounts.
1174
- * @deprecated Use `withKeyring` instead.
1175
- */
1176
- async forgetQRDevice() {
1177
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
1178
- return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
1179
- const keyring = this.getQRKeyring();
1180
- if (!keyring) {
1181
- return { removedAccounts: [], remainingAccounts: [] };
1182
- }
1183
- const allAccounts = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getAccountsFromKeyrings).call(this));
1184
- keyring.forgetDevice();
1185
- const remainingAccounts = (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getAccountsFromKeyrings).call(this));
1186
- const removedAccounts = allAccounts.filter((address) => !remainingAccounts.includes(address));
1187
- return { removedAccounts, remainingAccounts };
1188
- });
1189
- }
1190
992
  }
1191
993
  exports.KeyringController = KeyringController;
1192
- _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
994
+ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1193
995
  this.messagingSystem.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
1194
996
  this.messagingSystem.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
1195
997
  this.messagingSystem.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
@@ -1221,30 +1023,6 @@ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_
1221
1023
  return keyringWithMetadata.metadata;
1222
1024
  }, _KeyringController_getKeyringBuilderForType = function _KeyringController_getKeyringBuilderForType(type) {
1223
1025
  return __classPrivateFieldGet(this, _KeyringController_keyringBuilders, "f").find((keyringBuilder) => keyringBuilder.type === type);
1224
- }, _KeyringController_addQRKeyring =
1225
- /**
1226
- * Add qr hardware keyring.
1227
- *
1228
- * @returns The added keyring
1229
- * @throws If a QRKeyring builder is not provided
1230
- * when initializing the controller
1231
- */
1232
- async function _KeyringController_addQRKeyring() {
1233
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1234
- // QRKeyring is not yet compatible with Keyring type from @metamask/utils
1235
- return (await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_newKeyring).call(this, KeyringTypes.qr));
1236
- }, _KeyringController_subscribeToQRKeyringEvents = function _KeyringController_subscribeToQRKeyringEvents(qrKeyring) {
1237
- __classPrivateFieldSet(this, _KeyringController_qrKeyringStateListener, (state) => {
1238
- this.messagingSystem.publish(`${name}:qrKeyringStateChange`, state);
1239
- }, "f");
1240
- qrKeyring.getMemStore().subscribe(__classPrivateFieldGet(this, _KeyringController_qrKeyringStateListener, "f"));
1241
- }, _KeyringController_unsubscribeFromQRKeyringsEvents = function _KeyringController_unsubscribeFromQRKeyringsEvents() {
1242
- const qrKeyrings = this.getKeyringsByType(KeyringTypes.qr);
1243
- qrKeyrings.forEach((qrKeyring) => {
1244
- if (__classPrivateFieldGet(this, _KeyringController_qrKeyringStateListener, "f")) {
1245
- qrKeyring.getMemStore().unsubscribe(__classPrivateFieldGet(this, _KeyringController_qrKeyringStateListener, "f"));
1246
- }
1247
- });
1248
1026
  }, _KeyringController_createNewVaultWithKeyring =
1249
1027
  /**
1250
1028
  * Create new vault with an initial keyring
@@ -1604,11 +1382,6 @@ async function _KeyringController_createKeyring(type, data) {
1604
1382
  await keyring.generateRandomMnemonic();
1605
1383
  await keyring.addAccounts(1);
1606
1384
  }
1607
- if (type === KeyringTypes.qr) {
1608
- // In case of a QR keyring type, we need to subscribe
1609
- // to its events after creating it
1610
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_subscribeToQRKeyringEvents).call(this, keyring);
1611
- }
1612
1385
  return keyring;
1613
1386
  }, _KeyringController_clearKeyrings =
1614
1387
  /**