@metamask-previews/address-book-controller 6.0.3-preview-4809837c → 6.0.3-preview-ae04854

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/CHANGELOG.md CHANGED
@@ -7,11 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add contact event system ([#5779](https://github.com/MetaMask/core/pull/5779))
13
+ - Add `AddressBookControllerContactUpdatedEvent` and `AddressBookControllerContactDeletedEvent` types for contact events
14
+ - Add `list` method on `AddressBookController` to get all address book entries as an array
15
+ - Register message handlers for `list`, `set`, and `delete` actions
16
+ - Add `lastUpdatedAt` property to `AddressBookEntry` to track when contacts were last modified
17
+
10
18
  ### Changed
11
19
 
12
20
  - Bump `@metamask/base-controller` from ^8.0.0 to ^8.0.1 ([#5722](https://github.com/MetaMask/core/pull/5722))
13
21
  - Bump `@metamask/controller-utils` to `^11.9.0` ([#5583](https://github.com/MetaMask/core/pull/5583), [#5765](https://github.com/MetaMask/core/pull/5765), [#5812](https://github.com/MetaMask/core/pull/5812))
14
22
 
23
+ ### Fixed
24
+
25
+ - Fix `delete` method to clean up empty chainId objects when the last address in a chain is deleted ([#5779](https://github.com/MetaMask/core/pull/5779))
26
+
15
27
  ## [6.0.3]
16
28
 
17
29
  ### Changed
@@ -1,4 +1,10 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ 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");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var _AddressBookController_instances, _AddressBookController_registerMessageHandlers;
2
8
  Object.defineProperty(exports, "__esModule", { value: true });
3
9
  exports.AddressBookController = exports.getDefaultAddressBookControllerState = exports.controllerName = exports.AddressType = void 0;
4
10
  const base_controller_1 = require("@metamask/base-controller");
@@ -8,20 +14,19 @@ const controller_utils_1 = require("@metamask/controller-utils");
8
14
  */
9
15
  var AddressType;
10
16
  (function (AddressType) {
11
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
12
- // eslint-disable-next-line @typescript-eslint/naming-convention
13
17
  AddressType["externallyOwnedAccounts"] = "EXTERNALLY_OWNED_ACCOUNTS";
14
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
15
- // eslint-disable-next-line @typescript-eslint/naming-convention
16
18
  AddressType["contractAccounts"] = "CONTRACT_ACCOUNTS";
17
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
18
- // eslint-disable-next-line @typescript-eslint/naming-convention
19
19
  AddressType["nonAccounts"] = "NON_ACCOUNTS";
20
20
  })(AddressType || (exports.AddressType = AddressType = {}));
21
21
  /**
22
22
  * The name of the {@link AddressBookController}.
23
23
  */
24
24
  exports.controllerName = 'AddressBookController';
25
+ /**
26
+ * Special chainId used for wallet's own accounts (internal MetaMask accounts).
27
+ * These entries don't trigger sync events as they are not user-created contacts.
28
+ */
29
+ const WALLET_ACCOUNTS_CHAIN_ID = '*';
25
30
  const addressBookControllerMetadata = {
26
31
  addressBook: { persist: true, anonymous: false },
27
32
  };
@@ -55,6 +60,21 @@ class AddressBookController extends base_controller_1.BaseController {
55
60
  name: exports.controllerName,
56
61
  state: mergedState,
57
62
  });
63
+ _AddressBookController_instances.add(this);
64
+ __classPrivateFieldGet(this, _AddressBookController_instances, "m", _AddressBookController_registerMessageHandlers).call(this);
65
+ }
66
+ /**
67
+ * Returns all address book entries as an array.
68
+ *
69
+ * @returns Array of all address book entries.
70
+ */
71
+ list() {
72
+ const { addressBook } = this.state;
73
+ return Object.keys(addressBook).reduce((acc, chainId) => {
74
+ const chainIdHex = chainId;
75
+ const chainContacts = Object.values(addressBook[chainIdHex]);
76
+ return [...acc, ...chainContacts];
77
+ }, []);
58
78
  }
59
79
  /**
60
80
  * Remove all contract entries.
@@ -79,12 +99,23 @@ class AddressBookController extends base_controller_1.BaseController {
79
99
  !this.state.addressBook[chainId][address]) {
80
100
  return false;
81
101
  }
102
+ const deletedEntry = { ...this.state.addressBook[chainId][address] };
82
103
  this.update((state) => {
83
- delete state.addressBook[chainId][address];
84
- if (Object.keys(state.addressBook[chainId]).length === 0) {
85
- delete state.addressBook[chainId];
104
+ const chainContacts = state.addressBook[chainId];
105
+ if (chainContacts?.[address]) {
106
+ delete chainContacts[address];
107
+ // Clean up empty chainId objects
108
+ if (Object.keys(chainContacts).length === 0) {
109
+ delete state.addressBook[chainId];
110
+ }
86
111
  }
87
112
  });
113
+ // Skip sending delete event for global contacts with chainId '*'
114
+ // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),
115
+ // not user-created contacts. They don't need to trigger sync events.
116
+ if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {
117
+ this.messagingSystem.publish('AddressBookController:contactDeleted', deletedEntry);
118
+ }
88
119
  return true;
89
120
  }
90
121
  /**
@@ -109,6 +140,7 @@ class AddressBookController extends base_controller_1.BaseController {
109
140
  memo,
110
141
  name,
111
142
  addressType,
143
+ lastUpdatedAt: Date.now(),
112
144
  };
113
145
  const ensName = (0, controller_utils_1.normalizeEnsName)(name);
114
146
  if (ensName) {
@@ -124,9 +156,20 @@ class AddressBookController extends base_controller_1.BaseController {
124
156
  },
125
157
  };
126
158
  });
159
+ // Skip sending update event for global contacts with chainId '*'
160
+ // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),
161
+ // not user-created contacts. They don't need to trigger sync events.
162
+ if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {
163
+ this.messagingSystem.publish('AddressBookController:contactUpdated', entry);
164
+ }
127
165
  return true;
128
166
  }
129
167
  }
130
168
  exports.AddressBookController = AddressBookController;
169
+ _AddressBookController_instances = new WeakSet(), _AddressBookController_registerMessageHandlers = function _AddressBookController_registerMessageHandlers() {
170
+ this.messagingSystem.registerActionHandler(`${exports.controllerName}:list`, this.list.bind(this));
171
+ this.messagingSystem.registerActionHandler(`${exports.controllerName}:set`, this.set.bind(this));
172
+ this.messagingSystem.registerActionHandler(`${exports.controllerName}:delete`, this.delete.bind(this));
173
+ };
131
174
  exports.default = AddressBookController;
132
175
  //# sourceMappingURL=AddressBookController.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddressBookController.cjs","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n normalizeEnsName,\n isValidHexAddress,\n isSafeDynamicKey,\n toChecksumHexAddress,\n toHex,\n} from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\n/**\n * @type ContactEntry\n *\n * ContactEntry representation\n * @property address - Hex address of a recipient account\n * @property name - Nickname associated with this address\n * @property importTime - Data time when an account as created/imported\n */\nexport type ContactEntry = {\n address: string;\n name: string;\n importTime?: number;\n};\n\n/**\n * The type of address.\n */\nexport enum AddressType {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n externallyOwnedAccounts = 'EXTERNALLY_OWNED_ACCOUNTS',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n contractAccounts = 'CONTRACT_ACCOUNTS',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n nonAccounts = 'NON_ACCOUNTS',\n}\n\n/**\n * @type AddressBookEntry\n *\n * AddressBookEntry representation\n * @property address - Hex address of a recipient account\n * @property name - Nickname associated with this address\n * @property chainId - Chain id identifies the current chain\n * @property memo - User's note about address\n * @property isEns - is the entry an ENS name\n * @property addressType - is the type of this address\n */\nexport type AddressBookEntry = {\n address: string;\n name: string;\n chainId: Hex;\n memo: string;\n isEns: boolean;\n addressType?: AddressType;\n};\n\n/**\n * @type AddressBookState\n *\n * Address book controller state\n * @property addressBook - Array of contact entry objects\n */\nexport type AddressBookControllerState = {\n addressBook: { [chainId: Hex]: { [address: string]: AddressBookEntry } };\n};\n\n/**\n * The name of the {@link AddressBookController}.\n */\nexport const controllerName = 'AddressBookController';\n\n/**\n * The action that can be performed to get the state of the {@link AddressBookController}.\n */\nexport type AddressBookControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AddressBookController}.\n */\nexport type AddressBookControllerActions = AddressBookControllerGetStateAction;\n\n/**\n * The event that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The events that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerEvents = AddressBookControllerStateChangeEvent;\n\nconst addressBookControllerMetadata = {\n addressBook: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link AddressBookController} state.\n *\n * @returns The default {@link AddressBookController} state.\n */\nexport const getDefaultAddressBookControllerState =\n (): AddressBookControllerState => {\n return {\n addressBook: {},\n };\n };\n\n/**\n * The messenger of the {@link AddressBookController} for communication.\n */\nexport type AddressBookControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AddressBookControllerActions,\n AddressBookControllerEvents,\n never,\n never\n>;\n\n/**\n * Controller that manages a list of recipient addresses associated with nicknames.\n */\nexport class AddressBookController extends BaseController<\n typeof controllerName,\n AddressBookControllerState,\n AddressBookControllerMessenger\n> {\n /**\n * Creates an AddressBookController instance.\n *\n * @param args - The {@link AddressBookController} arguments.\n * @param args.messenger - The controller messenger instance for communication.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AddressBookControllerMessenger;\n state?: Partial<AddressBookControllerState>;\n }) {\n const mergedState = { ...getDefaultAddressBookControllerState(), ...state };\n super({\n messenger,\n metadata: addressBookControllerMetadata,\n name: controllerName,\n state: mergedState,\n });\n }\n\n /**\n * Remove all contract entries.\n */\n clear() {\n this.update((state) => {\n state.addressBook = {};\n });\n }\n\n /**\n * Remove a contract entry by address.\n *\n * @param chainId - Chain id identifies the current chain.\n * @param address - Recipient address to delete.\n * @returns Whether the entry was deleted.\n */\n delete(chainId: Hex, address: string) {\n address = toChecksumHexAddress(address);\n if (\n ![chainId, address].every((key) => isSafeDynamicKey(key)) ||\n !isValidHexAddress(address) ||\n !this.state.addressBook[chainId] ||\n !this.state.addressBook[chainId][address]\n ) {\n return false;\n }\n\n this.update((state) => {\n delete state.addressBook[chainId][address];\n if (Object.keys(state.addressBook[chainId]).length === 0) {\n delete state.addressBook[chainId];\n }\n });\n\n return true;\n }\n\n /**\n * Add or update a contact entry by address.\n *\n * @param address - Recipient address to add or update.\n * @param name - Nickname to associate with this address.\n * @param chainId - Chain id identifies the current chain.\n * @param memo - User's note about address.\n * @param addressType - Contact's address type.\n * @returns Boolean indicating if the address was successfully set.\n */\n set(\n address: string,\n name: string,\n chainId = toHex(1),\n memo = '',\n addressType?: AddressType,\n ) {\n address = toChecksumHexAddress(address);\n if (!isValidHexAddress(address)) {\n return false;\n }\n\n const entry = {\n address,\n chainId,\n isEns: false,\n memo,\n name,\n addressType,\n };\n\n const ensName = normalizeEnsName(name);\n if (ensName) {\n entry.name = ensName;\n entry.isEns = true;\n }\n\n this.update((state) => {\n state.addressBook = {\n ...this.state.addressBook,\n [chainId]: {\n ...this.state.addressBook[chainId],\n [address]: entry,\n },\n };\n });\n\n return true;\n }\n}\n\nexport default AddressBookController;\n"]}
1
+ {"version":3,"file":"AddressBookController.cjs","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n normalizeEnsName,\n isValidHexAddress,\n isSafeDynamicKey,\n toChecksumHexAddress,\n toHex,\n} from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\n/**\n * ContactEntry representation\n */\nexport type ContactEntry = {\n /** Hex address of a recipient account */\n address: string;\n /** Nickname associated with this address */\n name: string;\n /** Data time when an account as created/imported */\n importTime?: number;\n};\n\n/**\n * The type of address.\n */\nexport enum AddressType {\n externallyOwnedAccounts = 'EXTERNALLY_OWNED_ACCOUNTS',\n contractAccounts = 'CONTRACT_ACCOUNTS',\n nonAccounts = 'NON_ACCOUNTS',\n}\n\n/**\n * AddressBookEntry represents a contact in the address book.\n */\nexport type AddressBookEntry = {\n /** Hex address of a recipient account */\n address: string;\n /** Nickname associated with this address */\n name: string;\n /** Chain id identifies the current chain */\n chainId: Hex;\n /** User's note about address */\n memo: string;\n /** Indicates if the entry is an ENS name */\n isEns: boolean;\n /** The type of this address */\n addressType?: AddressType;\n /** Timestamp of when this entry was last updated */\n lastUpdatedAt?: number;\n};\n\n/**\n * State for the AddressBookController.\n */\nexport type AddressBookControllerState = {\n /** Map of chainId to address to contact entries */\n addressBook: { [chainId: Hex]: { [address: string]: AddressBookEntry } };\n};\n\n/**\n * The name of the {@link AddressBookController}.\n */\nexport const controllerName = 'AddressBookController';\n\n/**\n * Special chainId used for wallet's own accounts (internal MetaMask accounts).\n * These entries don't trigger sync events as they are not user-created contacts.\n */\nconst WALLET_ACCOUNTS_CHAIN_ID = '*';\n\n/**\n * The action that can be performed to get the state of the {@link AddressBookController}.\n */\nexport type AddressBookControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The action that can be performed to list contacts from the {@link AddressBookController}.\n */\nexport type AddressBookControllerListAction = {\n type: `${typeof controllerName}:list`;\n handler: AddressBookController['list'];\n};\n\n/**\n * The action that can be performed to set a contact in the {@link AddressBookController}.\n */\nexport type AddressBookControllerSetAction = {\n type: `${typeof controllerName}:set`;\n handler: AddressBookController['set'];\n};\n\n/**\n * The action that can be performed to delete a contact from the {@link AddressBookController}.\n */\nexport type AddressBookControllerDeleteAction = {\n type: `${typeof controllerName}:delete`;\n handler: AddressBookController['delete'];\n};\n\n/**\n * Event emitted when a contact is added or updated\n */\nexport type AddressBookControllerContactUpdatedEvent = {\n type: `${typeof controllerName}:contactUpdated`;\n payload: [AddressBookEntry];\n};\n\n/**\n * Event emitted when a contact is deleted\n */\nexport type AddressBookControllerContactDeletedEvent = {\n type: `${typeof controllerName}:contactDeleted`;\n payload: [AddressBookEntry];\n};\n\n/**\n * The actions that can be performed using the {@link AddressBookController}.\n */\nexport type AddressBookControllerActions =\n | AddressBookControllerGetStateAction\n | AddressBookControllerListAction\n | AddressBookControllerSetAction\n | AddressBookControllerDeleteAction;\n\n/**\n * The event that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The events that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerEvents =\n | AddressBookControllerStateChangeEvent\n | AddressBookControllerContactUpdatedEvent\n | AddressBookControllerContactDeletedEvent;\n\nconst addressBookControllerMetadata = {\n addressBook: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link AddressBookController} state.\n *\n * @returns The default {@link AddressBookController} state.\n */\nexport const getDefaultAddressBookControllerState =\n (): AddressBookControllerState => {\n return {\n addressBook: {},\n };\n };\n\n/**\n * The messenger of the {@link AddressBookController} for communication.\n */\nexport type AddressBookControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AddressBookControllerActions,\n AddressBookControllerEvents,\n never,\n never\n>;\n\n/**\n * Controller that manages a list of recipient addresses associated with nicknames.\n */\nexport class AddressBookController extends BaseController<\n typeof controllerName,\n AddressBookControllerState,\n AddressBookControllerMessenger\n> {\n /**\n * Creates an AddressBookController instance.\n *\n * @param args - The {@link AddressBookController} arguments.\n * @param args.messenger - The controller messenger instance for communication.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AddressBookControllerMessenger;\n state?: Partial<AddressBookControllerState>;\n }) {\n const mergedState = { ...getDefaultAddressBookControllerState(), ...state };\n super({\n messenger,\n metadata: addressBookControllerMetadata,\n name: controllerName,\n state: mergedState,\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Returns all address book entries as an array.\n *\n * @returns Array of all address book entries.\n */\n list(): AddressBookEntry[] {\n const { addressBook } = this.state;\n\n return Object.keys(addressBook).reduce<AddressBookEntry[]>(\n (acc, chainId) => {\n const chainIdHex = chainId as Hex;\n const chainContacts = Object.values(addressBook[chainIdHex]);\n\n return [...acc, ...chainContacts];\n },\n [],\n );\n }\n\n /**\n * Remove all contract entries.\n */\n clear() {\n this.update((state) => {\n state.addressBook = {};\n });\n }\n\n /**\n * Remove a contract entry by address.\n *\n * @param chainId - Chain id identifies the current chain.\n * @param address - Recipient address to delete.\n * @returns Whether the entry was deleted.\n */\n delete(chainId: Hex, address: string) {\n address = toChecksumHexAddress(address);\n if (\n ![chainId, address].every((key) => isSafeDynamicKey(key)) ||\n !isValidHexAddress(address) ||\n !this.state.addressBook[chainId] ||\n !this.state.addressBook[chainId][address]\n ) {\n return false;\n }\n\n const deletedEntry = { ...this.state.addressBook[chainId][address] };\n\n this.update((state) => {\n const chainContacts = state.addressBook[chainId];\n if (chainContacts?.[address]) {\n delete chainContacts[address];\n\n // Clean up empty chainId objects\n if (Object.keys(chainContacts).length === 0) {\n delete state.addressBook[chainId];\n }\n }\n });\n\n // Skip sending delete event for global contacts with chainId '*'\n // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),\n // not user-created contacts. They don't need to trigger sync events.\n if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {\n this.messagingSystem.publish(\n 'AddressBookController:contactDeleted',\n deletedEntry,\n );\n }\n\n return true;\n }\n\n /**\n * Add or update a contact entry by address.\n *\n * @param address - Recipient address to add or update.\n * @param name - Nickname to associate with this address.\n * @param chainId - Chain id identifies the current chain.\n * @param memo - User's note about address.\n * @param addressType - Contact's address type.\n * @returns Boolean indicating if the address was successfully set.\n */\n set(\n address: string,\n name: string,\n chainId = toHex(1),\n memo = '',\n addressType?: AddressType,\n ) {\n address = toChecksumHexAddress(address);\n if (!isValidHexAddress(address)) {\n return false;\n }\n\n const entry = {\n address,\n chainId,\n isEns: false,\n memo,\n name,\n addressType,\n lastUpdatedAt: Date.now(),\n };\n const ensName = normalizeEnsName(name);\n if (ensName) {\n entry.name = ensName;\n entry.isEns = true;\n }\n\n this.update((state) => {\n state.addressBook = {\n ...this.state.addressBook,\n [chainId]: {\n ...this.state.addressBook[chainId],\n [address]: entry,\n },\n };\n });\n\n // Skip sending update event for global contacts with chainId '*'\n // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),\n // not user-created contacts. They don't need to trigger sync events.\n if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {\n this.messagingSystem.publish(\n 'AddressBookController:contactUpdated',\n entry,\n );\n }\n\n return true;\n }\n\n /**\n * Registers message handlers for the AddressBookController.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:list`,\n this.list.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${controllerName}:set`,\n this.set.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${controllerName}:delete`,\n this.delete.bind(this),\n );\n }\n}\n\nexport default AddressBookController;\n"]}
@@ -2,16 +2,14 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMe
2
2
  import { BaseController } from "@metamask/base-controller";
3
3
  import type { Hex } from "@metamask/utils";
4
4
  /**
5
- * @type ContactEntry
6
- *
7
5
  * ContactEntry representation
8
- * @property address - Hex address of a recipient account
9
- * @property name - Nickname associated with this address
10
- * @property importTime - Data time when an account as created/imported
11
6
  */
12
7
  export type ContactEntry = {
8
+ /** Hex address of a recipient account */
13
9
  address: string;
10
+ /** Nickname associated with this address */
14
11
  name: string;
12
+ /** Data time when an account as created/imported */
15
13
  importTime?: number;
16
14
  };
17
15
  /**
@@ -23,31 +21,29 @@ export declare enum AddressType {
23
21
  nonAccounts = "NON_ACCOUNTS"
24
22
  }
25
23
  /**
26
- * @type AddressBookEntry
27
- *
28
- * AddressBookEntry representation
29
- * @property address - Hex address of a recipient account
30
- * @property name - Nickname associated with this address
31
- * @property chainId - Chain id identifies the current chain
32
- * @property memo - User's note about address
33
- * @property isEns - is the entry an ENS name
34
- * @property addressType - is the type of this address
24
+ * AddressBookEntry represents a contact in the address book.
35
25
  */
36
26
  export type AddressBookEntry = {
27
+ /** Hex address of a recipient account */
37
28
  address: string;
29
+ /** Nickname associated with this address */
38
30
  name: string;
31
+ /** Chain id identifies the current chain */
39
32
  chainId: Hex;
33
+ /** User's note about address */
40
34
  memo: string;
35
+ /** Indicates if the entry is an ENS name */
41
36
  isEns: boolean;
37
+ /** The type of this address */
42
38
  addressType?: AddressType;
39
+ /** Timestamp of when this entry was last updated */
40
+ lastUpdatedAt?: number;
43
41
  };
44
42
  /**
45
- * @type AddressBookState
46
- *
47
- * Address book controller state
48
- * @property addressBook - Array of contact entry objects
43
+ * State for the AddressBookController.
49
44
  */
50
45
  export type AddressBookControllerState = {
46
+ /** Map of chainId to address to contact entries */
51
47
  addressBook: {
52
48
  [chainId: Hex]: {
53
49
  [address: string]: AddressBookEntry;
@@ -62,10 +58,45 @@ export declare const controllerName = "AddressBookController";
62
58
  * The action that can be performed to get the state of the {@link AddressBookController}.
63
59
  */
64
60
  export type AddressBookControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AddressBookControllerState>;
61
+ /**
62
+ * The action that can be performed to list contacts from the {@link AddressBookController}.
63
+ */
64
+ export type AddressBookControllerListAction = {
65
+ type: `${typeof controllerName}:list`;
66
+ handler: AddressBookController['list'];
67
+ };
68
+ /**
69
+ * The action that can be performed to set a contact in the {@link AddressBookController}.
70
+ */
71
+ export type AddressBookControllerSetAction = {
72
+ type: `${typeof controllerName}:set`;
73
+ handler: AddressBookController['set'];
74
+ };
75
+ /**
76
+ * The action that can be performed to delete a contact from the {@link AddressBookController}.
77
+ */
78
+ export type AddressBookControllerDeleteAction = {
79
+ type: `${typeof controllerName}:delete`;
80
+ handler: AddressBookController['delete'];
81
+ };
82
+ /**
83
+ * Event emitted when a contact is added or updated
84
+ */
85
+ export type AddressBookControllerContactUpdatedEvent = {
86
+ type: `${typeof controllerName}:contactUpdated`;
87
+ payload: [AddressBookEntry];
88
+ };
89
+ /**
90
+ * Event emitted when a contact is deleted
91
+ */
92
+ export type AddressBookControllerContactDeletedEvent = {
93
+ type: `${typeof controllerName}:contactDeleted`;
94
+ payload: [AddressBookEntry];
95
+ };
65
96
  /**
66
97
  * The actions that can be performed using the {@link AddressBookController}.
67
98
  */
68
- export type AddressBookControllerActions = AddressBookControllerGetStateAction;
99
+ export type AddressBookControllerActions = AddressBookControllerGetStateAction | AddressBookControllerListAction | AddressBookControllerSetAction | AddressBookControllerDeleteAction;
69
100
  /**
70
101
  * The event that {@link AddressBookController} can emit.
71
102
  */
@@ -73,7 +104,7 @@ export type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<t
73
104
  /**
74
105
  * The events that {@link AddressBookController} can emit.
75
106
  */
76
- export type AddressBookControllerEvents = AddressBookControllerStateChangeEvent;
107
+ export type AddressBookControllerEvents = AddressBookControllerStateChangeEvent | AddressBookControllerContactUpdatedEvent | AddressBookControllerContactDeletedEvent;
77
108
  /**
78
109
  * Get the default {@link AddressBookController} state.
79
110
  *
@@ -88,6 +119,7 @@ export type AddressBookControllerMessenger = RestrictedMessenger<typeof controll
88
119
  * Controller that manages a list of recipient addresses associated with nicknames.
89
120
  */
90
121
  export declare class AddressBookController extends BaseController<typeof controllerName, AddressBookControllerState, AddressBookControllerMessenger> {
122
+ #private;
91
123
  /**
92
124
  * Creates an AddressBookController instance.
93
125
  *
@@ -99,6 +131,12 @@ export declare class AddressBookController extends BaseController<typeof control
99
131
  messenger: AddressBookControllerMessenger;
100
132
  state?: Partial<AddressBookControllerState>;
101
133
  });
134
+ /**
135
+ * Returns all address book entries as an array.
136
+ *
137
+ * @returns Array of all address book entries.
138
+ */
139
+ list(): AddressBookEntry[];
102
140
  /**
103
141
  * Remove all contract entries.
104
142
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AddressBookController.d.cts","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAQ3D,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,oBAAY,WAAW;IAGrB,uBAAuB,8BAA8B;IAGrD,gBAAgB,sBAAsB;IAGtC,WAAW,iBAAiB;CAC7B;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,GAAG,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,EAAE;QAAE,CAAC,OAAO,EAAE,GAAG,GAAG;YAAE,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAA;SAAE,CAAA;KAAE,CAAC;CAC1E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,mCAAmC,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAMhF;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,QAC3C,0BAIH,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,CAC9D,OAAO,cAAc,EACrB,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,EACL,KAAK,CACN,CAAC;AAEF;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;KAC7C;IAUD;;OAEG;IACH,KAAK;IAML;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM;IAqBpC;;;;;;;;;OASG;IACH,GAAG,CACD,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,gBAAW,EAClB,IAAI,SAAK,EACT,WAAW,CAAC,EAAE,WAAW;CAkC5B;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"AddressBookController.d.cts","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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"}
@@ -2,16 +2,14 @@ import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMe
2
2
  import { BaseController } from "@metamask/base-controller";
3
3
  import type { Hex } from "@metamask/utils";
4
4
  /**
5
- * @type ContactEntry
6
- *
7
5
  * ContactEntry representation
8
- * @property address - Hex address of a recipient account
9
- * @property name - Nickname associated with this address
10
- * @property importTime - Data time when an account as created/imported
11
6
  */
12
7
  export type ContactEntry = {
8
+ /** Hex address of a recipient account */
13
9
  address: string;
10
+ /** Nickname associated with this address */
14
11
  name: string;
12
+ /** Data time when an account as created/imported */
15
13
  importTime?: number;
16
14
  };
17
15
  /**
@@ -23,31 +21,29 @@ export declare enum AddressType {
23
21
  nonAccounts = "NON_ACCOUNTS"
24
22
  }
25
23
  /**
26
- * @type AddressBookEntry
27
- *
28
- * AddressBookEntry representation
29
- * @property address - Hex address of a recipient account
30
- * @property name - Nickname associated with this address
31
- * @property chainId - Chain id identifies the current chain
32
- * @property memo - User's note about address
33
- * @property isEns - is the entry an ENS name
34
- * @property addressType - is the type of this address
24
+ * AddressBookEntry represents a contact in the address book.
35
25
  */
36
26
  export type AddressBookEntry = {
27
+ /** Hex address of a recipient account */
37
28
  address: string;
29
+ /** Nickname associated with this address */
38
30
  name: string;
31
+ /** Chain id identifies the current chain */
39
32
  chainId: Hex;
33
+ /** User's note about address */
40
34
  memo: string;
35
+ /** Indicates if the entry is an ENS name */
41
36
  isEns: boolean;
37
+ /** The type of this address */
42
38
  addressType?: AddressType;
39
+ /** Timestamp of when this entry was last updated */
40
+ lastUpdatedAt?: number;
43
41
  };
44
42
  /**
45
- * @type AddressBookState
46
- *
47
- * Address book controller state
48
- * @property addressBook - Array of contact entry objects
43
+ * State for the AddressBookController.
49
44
  */
50
45
  export type AddressBookControllerState = {
46
+ /** Map of chainId to address to contact entries */
51
47
  addressBook: {
52
48
  [chainId: Hex]: {
53
49
  [address: string]: AddressBookEntry;
@@ -62,10 +58,45 @@ export declare const controllerName = "AddressBookController";
62
58
  * The action that can be performed to get the state of the {@link AddressBookController}.
63
59
  */
64
60
  export type AddressBookControllerGetStateAction = ControllerGetStateAction<typeof controllerName, AddressBookControllerState>;
61
+ /**
62
+ * The action that can be performed to list contacts from the {@link AddressBookController}.
63
+ */
64
+ export type AddressBookControllerListAction = {
65
+ type: `${typeof controllerName}:list`;
66
+ handler: AddressBookController['list'];
67
+ };
68
+ /**
69
+ * The action that can be performed to set a contact in the {@link AddressBookController}.
70
+ */
71
+ export type AddressBookControllerSetAction = {
72
+ type: `${typeof controllerName}:set`;
73
+ handler: AddressBookController['set'];
74
+ };
75
+ /**
76
+ * The action that can be performed to delete a contact from the {@link AddressBookController}.
77
+ */
78
+ export type AddressBookControllerDeleteAction = {
79
+ type: `${typeof controllerName}:delete`;
80
+ handler: AddressBookController['delete'];
81
+ };
82
+ /**
83
+ * Event emitted when a contact is added or updated
84
+ */
85
+ export type AddressBookControllerContactUpdatedEvent = {
86
+ type: `${typeof controllerName}:contactUpdated`;
87
+ payload: [AddressBookEntry];
88
+ };
89
+ /**
90
+ * Event emitted when a contact is deleted
91
+ */
92
+ export type AddressBookControllerContactDeletedEvent = {
93
+ type: `${typeof controllerName}:contactDeleted`;
94
+ payload: [AddressBookEntry];
95
+ };
65
96
  /**
66
97
  * The actions that can be performed using the {@link AddressBookController}.
67
98
  */
68
- export type AddressBookControllerActions = AddressBookControllerGetStateAction;
99
+ export type AddressBookControllerActions = AddressBookControllerGetStateAction | AddressBookControllerListAction | AddressBookControllerSetAction | AddressBookControllerDeleteAction;
69
100
  /**
70
101
  * The event that {@link AddressBookController} can emit.
71
102
  */
@@ -73,7 +104,7 @@ export type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<t
73
104
  /**
74
105
  * The events that {@link AddressBookController} can emit.
75
106
  */
76
- export type AddressBookControllerEvents = AddressBookControllerStateChangeEvent;
107
+ export type AddressBookControllerEvents = AddressBookControllerStateChangeEvent | AddressBookControllerContactUpdatedEvent | AddressBookControllerContactDeletedEvent;
77
108
  /**
78
109
  * Get the default {@link AddressBookController} state.
79
110
  *
@@ -88,6 +119,7 @@ export type AddressBookControllerMessenger = RestrictedMessenger<typeof controll
88
119
  * Controller that manages a list of recipient addresses associated with nicknames.
89
120
  */
90
121
  export declare class AddressBookController extends BaseController<typeof controllerName, AddressBookControllerState, AddressBookControllerMessenger> {
122
+ #private;
91
123
  /**
92
124
  * Creates an AddressBookController instance.
93
125
  *
@@ -99,6 +131,12 @@ export declare class AddressBookController extends BaseController<typeof control
99
131
  messenger: AddressBookControllerMessenger;
100
132
  state?: Partial<AddressBookControllerState>;
101
133
  });
134
+ /**
135
+ * Returns all address book entries as an array.
136
+ *
137
+ * @returns Array of all address book entries.
138
+ */
139
+ list(): AddressBookEntry[];
102
140
  /**
103
141
  * Remove all contract entries.
104
142
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AddressBookController.d.mts","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAQ3D,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,oBAAY,WAAW;IAGrB,uBAAuB,8BAA8B;IAGrD,gBAAgB,sBAAsB;IAGtC,WAAW,iBAAiB;CAC7B;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,GAAG,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,EAAE;QAAE,CAAC,OAAO,EAAE,GAAG,GAAG;YAAE,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAAA;SAAE,CAAA;KAAE,CAAC;CAC1E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,mCAAmC,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAMhF;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,QAC3C,0BAIH,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,CAC9D,OAAO,cAAc,EACrB,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,EACL,KAAK,CACN,CAAC;AAEF;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;IACC;;;;;;OAMG;gBACS,EACV,SAAS,EACT,KAAK,GACN,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;KAC7C;IAUD;;OAEG;IACH,KAAK;IAML;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM;IAqBpC;;;;;;;;;OASG;IACH,GAAG,CACD,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,gBAAW,EAClB,IAAI,SAAK,EACT,WAAW,CAAC,EAAE,WAAW;CAkC5B;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"AddressBookController.d.mts","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,9 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ 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");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _AddressBookController_instances, _AddressBookController_registerMessageHandlers;
1
7
  import { BaseController } from "@metamask/base-controller";
2
8
  import { normalizeEnsName, isValidHexAddress, isSafeDynamicKey, toChecksumHexAddress, toHex } from "@metamask/controller-utils";
3
9
  /**
@@ -5,20 +11,19 @@ import { normalizeEnsName, isValidHexAddress, isSafeDynamicKey, toChecksumHexAdd
5
11
  */
6
12
  export var AddressType;
7
13
  (function (AddressType) {
8
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
9
- // eslint-disable-next-line @typescript-eslint/naming-convention
10
14
  AddressType["externallyOwnedAccounts"] = "EXTERNALLY_OWNED_ACCOUNTS";
11
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
12
- // eslint-disable-next-line @typescript-eslint/naming-convention
13
15
  AddressType["contractAccounts"] = "CONTRACT_ACCOUNTS";
14
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
15
- // eslint-disable-next-line @typescript-eslint/naming-convention
16
16
  AddressType["nonAccounts"] = "NON_ACCOUNTS";
17
17
  })(AddressType || (AddressType = {}));
18
18
  /**
19
19
  * The name of the {@link AddressBookController}.
20
20
  */
21
21
  export const controllerName = 'AddressBookController';
22
+ /**
23
+ * Special chainId used for wallet's own accounts (internal MetaMask accounts).
24
+ * These entries don't trigger sync events as they are not user-created contacts.
25
+ */
26
+ const WALLET_ACCOUNTS_CHAIN_ID = '*';
22
27
  const addressBookControllerMetadata = {
23
28
  addressBook: { persist: true, anonymous: false },
24
29
  };
@@ -51,6 +56,21 @@ export class AddressBookController extends BaseController {
51
56
  name: controllerName,
52
57
  state: mergedState,
53
58
  });
59
+ _AddressBookController_instances.add(this);
60
+ __classPrivateFieldGet(this, _AddressBookController_instances, "m", _AddressBookController_registerMessageHandlers).call(this);
61
+ }
62
+ /**
63
+ * Returns all address book entries as an array.
64
+ *
65
+ * @returns Array of all address book entries.
66
+ */
67
+ list() {
68
+ const { addressBook } = this.state;
69
+ return Object.keys(addressBook).reduce((acc, chainId) => {
70
+ const chainIdHex = chainId;
71
+ const chainContacts = Object.values(addressBook[chainIdHex]);
72
+ return [...acc, ...chainContacts];
73
+ }, []);
54
74
  }
55
75
  /**
56
76
  * Remove all contract entries.
@@ -75,12 +95,23 @@ export class AddressBookController extends BaseController {
75
95
  !this.state.addressBook[chainId][address]) {
76
96
  return false;
77
97
  }
98
+ const deletedEntry = { ...this.state.addressBook[chainId][address] };
78
99
  this.update((state) => {
79
- delete state.addressBook[chainId][address];
80
- if (Object.keys(state.addressBook[chainId]).length === 0) {
81
- delete state.addressBook[chainId];
100
+ const chainContacts = state.addressBook[chainId];
101
+ if (chainContacts?.[address]) {
102
+ delete chainContacts[address];
103
+ // Clean up empty chainId objects
104
+ if (Object.keys(chainContacts).length === 0) {
105
+ delete state.addressBook[chainId];
106
+ }
82
107
  }
83
108
  });
109
+ // Skip sending delete event for global contacts with chainId '*'
110
+ // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),
111
+ // not user-created contacts. They don't need to trigger sync events.
112
+ if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {
113
+ this.messagingSystem.publish('AddressBookController:contactDeleted', deletedEntry);
114
+ }
84
115
  return true;
85
116
  }
86
117
  /**
@@ -105,6 +136,7 @@ export class AddressBookController extends BaseController {
105
136
  memo,
106
137
  name,
107
138
  addressType,
139
+ lastUpdatedAt: Date.now(),
108
140
  };
109
141
  const ensName = normalizeEnsName(name);
110
142
  if (ensName) {
@@ -120,8 +152,19 @@ export class AddressBookController extends BaseController {
120
152
  },
121
153
  };
122
154
  });
155
+ // Skip sending update event for global contacts with chainId '*'
156
+ // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),
157
+ // not user-created contacts. They don't need to trigger sync events.
158
+ if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {
159
+ this.messagingSystem.publish('AddressBookController:contactUpdated', entry);
160
+ }
123
161
  return true;
124
162
  }
125
163
  }
164
+ _AddressBookController_instances = new WeakSet(), _AddressBookController_registerMessageHandlers = function _AddressBookController_registerMessageHandlers() {
165
+ this.messagingSystem.registerActionHandler(`${controllerName}:list`, this.list.bind(this));
166
+ this.messagingSystem.registerActionHandler(`${controllerName}:set`, this.set.bind(this));
167
+ this.messagingSystem.registerActionHandler(`${controllerName}:delete`, this.delete.bind(this));
168
+ };
126
169
  export default AddressBookController;
127
170
  //# sourceMappingURL=AddressBookController.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"AddressBookController.mjs","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n normalizeEnsName,\n isValidHexAddress,\n isSafeDynamicKey,\n toChecksumHexAddress,\n toHex,\n} from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\n/**\n * @type ContactEntry\n *\n * ContactEntry representation\n * @property address - Hex address of a recipient account\n * @property name - Nickname associated with this address\n * @property importTime - Data time when an account as created/imported\n */\nexport type ContactEntry = {\n address: string;\n name: string;\n importTime?: number;\n};\n\n/**\n * The type of address.\n */\nexport enum AddressType {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n externallyOwnedAccounts = 'EXTERNALLY_OWNED_ACCOUNTS',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n contractAccounts = 'CONTRACT_ACCOUNTS',\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/naming-convention\n nonAccounts = 'NON_ACCOUNTS',\n}\n\n/**\n * @type AddressBookEntry\n *\n * AddressBookEntry representation\n * @property address - Hex address of a recipient account\n * @property name - Nickname associated with this address\n * @property chainId - Chain id identifies the current chain\n * @property memo - User's note about address\n * @property isEns - is the entry an ENS name\n * @property addressType - is the type of this address\n */\nexport type AddressBookEntry = {\n address: string;\n name: string;\n chainId: Hex;\n memo: string;\n isEns: boolean;\n addressType?: AddressType;\n};\n\n/**\n * @type AddressBookState\n *\n * Address book controller state\n * @property addressBook - Array of contact entry objects\n */\nexport type AddressBookControllerState = {\n addressBook: { [chainId: Hex]: { [address: string]: AddressBookEntry } };\n};\n\n/**\n * The name of the {@link AddressBookController}.\n */\nexport const controllerName = 'AddressBookController';\n\n/**\n * The action that can be performed to get the state of the {@link AddressBookController}.\n */\nexport type AddressBookControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AddressBookController}.\n */\nexport type AddressBookControllerActions = AddressBookControllerGetStateAction;\n\n/**\n * The event that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The events that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerEvents = AddressBookControllerStateChangeEvent;\n\nconst addressBookControllerMetadata = {\n addressBook: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link AddressBookController} state.\n *\n * @returns The default {@link AddressBookController} state.\n */\nexport const getDefaultAddressBookControllerState =\n (): AddressBookControllerState => {\n return {\n addressBook: {},\n };\n };\n\n/**\n * The messenger of the {@link AddressBookController} for communication.\n */\nexport type AddressBookControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AddressBookControllerActions,\n AddressBookControllerEvents,\n never,\n never\n>;\n\n/**\n * Controller that manages a list of recipient addresses associated with nicknames.\n */\nexport class AddressBookController extends BaseController<\n typeof controllerName,\n AddressBookControllerState,\n AddressBookControllerMessenger\n> {\n /**\n * Creates an AddressBookController instance.\n *\n * @param args - The {@link AddressBookController} arguments.\n * @param args.messenger - The controller messenger instance for communication.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AddressBookControllerMessenger;\n state?: Partial<AddressBookControllerState>;\n }) {\n const mergedState = { ...getDefaultAddressBookControllerState(), ...state };\n super({\n messenger,\n metadata: addressBookControllerMetadata,\n name: controllerName,\n state: mergedState,\n });\n }\n\n /**\n * Remove all contract entries.\n */\n clear() {\n this.update((state) => {\n state.addressBook = {};\n });\n }\n\n /**\n * Remove a contract entry by address.\n *\n * @param chainId - Chain id identifies the current chain.\n * @param address - Recipient address to delete.\n * @returns Whether the entry was deleted.\n */\n delete(chainId: Hex, address: string) {\n address = toChecksumHexAddress(address);\n if (\n ![chainId, address].every((key) => isSafeDynamicKey(key)) ||\n !isValidHexAddress(address) ||\n !this.state.addressBook[chainId] ||\n !this.state.addressBook[chainId][address]\n ) {\n return false;\n }\n\n this.update((state) => {\n delete state.addressBook[chainId][address];\n if (Object.keys(state.addressBook[chainId]).length === 0) {\n delete state.addressBook[chainId];\n }\n });\n\n return true;\n }\n\n /**\n * Add or update a contact entry by address.\n *\n * @param address - Recipient address to add or update.\n * @param name - Nickname to associate with this address.\n * @param chainId - Chain id identifies the current chain.\n * @param memo - User's note about address.\n * @param addressType - Contact's address type.\n * @returns Boolean indicating if the address was successfully set.\n */\n set(\n address: string,\n name: string,\n chainId = toHex(1),\n memo = '',\n addressType?: AddressType,\n ) {\n address = toChecksumHexAddress(address);\n if (!isValidHexAddress(address)) {\n return false;\n }\n\n const entry = {\n address,\n chainId,\n isEns: false,\n memo,\n name,\n addressType,\n };\n\n const ensName = normalizeEnsName(name);\n if (ensName) {\n entry.name = ensName;\n entry.isEns = true;\n }\n\n this.update((state) => {\n state.addressBook = {\n ...this.state.addressBook,\n [chainId]: {\n ...this.state.addressBook[chainId],\n [address]: entry,\n },\n };\n });\n\n return true;\n }\n}\n\nexport default AddressBookController;\n"]}
1
+ {"version":3,"file":"AddressBookController.mjs","sourceRoot":"","sources":["../src/AddressBookController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n normalizeEnsName,\n isValidHexAddress,\n isSafeDynamicKey,\n toChecksumHexAddress,\n toHex,\n} from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\n/**\n * ContactEntry representation\n */\nexport type ContactEntry = {\n /** Hex address of a recipient account */\n address: string;\n /** Nickname associated with this address */\n name: string;\n /** Data time when an account as created/imported */\n importTime?: number;\n};\n\n/**\n * The type of address.\n */\nexport enum AddressType {\n externallyOwnedAccounts = 'EXTERNALLY_OWNED_ACCOUNTS',\n contractAccounts = 'CONTRACT_ACCOUNTS',\n nonAccounts = 'NON_ACCOUNTS',\n}\n\n/**\n * AddressBookEntry represents a contact in the address book.\n */\nexport type AddressBookEntry = {\n /** Hex address of a recipient account */\n address: string;\n /** Nickname associated with this address */\n name: string;\n /** Chain id identifies the current chain */\n chainId: Hex;\n /** User's note about address */\n memo: string;\n /** Indicates if the entry is an ENS name */\n isEns: boolean;\n /** The type of this address */\n addressType?: AddressType;\n /** Timestamp of when this entry was last updated */\n lastUpdatedAt?: number;\n};\n\n/**\n * State for the AddressBookController.\n */\nexport type AddressBookControllerState = {\n /** Map of chainId to address to contact entries */\n addressBook: { [chainId: Hex]: { [address: string]: AddressBookEntry } };\n};\n\n/**\n * The name of the {@link AddressBookController}.\n */\nexport const controllerName = 'AddressBookController';\n\n/**\n * Special chainId used for wallet's own accounts (internal MetaMask accounts).\n * These entries don't trigger sync events as they are not user-created contacts.\n */\nconst WALLET_ACCOUNTS_CHAIN_ID = '*';\n\n/**\n * The action that can be performed to get the state of the {@link AddressBookController}.\n */\nexport type AddressBookControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The action that can be performed to list contacts from the {@link AddressBookController}.\n */\nexport type AddressBookControllerListAction = {\n type: `${typeof controllerName}:list`;\n handler: AddressBookController['list'];\n};\n\n/**\n * The action that can be performed to set a contact in the {@link AddressBookController}.\n */\nexport type AddressBookControllerSetAction = {\n type: `${typeof controllerName}:set`;\n handler: AddressBookController['set'];\n};\n\n/**\n * The action that can be performed to delete a contact from the {@link AddressBookController}.\n */\nexport type AddressBookControllerDeleteAction = {\n type: `${typeof controllerName}:delete`;\n handler: AddressBookController['delete'];\n};\n\n/**\n * Event emitted when a contact is added or updated\n */\nexport type AddressBookControllerContactUpdatedEvent = {\n type: `${typeof controllerName}:contactUpdated`;\n payload: [AddressBookEntry];\n};\n\n/**\n * Event emitted when a contact is deleted\n */\nexport type AddressBookControllerContactDeletedEvent = {\n type: `${typeof controllerName}:contactDeleted`;\n payload: [AddressBookEntry];\n};\n\n/**\n * The actions that can be performed using the {@link AddressBookController}.\n */\nexport type AddressBookControllerActions =\n | AddressBookControllerGetStateAction\n | AddressBookControllerListAction\n | AddressBookControllerSetAction\n | AddressBookControllerDeleteAction;\n\n/**\n * The event that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AddressBookControllerState\n>;\n\n/**\n * The events that {@link AddressBookController} can emit.\n */\nexport type AddressBookControllerEvents =\n | AddressBookControllerStateChangeEvent\n | AddressBookControllerContactUpdatedEvent\n | AddressBookControllerContactDeletedEvent;\n\nconst addressBookControllerMetadata = {\n addressBook: { persist: true, anonymous: false },\n};\n\n/**\n * Get the default {@link AddressBookController} state.\n *\n * @returns The default {@link AddressBookController} state.\n */\nexport const getDefaultAddressBookControllerState =\n (): AddressBookControllerState => {\n return {\n addressBook: {},\n };\n };\n\n/**\n * The messenger of the {@link AddressBookController} for communication.\n */\nexport type AddressBookControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n AddressBookControllerActions,\n AddressBookControllerEvents,\n never,\n never\n>;\n\n/**\n * Controller that manages a list of recipient addresses associated with nicknames.\n */\nexport class AddressBookController extends BaseController<\n typeof controllerName,\n AddressBookControllerState,\n AddressBookControllerMessenger\n> {\n /**\n * Creates an AddressBookController instance.\n *\n * @param args - The {@link AddressBookController} arguments.\n * @param args.messenger - The controller messenger instance for communication.\n * @param args.state - Initial state to set on this controller.\n */\n constructor({\n messenger,\n state,\n }: {\n messenger: AddressBookControllerMessenger;\n state?: Partial<AddressBookControllerState>;\n }) {\n const mergedState = { ...getDefaultAddressBookControllerState(), ...state };\n super({\n messenger,\n metadata: addressBookControllerMetadata,\n name: controllerName,\n state: mergedState,\n });\n\n this.#registerMessageHandlers();\n }\n\n /**\n * Returns all address book entries as an array.\n *\n * @returns Array of all address book entries.\n */\n list(): AddressBookEntry[] {\n const { addressBook } = this.state;\n\n return Object.keys(addressBook).reduce<AddressBookEntry[]>(\n (acc, chainId) => {\n const chainIdHex = chainId as Hex;\n const chainContacts = Object.values(addressBook[chainIdHex]);\n\n return [...acc, ...chainContacts];\n },\n [],\n );\n }\n\n /**\n * Remove all contract entries.\n */\n clear() {\n this.update((state) => {\n state.addressBook = {};\n });\n }\n\n /**\n * Remove a contract entry by address.\n *\n * @param chainId - Chain id identifies the current chain.\n * @param address - Recipient address to delete.\n * @returns Whether the entry was deleted.\n */\n delete(chainId: Hex, address: string) {\n address = toChecksumHexAddress(address);\n if (\n ![chainId, address].every((key) => isSafeDynamicKey(key)) ||\n !isValidHexAddress(address) ||\n !this.state.addressBook[chainId] ||\n !this.state.addressBook[chainId][address]\n ) {\n return false;\n }\n\n const deletedEntry = { ...this.state.addressBook[chainId][address] };\n\n this.update((state) => {\n const chainContacts = state.addressBook[chainId];\n if (chainContacts?.[address]) {\n delete chainContacts[address];\n\n // Clean up empty chainId objects\n if (Object.keys(chainContacts).length === 0) {\n delete state.addressBook[chainId];\n }\n }\n });\n\n // Skip sending delete event for global contacts with chainId '*'\n // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),\n // not user-created contacts. They don't need to trigger sync events.\n if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {\n this.messagingSystem.publish(\n 'AddressBookController:contactDeleted',\n deletedEntry,\n );\n }\n\n return true;\n }\n\n /**\n * Add or update a contact entry by address.\n *\n * @param address - Recipient address to add or update.\n * @param name - Nickname to associate with this address.\n * @param chainId - Chain id identifies the current chain.\n * @param memo - User's note about address.\n * @param addressType - Contact's address type.\n * @returns Boolean indicating if the address was successfully set.\n */\n set(\n address: string,\n name: string,\n chainId = toHex(1),\n memo = '',\n addressType?: AddressType,\n ) {\n address = toChecksumHexAddress(address);\n if (!isValidHexAddress(address)) {\n return false;\n }\n\n const entry = {\n address,\n chainId,\n isEns: false,\n memo,\n name,\n addressType,\n lastUpdatedAt: Date.now(),\n };\n const ensName = normalizeEnsName(name);\n if (ensName) {\n entry.name = ensName;\n entry.isEns = true;\n }\n\n this.update((state) => {\n state.addressBook = {\n ...this.state.addressBook,\n [chainId]: {\n ...this.state.addressBook[chainId],\n [address]: entry,\n },\n };\n });\n\n // Skip sending update event for global contacts with chainId '*'\n // These entries with chainId='*' are the wallet's own accounts (internal MetaMask accounts),\n // not user-created contacts. They don't need to trigger sync events.\n if (String(chainId) !== WALLET_ACCOUNTS_CHAIN_ID) {\n this.messagingSystem.publish(\n 'AddressBookController:contactUpdated',\n entry,\n );\n }\n\n return true;\n }\n\n /**\n * Registers message handlers for the AddressBookController.\n */\n #registerMessageHandlers() {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:list`,\n this.list.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${controllerName}:set`,\n this.set.bind(this),\n );\n this.messagingSystem.registerActionHandler(\n `${controllerName}:delete`,\n this.delete.bind(this),\n );\n }\n}\n\nexport default AddressBookController;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAWA,qEAGiC;AAF/B,6IAAA,oCAAoC,OAAA;AACpC,8HAAA,qBAAqB,OAAA","sourcesContent":["export type {\n AddressType,\n AddressBookEntry,\n AddressBookControllerState,\n AddressBookControllerGetStateAction,\n AddressBookControllerActions,\n AddressBookControllerStateChangeEvent,\n AddressBookControllerEvents,\n AddressBookControllerMessenger,\n ContactEntry,\n} from './AddressBookController';\nexport {\n getDefaultAddressBookControllerState,\n AddressBookController,\n} from './AddressBookController';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAgBA,qEAGiC;AAF/B,6IAAA,oCAAoC,OAAA;AACpC,8HAAA,qBAAqB,OAAA","sourcesContent":["export type {\n AddressType,\n AddressBookEntry,\n AddressBookControllerState,\n AddressBookControllerGetStateAction,\n AddressBookControllerListAction,\n AddressBookControllerSetAction,\n AddressBookControllerDeleteAction,\n AddressBookControllerActions,\n AddressBookControllerStateChangeEvent,\n AddressBookControllerContactUpdatedEvent,\n AddressBookControllerContactDeletedEvent,\n AddressBookControllerEvents,\n AddressBookControllerMessenger,\n ContactEntry,\n} from './AddressBookController';\nexport {\n getDefaultAddressBookControllerState,\n AddressBookController,\n} from './AddressBookController';\n"]}
package/dist/index.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- export type { AddressType, AddressBookEntry, AddressBookControllerState, AddressBookControllerGetStateAction, AddressBookControllerActions, AddressBookControllerStateChangeEvent, AddressBookControllerEvents, AddressBookControllerMessenger, ContactEntry, } from "./AddressBookController.cjs";
1
+ export type { AddressType, AddressBookEntry, AddressBookControllerState, AddressBookControllerGetStateAction, AddressBookControllerListAction, AddressBookControllerSetAction, AddressBookControllerDeleteAction, AddressBookControllerActions, AddressBookControllerStateChangeEvent, AddressBookControllerContactUpdatedEvent, AddressBookControllerContactDeletedEvent, AddressBookControllerEvents, AddressBookControllerMessenger, ContactEntry, } from "./AddressBookController.cjs";
2
2
  export { getDefaultAddressBookControllerState, AddressBookController, } from "./AddressBookController.cjs";
3
3
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,mCAAmC,EACnC,4BAA4B,EAC5B,qCAAqC,EACrC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,GACb,oCAAgC;AACjC,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,oCAAgC"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,mCAAmC,EACnC,+BAA+B,EAC/B,8BAA8B,EAC9B,iCAAiC,EACjC,4BAA4B,EAC5B,qCAAqC,EACrC,wCAAwC,EACxC,wCAAwC,EACxC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,GACb,oCAAgC;AACjC,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,oCAAgC"}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- export type { AddressType, AddressBookEntry, AddressBookControllerState, AddressBookControllerGetStateAction, AddressBookControllerActions, AddressBookControllerStateChangeEvent, AddressBookControllerEvents, AddressBookControllerMessenger, ContactEntry, } from "./AddressBookController.mjs";
1
+ export type { AddressType, AddressBookEntry, AddressBookControllerState, AddressBookControllerGetStateAction, AddressBookControllerListAction, AddressBookControllerSetAction, AddressBookControllerDeleteAction, AddressBookControllerActions, AddressBookControllerStateChangeEvent, AddressBookControllerContactUpdatedEvent, AddressBookControllerContactDeletedEvent, AddressBookControllerEvents, AddressBookControllerMessenger, ContactEntry, } from "./AddressBookController.mjs";
2
2
  export { getDefaultAddressBookControllerState, AddressBookController, } from "./AddressBookController.mjs";
3
3
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,mCAAmC,EACnC,4BAA4B,EAC5B,qCAAqC,EACrC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,GACb,oCAAgC;AACjC,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,oCAAgC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,mCAAmC,EACnC,+BAA+B,EAC/B,8BAA8B,EAC9B,iCAAiC,EACjC,4BAA4B,EAC5B,qCAAqC,EACrC,wCAAwC,EACxC,wCAAwC,EACxC,2BAA2B,EAC3B,8BAA8B,EAC9B,YAAY,GACb,oCAAgC;AACjC,OAAO,EACL,oCAAoC,EACpC,qBAAqB,GACtB,oCAAgC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,oCAAoC,EACpC,qBAAqB,EACtB,oCAAgC","sourcesContent":["export type {\n AddressType,\n AddressBookEntry,\n AddressBookControllerState,\n AddressBookControllerGetStateAction,\n AddressBookControllerActions,\n AddressBookControllerStateChangeEvent,\n AddressBookControllerEvents,\n AddressBookControllerMessenger,\n ContactEntry,\n} from './AddressBookController';\nexport {\n getDefaultAddressBookControllerState,\n AddressBookController,\n} from './AddressBookController';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,oCAAoC,EACpC,qBAAqB,EACtB,oCAAgC","sourcesContent":["export type {\n AddressType,\n AddressBookEntry,\n AddressBookControllerState,\n AddressBookControllerGetStateAction,\n AddressBookControllerListAction,\n AddressBookControllerSetAction,\n AddressBookControllerDeleteAction,\n AddressBookControllerActions,\n AddressBookControllerStateChangeEvent,\n AddressBookControllerContactUpdatedEvent,\n AddressBookControllerContactDeletedEvent,\n AddressBookControllerEvents,\n AddressBookControllerMessenger,\n ContactEntry,\n} from './AddressBookController';\nexport {\n getDefaultAddressBookControllerState,\n AddressBookController,\n} from './AddressBookController';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/address-book-controller",
3
- "version": "6.0.3-preview-4809837c",
3
+ "version": "6.0.3-preview-ae04854",
4
4
  "description": "Manages a list of recipient addresses associated with nicknames",
5
5
  "keywords": [
6
6
  "MetaMask",