@metamask-previews/account-tree-controller 7.6.1-preview-e57e5c3dc → 7.6.1-preview-c449b8da8

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.
Files changed (78) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/AccountTreeController-method-action-types.cjs.map +1 -1
  3. package/dist/AccountTreeController-method-action-types.d.cts +34 -1
  4. package/dist/AccountTreeController-method-action-types.d.cts.map +1 -1
  5. package/dist/AccountTreeController-method-action-types.d.mts +34 -1
  6. package/dist/AccountTreeController-method-action-types.d.mts.map +1 -1
  7. package/dist/AccountTreeController-method-action-types.mjs.map +1 -1
  8. package/dist/AccountTreeController.cjs +42 -0
  9. package/dist/AccountTreeController.cjs.map +1 -1
  10. package/dist/AccountTreeController.d.cts +29 -0
  11. package/dist/AccountTreeController.d.cts.map +1 -1
  12. package/dist/AccountTreeController.d.mts +29 -0
  13. package/dist/AccountTreeController.d.mts.map +1 -1
  14. package/dist/AccountTreeController.mjs +42 -0
  15. package/dist/AccountTreeController.mjs.map +1 -1
  16. package/dist/index.cjs +10 -1
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +5 -1
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +5 -1
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +3 -0
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/state/export.cjs +214 -0
  25. package/dist/state/export.cjs.map +1 -0
  26. package/dist/state/export.d.cts +40 -0
  27. package/dist/state/export.d.cts.map +1 -0
  28. package/dist/state/export.d.mts +40 -0
  29. package/dist/state/export.d.mts.map +1 -0
  30. package/dist/state/export.mjs +208 -0
  31. package/dist/state/export.mjs.map +1 -0
  32. package/dist/state/id-map.cjs +65 -0
  33. package/dist/state/id-map.cjs.map +1 -0
  34. package/dist/state/id-map.d.cts +41 -0
  35. package/dist/state/id-map.d.cts.map +1 -0
  36. package/dist/state/id-map.d.mts +41 -0
  37. package/dist/state/id-map.d.mts.map +1 -0
  38. package/dist/state/id-map.mjs +61 -0
  39. package/dist/state/id-map.mjs.map +1 -0
  40. package/dist/state/import.cjs +268 -0
  41. package/dist/state/import.cjs.map +1 -0
  42. package/dist/state/import.d.cts +29 -0
  43. package/dist/state/import.d.cts.map +1 -0
  44. package/dist/state/import.d.mts +29 -0
  45. package/dist/state/import.d.mts.map +1 -0
  46. package/dist/state/import.mjs +264 -0
  47. package/dist/state/import.mjs.map +1 -0
  48. package/dist/state/payload.cjs +169 -0
  49. package/dist/state/payload.cjs.map +1 -0
  50. package/dist/state/payload.d.cts +288 -0
  51. package/dist/state/payload.d.cts.map +1 -0
  52. package/dist/state/payload.d.mts +288 -0
  53. package/dist/state/payload.d.mts.map +1 -0
  54. package/dist/state/payload.mjs +162 -0
  55. package/dist/state/payload.mjs.map +1 -0
  56. package/dist/state/snapshot.cjs +202 -0
  57. package/dist/state/snapshot.cjs.map +1 -0
  58. package/dist/state/snapshot.d.cts +120 -0
  59. package/dist/state/snapshot.d.cts.map +1 -0
  60. package/dist/state/snapshot.d.mts +120 -0
  61. package/dist/state/snapshot.d.mts.map +1 -0
  62. package/dist/state/snapshot.mjs +198 -0
  63. package/dist/state/snapshot.mjs.map +1 -0
  64. package/dist/state/utils.cjs +68 -0
  65. package/dist/state/utils.cjs.map +1 -0
  66. package/dist/state/utils.d.cts +49 -0
  67. package/dist/state/utils.d.cts.map +1 -0
  68. package/dist/state/utils.d.mts +49 -0
  69. package/dist/state/utils.d.mts.map +1 -0
  70. package/dist/state/utils.mjs +61 -0
  71. package/dist/state/utils.mjs.map +1 -0
  72. package/dist/types.cjs.map +1 -1
  73. package/dist/types.d.cts +3 -3
  74. package/dist/types.d.cts.map +1 -1
  75. package/dist/types.d.mts +3 -3
  76. package/dist/types.d.mts.map +1 -1
  77. package/dist/types.mjs.map +1 -1
  78. package/package.json +3 -2
@@ -0,0 +1,120 @@
1
+ import type { IdMap } from "./id-map.mjs";
2
+ import type { AccountGroupPayloadId, AccountTreePayload, AccountTreeSnapshotGroup, AccountTreeSnapshotWallet, AccountTreeWalletEntry, AccountWalletPayloadId } from "./payload.mjs";
3
+ /**
4
+ * Immutable value object returned by {@link AccountTreeController.exportState}.
5
+ *
6
+ * Construct with {@link AccountTreeController.exportState},
7
+ * {@link AccountTreeSnapshot.deserialize}, or `new AccountTreeSnapshot(...)`
8
+ * for tests and advanced use.
9
+ *
10
+ * Wallet and group entries are deep-cloned and deep-frozen once in the
11
+ * constructor. Filtering predicates receive those read-only views directly;
12
+ * each filter method returns a new snapshot that repeats the process for its
13
+ * result.
14
+ *
15
+ * An optional ID map (local ↔ payload) may be supplied when bridging between
16
+ * internal controller IDs and the stable cross-device IDs in the serialized
17
+ * payload. The map covers the original export and is preserved unchanged
18
+ * through filtering until {@link serialize}. Omit it when deterministic IDs
19
+ * make {@link toLocalId} / {@link toPayloadId} unnecessary.
20
+ */
21
+ export declare class AccountTreeSnapshot {
22
+ #private;
23
+ /**
24
+ * @param entries - Wallet entries in the snapshot.
25
+ * @param idMap - Optional local ↔ payload ID map from export.
26
+ */
27
+ constructor(entries: AccountTreeWalletEntry[], idMap?: IdMap);
28
+ /**
29
+ * Returns a new snapshot containing only the wallets for which
30
+ * `predicate` returns `true`.
31
+ *
32
+ * When filtering by wallet ID, compare against stable payload IDs from
33
+ * {@link serialize} or convert local IDs with {@link toPayloadId} first.
34
+ *
35
+ * @param predicate - Function called with each deeply read-only wallet entry.
36
+ * @returns A filtered snapshot.
37
+ */
38
+ filterWallets(predicate: (wallet: AccountTreeSnapshotWallet) => boolean): AccountTreeSnapshot;
39
+ /**
40
+ * Filters groups within one wallet. Other wallets are left unchanged.
41
+ *
42
+ * Throws if `walletId` does not identify a wallet in the snapshot.
43
+ * Removes the wallet if no groups remain after filtering — this prevents a
44
+ * mnemonic wallet with zero selected groups from still transferring its secret.
45
+ *
46
+ * **Mnemonic wallets:** group indices must remain contiguous starting at 0
47
+ * after filtering, because the payload schema enforces this invariant.
48
+ * Predicates that produce gaps (e.g. keeping only index 1, or 0 and 2) will
49
+ * cause {@link AccountTreeSnapshot.deserialize} to reject the payload on the
50
+ * receiving end.
51
+ *
52
+ * @param walletId - Stable payload wallet ID to filter groups within.
53
+ * @param predicate - Function called with each deeply read-only group entry.
54
+ * @returns A filtered snapshot.
55
+ * @throws If `walletId` is not present in the snapshot.
56
+ */
57
+ filterGroups(walletId: AccountWalletPayloadId, predicate: (group: AccountTreeSnapshotGroup) => boolean): AccountTreeSnapshot;
58
+ /**
59
+ * Filters groups across every wallet.
60
+ *
61
+ * The parent wallet is provided as context to the predicate. Removes any
62
+ * wallet with no remaining groups after filtering.
63
+ *
64
+ * **Mnemonic wallets:** see {@link filterGroups} for the contiguous-index
65
+ * constraint that applies here as well.
66
+ *
67
+ * @param predicate - Function called with each group and its parent wallet.
68
+ * @returns A filtered snapshot.
69
+ */
70
+ filterAllGroups(predicate: (group: AccountTreeSnapshotGroup, wallet: AccountTreeSnapshotWallet) => boolean): AccountTreeSnapshot;
71
+ /**
72
+ * Converts a payload ID (wallet or group) to the corresponding local
73
+ * `AccountTreeController` ID.
74
+ *
75
+ * The map reflects the original export, not the wallets/groups currently
76
+ * retained in this snapshot after filtering.
77
+ *
78
+ * @param payloadId - Stable cross-device wallet or group payload ID.
79
+ * @returns The local controller ID, or `undefined` if not found or no ID map is present.
80
+ */
81
+ toLocalId(payloadId: AccountWalletPayloadId | AccountGroupPayloadId): ReturnType<IdMap['getLocalId']>;
82
+ /**
83
+ * Converts a local `AccountTreeController` ID (wallet or group) to its
84
+ * stable cross-device payload ID.
85
+ *
86
+ * The map reflects the original export, not the wallets/groups currently
87
+ * retained in this snapshot after filtering.
88
+ *
89
+ * @param localId - Local controller wallet or group ID.
90
+ * @returns The payload ID, or `undefined` if not found or no ID map is present.
91
+ */
92
+ toPayloadId(localId: Parameters<IdMap['add']>[0]): ReturnType<IdMap['getPayloadId']>;
93
+ /**
94
+ * Serializes the snapshot to a flat {@link AccountTreePayload} with `version` inlined
95
+ * alongside the wallet entries.
96
+ *
97
+ * Returns the constructor-frozen wallet tree without copying it again.
98
+ *
99
+ * @returns The versioned flat payload.
100
+ */
101
+ serialize(): AccountTreePayload;
102
+ /**
103
+ * Validates a raw value as an {@link AccountTreePayload}, running any
104
+ * necessary version migrations, and returns an immutable snapshot.
105
+ *
106
+ * This is the entry point for untrusted serialized data. Unsupported schema
107
+ * versions and wallet types fail closed with an error instead of returning a
108
+ * partial snapshot.
109
+ *
110
+ * The returned snapshot has no ID map — {@link toLocalId} / {@link toPayloadId}
111
+ * return `undefined`. Pass an {@link IdMap} to the constructor when you need
112
+ * the map.
113
+ *
114
+ * @param raw - Unknown value to parse.
115
+ * @returns A validated snapshot.
116
+ * @throws If `raw` is not a valid payload or its version is unsupported.
117
+ */
118
+ static deserialize(raw: unknown): Promise<AccountTreeSnapshot>;
119
+ }
120
+ //# sourceMappingURL=snapshot.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.mts","sourceRoot":"","sources":["../../src/state/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,qBAAoB;AACzC,OAAO,KAAK,EACV,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EAEtB,sBAAsB,EAEvB,sBAAqB;AAQtB;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,mBAAmB;;IAK9B;;;OAGG;gBACS,OAAO,EAAE,sBAAsB,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK;IAK5D;;;;;;;;;OASG;IACH,aAAa,CACX,SAAS,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,OAAO,GACxD,mBAAmB;IAQtB;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CACV,QAAQ,EAAE,sBAAsB,EAChC,SAAS,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,GACtD,mBAAmB;IAkCtB;;;;;;;;;;;OAWG;IACH,eAAe,CACb,SAAS,EAAE,CACT,KAAK,EAAE,wBAAwB,EAC/B,MAAM,EAAE,yBAAyB,KAC9B,OAAO,GACX,mBAAmB;IA+BtB;;;;;;;;;OASG;IACH,SAAS,CACP,SAAS,EAAE,sBAAsB,GAAG,qBAAqB,GACxD,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAIlC;;;;;;;;;OASG;IACH,WAAW,CACT,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GACnC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAIpC;;;;;;;OAOG;IACH,SAAS,IAAI,kBAAkB;IAO/B;;;;;;;;;;;;;;;OAeG;WACU,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAKrE"}
@@ -0,0 +1,198 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _AccountTreeSnapshot_entries, _AccountTreeSnapshot_idMap;
13
+ import { AccountWalletPayloadType, assertAccountTreePayload, ACCOUNT_TREE_PAYLOAD_CURRENT_VERSION } from "./payload.mjs";
14
+ import { deepFreeze } from "./utils.mjs";
15
+ /**
16
+ * Immutable value object returned by {@link AccountTreeController.exportState}.
17
+ *
18
+ * Construct with {@link AccountTreeController.exportState},
19
+ * {@link AccountTreeSnapshot.deserialize}, or `new AccountTreeSnapshot(...)`
20
+ * for tests and advanced use.
21
+ *
22
+ * Wallet and group entries are deep-cloned and deep-frozen once in the
23
+ * constructor. Filtering predicates receive those read-only views directly;
24
+ * each filter method returns a new snapshot that repeats the process for its
25
+ * result.
26
+ *
27
+ * An optional ID map (local ↔ payload) may be supplied when bridging between
28
+ * internal controller IDs and the stable cross-device IDs in the serialized
29
+ * payload. The map covers the original export and is preserved unchanged
30
+ * through filtering until {@link serialize}. Omit it when deterministic IDs
31
+ * make {@link toLocalId} / {@link toPayloadId} unnecessary.
32
+ */
33
+ export class AccountTreeSnapshot {
34
+ /**
35
+ * @param entries - Wallet entries in the snapshot.
36
+ * @param idMap - Optional local ↔ payload ID map from export.
37
+ */
38
+ constructor(entries, idMap) {
39
+ _AccountTreeSnapshot_entries.set(this, void 0);
40
+ _AccountTreeSnapshot_idMap.set(this, void 0);
41
+ __classPrivateFieldSet(this, _AccountTreeSnapshot_entries, deepFreeze(structuredClone(entries)), "f");
42
+ __classPrivateFieldSet(this, _AccountTreeSnapshot_idMap, idMap, "f");
43
+ }
44
+ /**
45
+ * Returns a new snapshot containing only the wallets for which
46
+ * `predicate` returns `true`.
47
+ *
48
+ * When filtering by wallet ID, compare against stable payload IDs from
49
+ * {@link serialize} or convert local IDs with {@link toPayloadId} first.
50
+ *
51
+ * @param predicate - Function called with each deeply read-only wallet entry.
52
+ * @returns A filtered snapshot.
53
+ */
54
+ filterWallets(predicate) {
55
+ const filteredEntries = __classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f").filter((entry) => predicate(entry));
56
+ return new AccountTreeSnapshot(filteredEntries, __classPrivateFieldGet(this, _AccountTreeSnapshot_idMap, "f"));
57
+ }
58
+ /**
59
+ * Filters groups within one wallet. Other wallets are left unchanged.
60
+ *
61
+ * Throws if `walletId` does not identify a wallet in the snapshot.
62
+ * Removes the wallet if no groups remain after filtering — this prevents a
63
+ * mnemonic wallet with zero selected groups from still transferring its secret.
64
+ *
65
+ * **Mnemonic wallets:** group indices must remain contiguous starting at 0
66
+ * after filtering, because the payload schema enforces this invariant.
67
+ * Predicates that produce gaps (e.g. keeping only index 1, or 0 and 2) will
68
+ * cause {@link AccountTreeSnapshot.deserialize} to reject the payload on the
69
+ * receiving end.
70
+ *
71
+ * @param walletId - Stable payload wallet ID to filter groups within.
72
+ * @param predicate - Function called with each deeply read-only group entry.
73
+ * @returns A filtered snapshot.
74
+ * @throws If `walletId` is not present in the snapshot.
75
+ */
76
+ filterGroups(walletId, predicate) {
77
+ const walletIndex = __classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f").findIndex((entry) => entry.id === walletId);
78
+ if (walletIndex === -1) {
79
+ throw new Error(`Cannot filter groups: wallet "${walletId}" not found in snapshot`);
80
+ }
81
+ const wallet = __classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f")[walletIndex];
82
+ const filteredGroups = wallet.groups.filter((group) => predicate(group));
83
+ const filteredEntries = [...__classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f")];
84
+ if (filteredGroups.length === 0) {
85
+ filteredEntries.splice(walletIndex, 1);
86
+ }
87
+ else if (wallet.type === AccountWalletPayloadType.Mnemonic) {
88
+ filteredEntries[walletIndex] = {
89
+ ...wallet,
90
+ groups: filteredGroups,
91
+ };
92
+ }
93
+ else {
94
+ filteredEntries[walletIndex] = {
95
+ ...wallet,
96
+ groups: filteredGroups,
97
+ };
98
+ }
99
+ return new AccountTreeSnapshot(filteredEntries, __classPrivateFieldGet(this, _AccountTreeSnapshot_idMap, "f"));
100
+ }
101
+ /**
102
+ * Filters groups across every wallet.
103
+ *
104
+ * The parent wallet is provided as context to the predicate. Removes any
105
+ * wallet with no remaining groups after filtering.
106
+ *
107
+ * **Mnemonic wallets:** see {@link filterGroups} for the contiguous-index
108
+ * constraint that applies here as well.
109
+ *
110
+ * @param predicate - Function called with each group and its parent wallet.
111
+ * @returns A filtered snapshot.
112
+ */
113
+ filterAllGroups(predicate) {
114
+ const filteredEntries = [];
115
+ for (const wallet of __classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f")) {
116
+ const filteredGroups = wallet.groups.filter((group) => predicate(group, wallet));
117
+ if (filteredGroups.length === 0) {
118
+ continue;
119
+ }
120
+ if (wallet.type === AccountWalletPayloadType.Mnemonic) {
121
+ filteredEntries.push({
122
+ ...wallet,
123
+ groups: filteredGroups,
124
+ });
125
+ }
126
+ else {
127
+ filteredEntries.push({
128
+ ...wallet,
129
+ groups: filteredGroups,
130
+ });
131
+ }
132
+ }
133
+ return new AccountTreeSnapshot(filteredEntries, __classPrivateFieldGet(this, _AccountTreeSnapshot_idMap, "f"));
134
+ }
135
+ /**
136
+ * Converts a payload ID (wallet or group) to the corresponding local
137
+ * `AccountTreeController` ID.
138
+ *
139
+ * The map reflects the original export, not the wallets/groups currently
140
+ * retained in this snapshot after filtering.
141
+ *
142
+ * @param payloadId - Stable cross-device wallet or group payload ID.
143
+ * @returns The local controller ID, or `undefined` if not found or no ID map is present.
144
+ */
145
+ toLocalId(payloadId) {
146
+ return __classPrivateFieldGet(this, _AccountTreeSnapshot_idMap, "f")?.getLocalId(payloadId);
147
+ }
148
+ /**
149
+ * Converts a local `AccountTreeController` ID (wallet or group) to its
150
+ * stable cross-device payload ID.
151
+ *
152
+ * The map reflects the original export, not the wallets/groups currently
153
+ * retained in this snapshot after filtering.
154
+ *
155
+ * @param localId - Local controller wallet or group ID.
156
+ * @returns The payload ID, or `undefined` if not found or no ID map is present.
157
+ */
158
+ toPayloadId(localId) {
159
+ return __classPrivateFieldGet(this, _AccountTreeSnapshot_idMap, "f")?.getPayloadId(localId);
160
+ }
161
+ /**
162
+ * Serializes the snapshot to a flat {@link AccountTreePayload} with `version` inlined
163
+ * alongside the wallet entries.
164
+ *
165
+ * Returns the constructor-frozen wallet tree without copying it again.
166
+ *
167
+ * @returns The versioned flat payload.
168
+ */
169
+ serialize() {
170
+ return {
171
+ version: ACCOUNT_TREE_PAYLOAD_CURRENT_VERSION,
172
+ wallets: __classPrivateFieldGet(this, _AccountTreeSnapshot_entries, "f"),
173
+ };
174
+ }
175
+ /**
176
+ * Validates a raw value as an {@link AccountTreePayload}, running any
177
+ * necessary version migrations, and returns an immutable snapshot.
178
+ *
179
+ * This is the entry point for untrusted serialized data. Unsupported schema
180
+ * versions and wallet types fail closed with an error instead of returning a
181
+ * partial snapshot.
182
+ *
183
+ * The returned snapshot has no ID map — {@link toLocalId} / {@link toPayloadId}
184
+ * return `undefined`. Pass an {@link IdMap} to the constructor when you need
185
+ * the map.
186
+ *
187
+ * @param raw - Unknown value to parse.
188
+ * @returns A validated snapshot.
189
+ * @throws If `raw` is not a valid payload or its version is unsupported.
190
+ */
191
+ static async deserialize(raw) {
192
+ // TODO: Use migration framework here.
193
+ assertAccountTreePayload(raw);
194
+ return new AccountTreeSnapshot(raw.wallets);
195
+ }
196
+ }
197
+ _AccountTreeSnapshot_entries = new WeakMap(), _AccountTreeSnapshot_idMap = new WeakMap();
198
+ //# sourceMappingURL=snapshot.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.mjs","sourceRoot":"","sources":["../../src/state/snapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdMap } from './id-map.js';\nimport type {\n AccountGroupPayloadId,\n AccountTreePayload,\n AccountTreeSnapshotGroup,\n AccountTreeSnapshotWallet,\n AccountTreeWalletEntry,\n AccountWalletMnemonicGroupEntry,\n AccountWalletPayloadId,\n AccountWalletPrivateKeyGroupEntry,\n} from './payload.js';\nimport {\n AccountWalletPayloadType,\n assertAccountTreePayload,\n ACCOUNT_TREE_PAYLOAD_CURRENT_VERSION,\n} from './payload.js';\nimport { deepFreeze } from './utils.js';\n\n/**\n * Immutable value object returned by {@link AccountTreeController.exportState}.\n *\n * Construct with {@link AccountTreeController.exportState},\n * {@link AccountTreeSnapshot.deserialize}, or `new AccountTreeSnapshot(...)`\n * for tests and advanced use.\n *\n * Wallet and group entries are deep-cloned and deep-frozen once in the\n * constructor. Filtering predicates receive those read-only views directly;\n * each filter method returns a new snapshot that repeats the process for its\n * result.\n *\n * An optional ID map (local ↔ payload) may be supplied when bridging between\n * internal controller IDs and the stable cross-device IDs in the serialized\n * payload. The map covers the original export and is preserved unchanged\n * through filtering until {@link serialize}. Omit it when deterministic IDs\n * make {@link toLocalId} / {@link toPayloadId} unnecessary.\n */\nexport class AccountTreeSnapshot {\n readonly #entries: AccountTreeWalletEntry[];\n\n readonly #idMap: IdMap | undefined;\n\n /**\n * @param entries - Wallet entries in the snapshot.\n * @param idMap - Optional local ↔ payload ID map from export.\n */\n constructor(entries: AccountTreeWalletEntry[], idMap?: IdMap) {\n this.#entries = deepFreeze(structuredClone(entries));\n this.#idMap = idMap;\n }\n\n /**\n * Returns a new snapshot containing only the wallets for which\n * `predicate` returns `true`.\n *\n * When filtering by wallet ID, compare against stable payload IDs from\n * {@link serialize} or convert local IDs with {@link toPayloadId} first.\n *\n * @param predicate - Function called with each deeply read-only wallet entry.\n * @returns A filtered snapshot.\n */\n filterWallets(\n predicate: (wallet: AccountTreeSnapshotWallet) => boolean,\n ): AccountTreeSnapshot {\n const filteredEntries = this.#entries.filter((entry) =>\n predicate(entry as AccountTreeSnapshotWallet),\n );\n\n return new AccountTreeSnapshot(filteredEntries, this.#idMap);\n }\n\n /**\n * Filters groups within one wallet. Other wallets are left unchanged.\n *\n * Throws if `walletId` does not identify a wallet in the snapshot.\n * Removes the wallet if no groups remain after filtering — this prevents a\n * mnemonic wallet with zero selected groups from still transferring its secret.\n *\n * **Mnemonic wallets:** group indices must remain contiguous starting at 0\n * after filtering, because the payload schema enforces this invariant.\n * Predicates that produce gaps (e.g. keeping only index 1, or 0 and 2) will\n * cause {@link AccountTreeSnapshot.deserialize} to reject the payload on the\n * receiving end.\n *\n * @param walletId - Stable payload wallet ID to filter groups within.\n * @param predicate - Function called with each deeply read-only group entry.\n * @returns A filtered snapshot.\n * @throws If `walletId` is not present in the snapshot.\n */\n filterGroups(\n walletId: AccountWalletPayloadId,\n predicate: (group: AccountTreeSnapshotGroup) => boolean,\n ): AccountTreeSnapshot {\n const walletIndex = this.#entries.findIndex(\n (entry) => entry.id === walletId,\n );\n if (walletIndex === -1) {\n throw new Error(\n `Cannot filter groups: wallet \"${walletId}\" not found in snapshot`,\n );\n }\n\n const wallet = this.#entries[walletIndex];\n\n const filteredGroups = wallet.groups.filter((group) =>\n predicate(group as AccountTreeSnapshotGroup),\n );\n\n const filteredEntries = [...this.#entries];\n if (filteredGroups.length === 0) {\n filteredEntries.splice(walletIndex, 1);\n } else if (wallet.type === AccountWalletPayloadType.Mnemonic) {\n filteredEntries[walletIndex] = {\n ...wallet,\n groups: filteredGroups as AccountWalletMnemonicGroupEntry[],\n };\n } else {\n filteredEntries[walletIndex] = {\n ...wallet,\n groups: filteredGroups as AccountWalletPrivateKeyGroupEntry[],\n };\n }\n\n return new AccountTreeSnapshot(filteredEntries, this.#idMap);\n }\n\n /**\n * Filters groups across every wallet.\n *\n * The parent wallet is provided as context to the predicate. Removes any\n * wallet with no remaining groups after filtering.\n *\n * **Mnemonic wallets:** see {@link filterGroups} for the contiguous-index\n * constraint that applies here as well.\n *\n * @param predicate - Function called with each group and its parent wallet.\n * @returns A filtered snapshot.\n */\n filterAllGroups(\n predicate: (\n group: AccountTreeSnapshotGroup,\n wallet: AccountTreeSnapshotWallet,\n ) => boolean,\n ): AccountTreeSnapshot {\n const filteredEntries: AccountTreeWalletEntry[] = [];\n\n for (const wallet of this.#entries) {\n const filteredGroups = wallet.groups.filter((group) =>\n predicate(\n group as AccountTreeSnapshotGroup,\n wallet as AccountTreeSnapshotWallet,\n ),\n );\n\n if (filteredGroups.length === 0) {\n continue;\n }\n\n if (wallet.type === AccountWalletPayloadType.Mnemonic) {\n filteredEntries.push({\n ...wallet,\n groups: filteredGroups as AccountWalletMnemonicGroupEntry[],\n });\n } else {\n filteredEntries.push({\n ...wallet,\n groups: filteredGroups as AccountWalletPrivateKeyGroupEntry[],\n });\n }\n }\n\n return new AccountTreeSnapshot(filteredEntries, this.#idMap);\n }\n\n /**\n * Converts a payload ID (wallet or group) to the corresponding local\n * `AccountTreeController` ID.\n *\n * The map reflects the original export, not the wallets/groups currently\n * retained in this snapshot after filtering.\n *\n * @param payloadId - Stable cross-device wallet or group payload ID.\n * @returns The local controller ID, or `undefined` if not found or no ID map is present.\n */\n toLocalId(\n payloadId: AccountWalletPayloadId | AccountGroupPayloadId,\n ): ReturnType<IdMap['getLocalId']> {\n return this.#idMap?.getLocalId(payloadId);\n }\n\n /**\n * Converts a local `AccountTreeController` ID (wallet or group) to its\n * stable cross-device payload ID.\n *\n * The map reflects the original export, not the wallets/groups currently\n * retained in this snapshot after filtering.\n *\n * @param localId - Local controller wallet or group ID.\n * @returns The payload ID, or `undefined` if not found or no ID map is present.\n */\n toPayloadId(\n localId: Parameters<IdMap['add']>[0],\n ): ReturnType<IdMap['getPayloadId']> {\n return this.#idMap?.getPayloadId(localId);\n }\n\n /**\n * Serializes the snapshot to a flat {@link AccountTreePayload} with `version` inlined\n * alongside the wallet entries.\n *\n * Returns the constructor-frozen wallet tree without copying it again.\n *\n * @returns The versioned flat payload.\n */\n serialize(): AccountTreePayload {\n return {\n version: ACCOUNT_TREE_PAYLOAD_CURRENT_VERSION,\n wallets: this.#entries,\n };\n }\n\n /**\n * Validates a raw value as an {@link AccountTreePayload}, running any\n * necessary version migrations, and returns an immutable snapshot.\n *\n * This is the entry point for untrusted serialized data. Unsupported schema\n * versions and wallet types fail closed with an error instead of returning a\n * partial snapshot.\n *\n * The returned snapshot has no ID map — {@link toLocalId} / {@link toPayloadId}\n * return `undefined`. Pass an {@link IdMap} to the constructor when you need\n * the map.\n *\n * @param raw - Unknown value to parse.\n * @returns A validated snapshot.\n * @throws If `raw` is not a valid payload or its version is unsupported.\n */\n static async deserialize(raw: unknown): Promise<AccountTreeSnapshot> {\n // TODO: Use migration framework here.\n assertAccountTreePayload(raw);\n return new AccountTreeSnapshot(raw.wallets);\n }\n}\n"]}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatValidationErrorMessages = exports.deepFreeze = exports.decodeBytes = exports.encodeBytes = exports.BytesStruct = void 0;
4
+ const superstruct_1 = require("@metamask/superstruct");
5
+ /**
6
+ * Superstruct struct that validates an {@link EncodedBytes} value.
7
+ */
8
+ exports.BytesStruct = (0, superstruct_1.refine)((0, superstruct_1.array)((0, superstruct_1.integer)()), 'bytes', (value) => {
9
+ const invalid = value.find((b) => b < 0 || b > 255);
10
+ return invalid === undefined
11
+ ? true
12
+ : `each byte must be in [0, 255]; got ${invalid}`;
13
+ });
14
+ /**
15
+ * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.
16
+ *
17
+ * @param bytes - The bytes to encode.
18
+ * @returns An array of integers in [0, 255].
19
+ */
20
+ function encodeBytes(bytes) {
21
+ return Array.from(bytes);
22
+ }
23
+ exports.encodeBytes = encodeBytes;
24
+ /**
25
+ * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.
26
+ * The caller is responsible for zeroing the result when the data is no longer needed.
27
+ *
28
+ * @param encoded - The encoded byte array.
29
+ * @returns The decoded `Uint8Array`.
30
+ */
31
+ function decodeBytes(encoded) {
32
+ return new Uint8Array(encoded);
33
+ }
34
+ exports.decodeBytes = decodeBytes;
35
+ /**
36
+ * Recursively freezes a value and its nested properties.
37
+ *
38
+ * @param value - Value to freeze.
39
+ * @returns The frozen value.
40
+ */
41
+ function deepFreeze(value) {
42
+ if (value === null || typeof value !== 'object') {
43
+ return value;
44
+ }
45
+ Object.freeze(value);
46
+ for (const nested of Object.values(value)) {
47
+ deepFreeze(nested);
48
+ }
49
+ return value;
50
+ }
51
+ exports.deepFreeze = deepFreeze;
52
+ /**
53
+ * Formats Superstruct validation failures into a single error message string.
54
+ *
55
+ * @param error - The StructError thrown during validation.
56
+ * @returns A comma-separated list of `[path] expected: <type>` entries.
57
+ */
58
+ function formatValidationErrorMessages(error) {
59
+ return error
60
+ .failures()
61
+ .map(({ path, type, refinement }) => {
62
+ const location = path.length > 0 ? path.join('.') : '<root>';
63
+ return `[${location}] expected: ${refinement ?? type}`;
64
+ })
65
+ .join(', ');
66
+ }
67
+ exports.formatValidationErrorMessages = formatValidationErrorMessages;
68
+ //# sourceMappingURL=utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":";;;AACA,uDAA4E;AAQ5E;;GAEG;AACU,QAAA,WAAW,GAAyB,IAAA,oBAAM,EACrD,IAAA,mBAAK,EAAC,IAAA,qBAAO,GAAE,CAAC,EAChB,OAAO,EACP,CAAC,KAAK,EAAE,EAAE;IACR,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IACpD,OAAO,OAAO,KAAK,SAAS;QAC1B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,sCAAsC,OAAO,EAAE,CAAC;AACtD,CAAC,CACF,CAAC;AAEF;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,KAAiB;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAFD,kCAEC;AAED;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,OAAqB;IAC/C,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAFD,kCAEC;AAaD;;;;;GAKG;AACH,SAAgB,UAAU,CAAQ,KAAY;IAC5C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAErB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,UAAU,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAZD,gCAYC;AAED;;;;;GAKG;AACH,SAAgB,6BAA6B,CAAC,KAAkB;IAC9D,OAAO,KAAK;SACT,QAAQ,EAAE;SACV,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7D,OAAO,IAAI,QAAQ,eAAe,UAAU,IAAI,IAAI,EAAE,CAAC;IACzD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AARD,sEAQC","sourcesContent":["import type { Struct } from '@metamask/superstruct';\nimport { array, integer, refine, StructError } from '@metamask/superstruct';\n\n/**\n * A JSON-compatible representation of a `Uint8Array` as an array of integers\n * in [0, 255]. Use {@link encodeBytes} and {@link decodeBytes} to convert.\n */\nexport type EncodedBytes = number[];\n\n/**\n * Superstruct struct that validates an {@link EncodedBytes} value.\n */\nexport const BytesStruct: Struct<EncodedBytes> = refine(\n array(integer()),\n 'bytes',\n (value) => {\n const invalid = value.find((b) => b < 0 || b > 255);\n return invalid === undefined\n ? true\n : `each byte must be in [0, 255]; got ${invalid}`;\n },\n);\n\n/**\n * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.\n *\n * @param bytes - The bytes to encode.\n * @returns An array of integers in [0, 255].\n */\nexport function encodeBytes(bytes: Uint8Array): EncodedBytes {\n return Array.from(bytes);\n}\n\n/**\n * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.\n * The caller is responsible for zeroing the result when the data is no longer needed.\n *\n * @param encoded - The encoded byte array.\n * @returns The decoded `Uint8Array`.\n */\nexport function decodeBytes(encoded: EncodedBytes): Uint8Array {\n return new Uint8Array(encoded);\n}\n\n/**\n * Recursively readonly view of `Value` used by snapshot filtering predicate types.\n *\n * @typeParam T - The mutable source type to expose as deeply read-only.\n */\nexport type DeepReadonly<Value> = Value extends readonly (infer Item)[]\n ? readonly DeepReadonly<Item>[]\n : Value extends object\n ? { readonly [Key in keyof Value]: DeepReadonly<Value[Key]> }\n : Value;\n\n/**\n * Recursively freezes a value and its nested properties.\n *\n * @param value - Value to freeze.\n * @returns The frozen value.\n */\nexport function deepFreeze<Value>(value: Value): Value {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n\n Object.freeze(value);\n\n for (const nested of Object.values(value)) {\n deepFreeze(nested);\n }\n\n return value;\n}\n\n/**\n * Formats Superstruct validation failures into a single error message string.\n *\n * @param error - The StructError thrown during validation.\n * @returns A comma-separated list of `[path] expected: <type>` entries.\n */\nexport function formatValidationErrorMessages(error: StructError): string {\n return error\n .failures()\n .map(({ path, type, refinement }) => {\n const location = path.length > 0 ? path.join('.') : '<root>';\n return `[${location}] expected: ${refinement ?? type}`;\n })\n .join(', ');\n}\n"]}
@@ -0,0 +1,49 @@
1
+ import type { Struct } from "@metamask/superstruct";
2
+ import { StructError } from "@metamask/superstruct";
3
+ /**
4
+ * A JSON-compatible representation of a `Uint8Array` as an array of integers
5
+ * in [0, 255]. Use {@link encodeBytes} and {@link decodeBytes} to convert.
6
+ */
7
+ export type EncodedBytes = number[];
8
+ /**
9
+ * Superstruct struct that validates an {@link EncodedBytes} value.
10
+ */
11
+ export declare const BytesStruct: Struct<EncodedBytes>;
12
+ /**
13
+ * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.
14
+ *
15
+ * @param bytes - The bytes to encode.
16
+ * @returns An array of integers in [0, 255].
17
+ */
18
+ export declare function encodeBytes(bytes: Uint8Array): EncodedBytes;
19
+ /**
20
+ * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.
21
+ * The caller is responsible for zeroing the result when the data is no longer needed.
22
+ *
23
+ * @param encoded - The encoded byte array.
24
+ * @returns The decoded `Uint8Array`.
25
+ */
26
+ export declare function decodeBytes(encoded: EncodedBytes): Uint8Array;
27
+ /**
28
+ * Recursively readonly view of `Value` used by snapshot filtering predicate types.
29
+ *
30
+ * @typeParam T - The mutable source type to expose as deeply read-only.
31
+ */
32
+ export type DeepReadonly<Value> = Value extends readonly (infer Item)[] ? readonly DeepReadonly<Item>[] : Value extends object ? {
33
+ readonly [Key in keyof Value]: DeepReadonly<Value[Key]>;
34
+ } : Value;
35
+ /**
36
+ * Recursively freezes a value and its nested properties.
37
+ *
38
+ * @param value - Value to freeze.
39
+ * @returns The frozen value.
40
+ */
41
+ export declare function deepFreeze<Value>(value: Value): Value;
42
+ /**
43
+ * Formats Superstruct validation failures into a single error message string.
44
+ *
45
+ * @param error - The StructError thrown during validation.
46
+ * @returns A comma-separated list of `[path] expected: <type>` entries.
47
+ */
48
+ export declare function formatValidationErrorMessages(error: StructError): string;
49
+ //# sourceMappingURL=utils.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,8BAA8B;AACpD,OAAO,EAA0B,WAAW,EAAE,8BAA8B;AAE5E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC;AAEpC;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,CAS5C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAE7D;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI,KAAK,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,GACnE,SAAS,YAAY,CAAC,IAAI,CAAC,EAAE,GAC7B,KAAK,SAAS,MAAM,GAClB;IAAE,QAAQ,EAAE,GAAG,IAAI,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;CAAE,GAC3D,KAAK,CAAC;AAEZ;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAYrD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAQxE"}
@@ -0,0 +1,49 @@
1
+ import type { Struct } from "@metamask/superstruct";
2
+ import { StructError } from "@metamask/superstruct";
3
+ /**
4
+ * A JSON-compatible representation of a `Uint8Array` as an array of integers
5
+ * in [0, 255]. Use {@link encodeBytes} and {@link decodeBytes} to convert.
6
+ */
7
+ export type EncodedBytes = number[];
8
+ /**
9
+ * Superstruct struct that validates an {@link EncodedBytes} value.
10
+ */
11
+ export declare const BytesStruct: Struct<EncodedBytes>;
12
+ /**
13
+ * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.
14
+ *
15
+ * @param bytes - The bytes to encode.
16
+ * @returns An array of integers in [0, 255].
17
+ */
18
+ export declare function encodeBytes(bytes: Uint8Array): EncodedBytes;
19
+ /**
20
+ * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.
21
+ * The caller is responsible for zeroing the result when the data is no longer needed.
22
+ *
23
+ * @param encoded - The encoded byte array.
24
+ * @returns The decoded `Uint8Array`.
25
+ */
26
+ export declare function decodeBytes(encoded: EncodedBytes): Uint8Array;
27
+ /**
28
+ * Recursively readonly view of `Value` used by snapshot filtering predicate types.
29
+ *
30
+ * @typeParam T - The mutable source type to expose as deeply read-only.
31
+ */
32
+ export type DeepReadonly<Value> = Value extends readonly (infer Item)[] ? readonly DeepReadonly<Item>[] : Value extends object ? {
33
+ readonly [Key in keyof Value]: DeepReadonly<Value[Key]>;
34
+ } : Value;
35
+ /**
36
+ * Recursively freezes a value and its nested properties.
37
+ *
38
+ * @param value - Value to freeze.
39
+ * @returns The frozen value.
40
+ */
41
+ export declare function deepFreeze<Value>(value: Value): Value;
42
+ /**
43
+ * Formats Superstruct validation failures into a single error message string.
44
+ *
45
+ * @param error - The StructError thrown during validation.
46
+ * @returns A comma-separated list of `[path] expected: <type>` entries.
47
+ */
48
+ export declare function formatValidationErrorMessages(error: StructError): string;
49
+ //# sourceMappingURL=utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,8BAA8B;AACpD,OAAO,EAA0B,WAAW,EAAE,8BAA8B;AAE5E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC;AAEpC;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,CAS5C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAE7D;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI,KAAK,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,GACnE,SAAS,YAAY,CAAC,IAAI,CAAC,EAAE,GAC7B,KAAK,SAAS,MAAM,GAClB;IAAE,QAAQ,EAAE,GAAG,IAAI,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;CAAE,GAC3D,KAAK,CAAC;AAEZ;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAYrD;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAQxE"}
@@ -0,0 +1,61 @@
1
+ import { array, integer, refine, StructError } from "@metamask/superstruct";
2
+ /**
3
+ * Superstruct struct that validates an {@link EncodedBytes} value.
4
+ */
5
+ export const BytesStruct = refine(array(integer()), 'bytes', (value) => {
6
+ const invalid = value.find((b) => b < 0 || b > 255);
7
+ return invalid === undefined
8
+ ? true
9
+ : `each byte must be in [0, 255]; got ${invalid}`;
10
+ });
11
+ /**
12
+ * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.
13
+ *
14
+ * @param bytes - The bytes to encode.
15
+ * @returns An array of integers in [0, 255].
16
+ */
17
+ export function encodeBytes(bytes) {
18
+ return Array.from(bytes);
19
+ }
20
+ /**
21
+ * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.
22
+ * The caller is responsible for zeroing the result when the data is no longer needed.
23
+ *
24
+ * @param encoded - The encoded byte array.
25
+ * @returns The decoded `Uint8Array`.
26
+ */
27
+ export function decodeBytes(encoded) {
28
+ return new Uint8Array(encoded);
29
+ }
30
+ /**
31
+ * Recursively freezes a value and its nested properties.
32
+ *
33
+ * @param value - Value to freeze.
34
+ * @returns The frozen value.
35
+ */
36
+ export function deepFreeze(value) {
37
+ if (value === null || typeof value !== 'object') {
38
+ return value;
39
+ }
40
+ Object.freeze(value);
41
+ for (const nested of Object.values(value)) {
42
+ deepFreeze(nested);
43
+ }
44
+ return value;
45
+ }
46
+ /**
47
+ * Formats Superstruct validation failures into a single error message string.
48
+ *
49
+ * @param error - The StructError thrown during validation.
50
+ * @returns A comma-separated list of `[path] expected: <type>` entries.
51
+ */
52
+ export function formatValidationErrorMessages(error) {
53
+ return error
54
+ .failures()
55
+ .map(({ path, type, refinement }) => {
56
+ const location = path.length > 0 ? path.join('.') : '<root>';
57
+ return `[${location}] expected: ${refinement ?? type}`;
58
+ })
59
+ .join(', ');
60
+ }
61
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,8BAA8B;AAQ5E;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CACrD,KAAK,CAAC,OAAO,EAAE,CAAC,EAChB,OAAO,EACP,CAAC,KAAK,EAAE,EAAE;IACR,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IACpD,OAAO,OAAO,KAAK,SAAS;QAC1B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,sCAAsC,OAAO,EAAE,CAAC;AACtD,CAAC,CACF,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAiB;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAqB;IAC/C,OAAO,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAaD;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAQ,KAAY;IAC5C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAErB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,UAAU,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,KAAkB;IAC9D,OAAO,KAAK;SACT,QAAQ,EAAE;SACV,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7D,OAAO,IAAI,QAAQ,eAAe,UAAU,IAAI,IAAI,EAAE,CAAC;IACzD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC","sourcesContent":["import type { Struct } from '@metamask/superstruct';\nimport { array, integer, refine, StructError } from '@metamask/superstruct';\n\n/**\n * A JSON-compatible representation of a `Uint8Array` as an array of integers\n * in [0, 255]. Use {@link encodeBytes} and {@link decodeBytes} to convert.\n */\nexport type EncodedBytes = number[];\n\n/**\n * Superstruct struct that validates an {@link EncodedBytes} value.\n */\nexport const BytesStruct: Struct<EncodedBytes> = refine(\n array(integer()),\n 'bytes',\n (value) => {\n const invalid = value.find((b) => b < 0 || b > 255);\n return invalid === undefined\n ? true\n : `each byte must be in [0, 255]; got ${invalid}`;\n },\n);\n\n/**\n * Encodes a `Uint8Array` as a JSON-compatible {@link EncodedBytes}.\n *\n * @param bytes - The bytes to encode.\n * @returns An array of integers in [0, 255].\n */\nexport function encodeBytes(bytes: Uint8Array): EncodedBytes {\n return Array.from(bytes);\n}\n\n/**\n * Decodes an {@link EncodedBytes} produced by {@link encodeBytes} back into a `Uint8Array`.\n * The caller is responsible for zeroing the result when the data is no longer needed.\n *\n * @param encoded - The encoded byte array.\n * @returns The decoded `Uint8Array`.\n */\nexport function decodeBytes(encoded: EncodedBytes): Uint8Array {\n return new Uint8Array(encoded);\n}\n\n/**\n * Recursively readonly view of `Value` used by snapshot filtering predicate types.\n *\n * @typeParam T - The mutable source type to expose as deeply read-only.\n */\nexport type DeepReadonly<Value> = Value extends readonly (infer Item)[]\n ? readonly DeepReadonly<Item>[]\n : Value extends object\n ? { readonly [Key in keyof Value]: DeepReadonly<Value[Key]> }\n : Value;\n\n/**\n * Recursively freezes a value and its nested properties.\n *\n * @param value - Value to freeze.\n * @returns The frozen value.\n */\nexport function deepFreeze<Value>(value: Value): Value {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n\n Object.freeze(value);\n\n for (const nested of Object.values(value)) {\n deepFreeze(nested);\n }\n\n return value;\n}\n\n/**\n * Formats Superstruct validation failures into a single error message string.\n *\n * @param error - The StructError thrown during validation.\n * @returns A comma-separated list of `[path] expected: <type>` entries.\n */\nexport function formatValidationErrorMessages(error: StructError): string {\n return error\n .failures()\n .map(({ path, type, refinement }) => {\n const location = path.length > 0 ? path.join('.') : '<root>';\n return `[${location}] expected: ${refinement ?? type}`;\n })\n .join(', ');\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { KeyringControllerGetStateAction } from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n MultichainAccountServiceCreateMultichainAccountGroupAction,\n MultichainAccountServiceCreateMultichainAccountGroupsAction,\n} from '@metamask/multichain-account-service';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { SnapControllerGetSnapAction } from '@metamask/snaps-controllers';\n\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types.js';\nimport type { controllerName } from './AccountTreeController.js';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics/index.js';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group.js';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet.js';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n };\n selectedAccountGroup: AccountGroupId | '';\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnapAction\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction\n | MultichainAccountServiceCreateMultichainAccountGroupsAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupCreated` event.\n * This event is emitted when a new account group is added to the tree\n * after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupCreatedEvent = {\n type: `${typeof controllerName}:accountGroupCreated`;\n payload: [AccountGroupObject];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupUpdated` event.\n * This event is emitted when an existing account group's metadata or\n * membership changes after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupUpdatedEvent = {\n type: `${typeof controllerName}:accountGroupUpdated`;\n payload: [AccountGroupObject];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupRemoved` event.\n * This event is emitted when an account group is pruned from the tree\n * (its last account was removed) after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupRemovedEvent = {\n type: `${typeof controllerName}:accountGroupRemoved`;\n payload: [AccountGroupId];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AccountGroupId, AccountWalletId } from '@metamask/account-api';\nimport type {\n AccountId,\n AccountsControllerAccountsAddedEvent,\n AccountsControllerAccountsRemovedEvent,\n AccountsControllerGetAccountAction,\n AccountsControllerGetSelectedMultichainAccountAction,\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerSelectedAccountChangeEvent,\n AccountsControllerSetSelectedAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerWithControllerAction,\n KeyringControllerWithKeyringV2Action,\n KeyringControllerWithKeyringV2UnsafeAction,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n MultichainAccountServiceCreateMultichainAccountGroupAction,\n MultichainAccountServiceCreateMultichainAccountGroupsAction,\n MultichainAccountServiceCreateMultichainAccountWalletAction,\n} from '@metamask/multichain-account-service';\nimport type { MultichainAccountServiceWalletStatusChangeEvent } from '@metamask/multichain-account-service';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport type { SnapControllerGetSnapAction } from '@metamask/snaps-controllers';\n\nimport type { AccountTreeControllerMethodActions } from './AccountTreeController-method-action-types.js';\nimport type { controllerName } from './AccountTreeController.js';\nimport type {\n BackupAndSyncAnalyticsEventPayload,\n BackupAndSyncEmitAnalyticsEventParams,\n} from './backup-and-sync/analytics/index.js';\nimport type {\n AccountGroupObject,\n AccountTreeGroupPersistedMetadata,\n} from './group.js';\nimport type {\n AccountWalletObject,\n AccountTreeWalletPersistedMetadata,\n} from './wallet.js';\n\n// Backward compatibility aliases using indexed access types\n/**\n * @deprecated Use AccountTreeGroupMetadata for tree objects or AccountTreeGroupPersistedMetadata for controller state\n */\nexport type AccountGroupMetadata = AccountGroupObject['metadata'];\n\n/**\n * @deprecated Use AccountTreeWalletMetadata for tree objects or AccountTreeWalletPersistedMetadata for controller state\n */\nexport type AccountWalletMetadata = AccountWalletObject['metadata'];\n\nexport type AccountTreeControllerState = {\n accountTree: {\n wallets: {\n // Wallets:\n [walletId: AccountWalletId]: AccountWalletObject;\n };\n };\n selectedAccountGroup: AccountGroupId | '';\n isAccountTreeSyncingInProgress: boolean;\n hasAccountTreeSyncingSyncedAtLeastOnce: boolean;\n /** Persistent metadata for account groups (names, pinning, hiding, sync timestamps) */\n accountGroupsMetadata: Record<\n AccountGroupId,\n AccountTreeGroupPersistedMetadata\n >;\n /** Persistent metadata for account wallets (names, sync timestamps) */\n accountWalletsMetadata: Record<\n AccountWalletId,\n AccountTreeWalletPersistedMetadata\n >;\n};\n\nexport type AccountTreeControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\nexport type AllowedActions =\n | AccountsControllerGetAccountAction\n | AccountsControllerGetSelectedMultichainAccountAction\n | AccountsControllerListMultichainAccountsAction\n | AccountsControllerSetSelectedAccountAction\n | KeyringControllerGetStateAction\n | SnapControllerGetSnapAction\n | UserStorageController.UserStorageControllerGetStateAction\n | UserStorageController.UserStorageControllerPerformGetStorageAction\n | UserStorageController.UserStorageControllerPerformGetStorageAllFeatureEntriesAction\n | UserStorageController.UserStorageControllerPerformSetStorageAction\n | UserStorageController.UserStorageControllerPerformBatchSetStorageAction\n | AuthenticationController.AuthenticationControllerGetSessionProfileAction\n | MultichainAccountServiceCreateMultichainAccountGroupAction\n | MultichainAccountServiceCreateMultichainAccountGroupsAction\n | MultichainAccountServiceCreateMultichainAccountWalletAction\n | KeyringControllerWithControllerAction\n | KeyringControllerWithKeyringV2Action\n | KeyringControllerWithKeyringV2UnsafeAction;\n\nexport type AccountTreeControllerActions =\n | AccountTreeControllerGetStateAction\n | AccountTreeControllerMethodActions;\n\nexport type AccountTreeControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AccountTreeControllerState\n>;\n\n/**\n * Represents the `AccountTreeController:accountTreeChange` event.\n * This event is emitted when nodes (wallets, groups, or accounts) are added or removed.\n */\nexport type AccountTreeControllerAccountTreeChangeEvent = {\n type: `${typeof controllerName}:accountTreeChange`;\n payload: [AccountTreeControllerState['accountTree']];\n};\n\n/**\n * Represents the `AccountTreeController:selectedAccountGroupChange` event.\n * This event is emitted when the selected account group changes.\n */\nexport type AccountTreeControllerSelectedAccountGroupChangeEvent = {\n type: `${typeof controllerName}:selectedAccountGroupChange`;\n payload: [AccountGroupId | '', AccountGroupId | ''];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupCreated` event.\n * This event is emitted when a new account group is added to the tree\n * after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupCreatedEvent = {\n type: `${typeof controllerName}:accountGroupCreated`;\n payload: [AccountGroupObject];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupUpdated` event.\n * This event is emitted when an existing account group's metadata or\n * membership changes after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupUpdatedEvent = {\n type: `${typeof controllerName}:accountGroupUpdated`;\n payload: [AccountGroupObject];\n};\n\n/**\n * Represents the `AccountTreeController:accountGroupRemoved` event.\n * This event is emitted when an account group is pruned from the tree\n * (its last account was removed) after the controller has been initialized.\n */\nexport type AccountTreeControllerAccountGroupRemovedEvent = {\n type: `${typeof controllerName}:accountGroupRemoved`;\n payload: [AccountGroupId];\n};\n\nexport type AllowedEvents =\n | AccountsControllerAccountsAddedEvent\n | AccountsControllerAccountsRemovedEvent\n | AccountsControllerSelectedAccountChangeEvent\n | UserStorageController.UserStorageControllerStateChangeEvent\n | MultichainAccountServiceWalletStatusChangeEvent;\n\nexport type AccountTreeControllerEvents =\n | AccountTreeControllerStateChangeEvent\n | AccountTreeControllerAccountTreeChangeEvent\n | AccountTreeControllerSelectedAccountGroupChangeEvent\n | AccountTreeControllerAccountGroupCreatedEvent\n | AccountTreeControllerAccountGroupUpdatedEvent\n | AccountTreeControllerAccountGroupRemovedEvent;\n\nexport type AccountTreeControllerMessenger = Messenger<\n typeof controllerName,\n AccountTreeControllerActions | AllowedActions,\n AccountTreeControllerEvents | AllowedEvents\n>;\n\nexport type AccountTreeControllerConfig = {\n trace?: TraceCallback;\n backupAndSync?: {\n onBackupAndSyncEvent?: (event: BackupAndSyncAnalyticsEventPayload) => void;\n };\n accountOrderCallbacks?: {\n isHiddenAccount?: (accountId: AccountId) => boolean;\n isPinnedAccount?: (accountId: AccountId) => boolean;\n };\n};\n\nexport type AccountTreeControllerInternalBackupAndSyncConfig = {\n emitAnalyticsEventFn: (event: BackupAndSyncEmitAnalyticsEventParams) => void;\n};\n"]}