@metamask-previews/profile-sync-controller 3.1.1-preview-0f92cfaa → 3.2.0-preview-4e54ae1

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 (94) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/controllers/user-storage/UserStorageController.cjs +39 -218
  3. package/dist/controllers/user-storage/UserStorageController.cjs.map +1 -1
  4. package/dist/controllers/user-storage/UserStorageController.d.cts +6 -1
  5. package/dist/controllers/user-storage/UserStorageController.d.cts.map +1 -1
  6. package/dist/controllers/user-storage/UserStorageController.d.mts +6 -1
  7. package/dist/controllers/user-storage/UserStorageController.d.mts.map +1 -1
  8. package/dist/controllers/user-storage/UserStorageController.mjs +36 -215
  9. package/dist/controllers/user-storage/UserStorageController.mjs.map +1 -1
  10. package/dist/controllers/user-storage/__fixtures__/test-utils.cjs +45 -1
  11. package/dist/controllers/user-storage/__fixtures__/test-utils.cjs.map +1 -1
  12. package/dist/controllers/user-storage/__fixtures__/test-utils.d.cts +21 -0
  13. package/dist/controllers/user-storage/__fixtures__/test-utils.d.cts.map +1 -1
  14. package/dist/controllers/user-storage/__fixtures__/test-utils.d.mts +21 -0
  15. package/dist/controllers/user-storage/__fixtures__/test-utils.d.mts.map +1 -1
  16. package/dist/controllers/user-storage/__fixtures__/test-utils.mjs +38 -0
  17. package/dist/controllers/user-storage/__fixtures__/test-utils.mjs.map +1 -1
  18. package/dist/controllers/user-storage/{__fixtures__ → account-syncing/__fixtures__}/mockAccounts.cjs +3 -3
  19. package/dist/controllers/user-storage/account-syncing/__fixtures__/mockAccounts.cjs.map +1 -0
  20. package/dist/controllers/user-storage/{__fixtures__ → account-syncing/__fixtures__}/mockAccounts.d.cts +6 -6
  21. package/dist/controllers/user-storage/account-syncing/__fixtures__/mockAccounts.d.cts.map +1 -0
  22. package/dist/controllers/user-storage/{__fixtures__ → account-syncing/__fixtures__}/mockAccounts.d.mts +6 -6
  23. package/dist/controllers/user-storage/account-syncing/__fixtures__/mockAccounts.d.mts.map +1 -0
  24. package/dist/controllers/user-storage/{__fixtures__ → account-syncing/__fixtures__}/mockAccounts.mjs +2 -2
  25. package/dist/controllers/user-storage/account-syncing/__fixtures__/mockAccounts.mjs.map +1 -0
  26. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.cjs +50 -0
  27. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.cjs.map +1 -0
  28. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.d.cts +85 -0
  29. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.d.cts.map +1 -0
  30. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.d.mts +85 -0
  31. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.d.mts.map +1 -0
  32. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.mjs +44 -0
  33. package/dist/controllers/user-storage/account-syncing/__fixtures__/test-utils.mjs.map +1 -0
  34. package/dist/controllers/user-storage/account-syncing/constants.cjs.map +1 -0
  35. package/dist/controllers/user-storage/account-syncing/constants.d.cts.map +1 -0
  36. package/dist/controllers/user-storage/account-syncing/constants.d.mts.map +1 -0
  37. package/dist/controllers/user-storage/account-syncing/constants.mjs.map +1 -0
  38. package/dist/controllers/user-storage/account-syncing/controller-integration.cjs +194 -0
  39. package/dist/controllers/user-storage/account-syncing/controller-integration.cjs.map +1 -0
  40. package/dist/controllers/user-storage/account-syncing/controller-integration.d.cts +31 -0
  41. package/dist/controllers/user-storage/account-syncing/controller-integration.d.cts.map +1 -0
  42. package/dist/controllers/user-storage/account-syncing/controller-integration.d.mts +31 -0
  43. package/dist/controllers/user-storage/account-syncing/controller-integration.d.mts.map +1 -0
  44. package/dist/controllers/user-storage/account-syncing/controller-integration.mjs +188 -0
  45. package/dist/controllers/user-storage/account-syncing/controller-integration.mjs.map +1 -0
  46. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.cjs +35 -0
  47. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.cjs.map +1 -0
  48. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.d.cts +8 -0
  49. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.d.cts.map +1 -0
  50. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.d.mts +8 -0
  51. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.d.mts.map +1 -0
  52. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.mjs +31 -0
  53. package/dist/controllers/user-storage/account-syncing/setup-subscriptions.mjs.map +1 -0
  54. package/dist/controllers/user-storage/account-syncing/sync-utils.cjs +47 -0
  55. package/dist/controllers/user-storage/account-syncing/sync-utils.cjs.map +1 -0
  56. package/dist/controllers/user-storage/account-syncing/sync-utils.d.cts +20 -0
  57. package/dist/controllers/user-storage/account-syncing/sync-utils.d.cts.map +1 -0
  58. package/dist/controllers/user-storage/account-syncing/sync-utils.d.mts +20 -0
  59. package/dist/controllers/user-storage/account-syncing/sync-utils.d.mts.map +1 -0
  60. package/dist/controllers/user-storage/account-syncing/sync-utils.mjs +41 -0
  61. package/dist/controllers/user-storage/account-syncing/sync-utils.mjs.map +1 -0
  62. package/dist/controllers/user-storage/account-syncing/types.cjs +3 -0
  63. package/dist/controllers/user-storage/account-syncing/types.cjs.map +1 -0
  64. package/dist/controllers/user-storage/account-syncing/types.d.cts +26 -0
  65. package/dist/controllers/user-storage/account-syncing/types.d.cts.map +1 -0
  66. package/dist/controllers/user-storage/account-syncing/types.d.mts +26 -0
  67. package/dist/controllers/user-storage/account-syncing/types.d.mts.map +1 -0
  68. package/dist/controllers/user-storage/account-syncing/types.mjs +2 -0
  69. package/dist/controllers/user-storage/account-syncing/types.mjs.map +1 -0
  70. package/dist/controllers/user-storage/{accounts/user-storage.cjs → account-syncing/utils.cjs} +12 -2
  71. package/dist/controllers/user-storage/account-syncing/utils.cjs.map +1 -0
  72. package/dist/controllers/user-storage/{accounts/user-storage.d.cts → account-syncing/utils.d.cts} +8 -17
  73. package/dist/controllers/user-storage/account-syncing/utils.d.cts.map +1 -0
  74. package/dist/controllers/user-storage/{accounts/user-storage.d.mts → account-syncing/utils.d.mts} +8 -17
  75. package/dist/controllers/user-storage/account-syncing/utils.d.mts.map +1 -0
  76. package/dist/controllers/user-storage/{accounts/user-storage.mjs → account-syncing/utils.mjs} +10 -1
  77. package/dist/controllers/user-storage/account-syncing/utils.mjs.map +1 -0
  78. package/package.json +3 -3
  79. package/dist/controllers/user-storage/__fixtures__/mockAccounts.cjs.map +0 -1
  80. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.cts.map +0 -1
  81. package/dist/controllers/user-storage/__fixtures__/mockAccounts.d.mts.map +0 -1
  82. package/dist/controllers/user-storage/__fixtures__/mockAccounts.mjs.map +0 -1
  83. package/dist/controllers/user-storage/accounts/constants.cjs.map +0 -1
  84. package/dist/controllers/user-storage/accounts/constants.d.cts.map +0 -1
  85. package/dist/controllers/user-storage/accounts/constants.d.mts.map +0 -1
  86. package/dist/controllers/user-storage/accounts/constants.mjs.map +0 -1
  87. package/dist/controllers/user-storage/accounts/user-storage.cjs.map +0 -1
  88. package/dist/controllers/user-storage/accounts/user-storage.d.cts.map +0 -1
  89. package/dist/controllers/user-storage/accounts/user-storage.d.mts.map +0 -1
  90. package/dist/controllers/user-storage/accounts/user-storage.mjs.map +0 -1
  91. /package/dist/controllers/user-storage/{accounts → account-syncing}/constants.cjs +0 -0
  92. /package/dist/controllers/user-storage/{accounts → account-syncing}/constants.d.cts +0 -0
  93. /package/dist/controllers/user-storage/{accounts → account-syncing}/constants.d.mts +0 -0
  94. /package/dist/controllers/user-storage/{accounts → account-syncing}/constants.mjs +0 -0
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createExpectedAccountSyncBatchDeleteBody = exports.createExpectedAccountSyncBatchUpsertBody = exports.mockUserStorageMessengerForAccountSyncing = void 0;
4
+ const encryption_1 = require("../../../../shared/encryption/index.cjs");
5
+ const mockMessenger_1 = require("../../__fixtures__/mockMessenger.cjs");
6
+ const utils_1 = require("../utils.cjs");
7
+ const mockAccounts_1 = require("./mockAccounts.cjs");
8
+ /**
9
+ * Test Utility - create a mock user storage messenger for account syncing tests
10
+ *
11
+ * @param options - options for the mock messenger
12
+ * @param options.accounts - options for the accounts part of the controller
13
+ * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action
14
+ * @returns Mock User Storage Messenger
15
+ */
16
+ function mockUserStorageMessengerForAccountSyncing(options) {
17
+ const messengerMocks = (0, mockMessenger_1.mockUserStorageMessenger)();
18
+ messengerMocks.mockKeyringAddNewAccount.mockImplementation(async () => {
19
+ messengerMocks.baseMessenger.publish('AccountsController:accountAdded', mockAccounts_1.MOCK_INTERNAL_ACCOUNTS.ONE[0]);
20
+ return mockAccounts_1.MOCK_INTERNAL_ACCOUNTS.ONE[0].address;
21
+ });
22
+ messengerMocks.mockAccountsListAccounts.mockReturnValue((options?.accounts?.accountsList ??
23
+ mockAccounts_1.MOCK_INTERNAL_ACCOUNTS.ALL));
24
+ return messengerMocks;
25
+ }
26
+ exports.mockUserStorageMessengerForAccountSyncing = mockUserStorageMessengerForAccountSyncing;
27
+ /**
28
+ * Test Utility - creates a realistic expected batch upsert payload
29
+ * @param data - data supposed to be upserted
30
+ * @param storageKey - storage key
31
+ * @returns expected body
32
+ */
33
+ function createExpectedAccountSyncBatchUpsertBody(data, storageKey) {
34
+ return data.map(([entryKey, entryValue]) => [
35
+ (0, encryption_1.createSHA256Hash)(String(entryKey) + storageKey),
36
+ JSON.stringify((0, utils_1.mapInternalAccountToUserStorageAccount)(entryValue)),
37
+ ]);
38
+ }
39
+ exports.createExpectedAccountSyncBatchUpsertBody = createExpectedAccountSyncBatchUpsertBody;
40
+ /**
41
+ * Test Utility - creates a realistic expected batch delete payload
42
+ * @param data - data supposed to be deleted
43
+ * @param storageKey - storage key
44
+ * @returns expected body
45
+ */
46
+ function createExpectedAccountSyncBatchDeleteBody(data, storageKey) {
47
+ return data.map((entryKey) => (0, encryption_1.createSHA256Hash)(String(entryKey) + storageKey));
48
+ }
49
+ exports.createExpectedAccountSyncBatchDeleteBody = createExpectedAccountSyncBatchDeleteBody;
50
+ //# sourceMappingURL=test-utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.cjs","sourceRoot":"","sources":["../../../../../src/controllers/user-storage/account-syncing/__fixtures__/test-utils.ts"],"names":[],"mappings":";;;AAEA,wEAAiE;AACjE,wEAA4E;AAC5E,wCAAkE;AAClE,qDAAwD;AAExD;;;;;;;GAOG;AACH,SAAgB,yCAAyC,CAAC,OAIzD;IACC,MAAM,cAAc,GAAG,IAAA,wCAAwB,GAAE,CAAC;IAElD,cAAc,CAAC,wBAAwB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;QACpE,cAAc,CAAC,aAAa,CAAC,OAAO,CAClC,iCAAiC,EACjC,qCAAsB,CAAC,GAAG,CAAC,CAAC,CAAoB,CACjD,CAAC;QACF,OAAO,qCAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,wBAAwB,CAAC,eAAe,CACrD,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY;QAC9B,qCAAsB,CAAC,GAAG,CAAsB,CACnD,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AArBD,8FAqBC;AAED;;;;;GAKG;AACH,SAAgB,wCAAwC,CACtD,IAAiC,EACjC,UAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC;QAC1C,IAAA,6BAAgB,EAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;QAC/C,IAAI,CAAC,SAAS,CAAC,IAAA,8CAAsC,EAAC,UAAU,CAAC,CAAC;KACnE,CAAC,CAAC;AACL,CAAC;AARD,4FAQC;AAED;;;;;GAKG;AACH,SAAgB,wCAAwC,CACtD,IAAc,EACd,UAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC3B,IAAA,6BAAgB,EAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,CAChD,CAAC;AACJ,CAAC;AAPD,4FAOC","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { createSHA256Hash } from '../../../../shared/encryption';\nimport { mockUserStorageMessenger } from '../../__fixtures__/mockMessenger';\nimport { mapInternalAccountToUserStorageAccount } from '../utils';\nimport { MOCK_INTERNAL_ACCOUNTS } from './mockAccounts';\n\n/**\n * Test Utility - create a mock user storage messenger for account syncing tests\n *\n * @param options - options for the mock messenger\n * @param options.accounts - options for the accounts part of the controller\n * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action\n * @returns Mock User Storage Messenger\n */\nexport function mockUserStorageMessengerForAccountSyncing(options?: {\n accounts?: {\n accountsList?: InternalAccount[];\n };\n}) {\n const messengerMocks = mockUserStorageMessenger();\n\n messengerMocks.mockKeyringAddNewAccount.mockImplementation(async () => {\n messengerMocks.baseMessenger.publish(\n 'AccountsController:accountAdded',\n MOCK_INTERNAL_ACCOUNTS.ONE[0] as InternalAccount,\n );\n return MOCK_INTERNAL_ACCOUNTS.ONE[0].address;\n });\n\n messengerMocks.mockAccountsListAccounts.mockReturnValue(\n (options?.accounts?.accountsList ??\n MOCK_INTERNAL_ACCOUNTS.ALL) as InternalAccount[],\n );\n\n return messengerMocks;\n}\n\n/**\n * Test Utility - creates a realistic expected batch upsert payload\n * @param data - data supposed to be upserted\n * @param storageKey - storage key\n * @returns expected body\n */\nexport function createExpectedAccountSyncBatchUpsertBody(\n data: [string, InternalAccount][],\n storageKey: string,\n) {\n return data.map(([entryKey, entryValue]) => [\n createSHA256Hash(String(entryKey) + storageKey),\n JSON.stringify(mapInternalAccountToUserStorageAccount(entryValue)),\n ]);\n}\n\n/**\n * Test Utility - creates a realistic expected batch delete payload\n * @param data - data supposed to be deleted\n * @param storageKey - storage key\n * @returns expected body\n */\nexport function createExpectedAccountSyncBatchDeleteBody(\n data: string[],\n storageKey: string,\n) {\n return data.map((entryKey) =>\n createSHA256Hash(String(entryKey) + storageKey),\n );\n}\n"]}
@@ -0,0 +1,85 @@
1
+ /// <reference types="jest" />
2
+ import type { InternalAccount } from "@metamask/keyring-internal-api";
3
+ /**
4
+ * Test Utility - create a mock user storage messenger for account syncing tests
5
+ *
6
+ * @param options - options for the mock messenger
7
+ * @param options.accounts - options for the accounts part of the controller
8
+ * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action
9
+ * @returns Mock User Storage Messenger
10
+ */
11
+ export declare function mockUserStorageMessengerForAccountSyncing(options?: {
12
+ accounts?: {
13
+ accountsList?: InternalAccount[];
14
+ };
15
+ }): {
16
+ baseMessenger: import("@metamask/base-controller").ControllerMessenger<import("../../index.cjs").AllowedActions, import("../../index.cjs").AllowedEvents>;
17
+ messenger: import("@metamask/base-controller").RestrictedControllerMessenger<"UserStorageController", import("@metamask/snaps-controllers").HandleSnapRequest | {
18
+ type: "AuthenticationController:isSignedIn";
19
+ handler: () => boolean;
20
+ } | {
21
+ type: "AuthenticationController:performSignIn";
22
+ handler: () => Promise<string>;
23
+ } | {
24
+ type: "AuthenticationController:performSignOut";
25
+ handler: () => void;
26
+ } | {
27
+ type: "AuthenticationController:getBearerToken";
28
+ handler: () => Promise<string>;
29
+ } | {
30
+ type: "AuthenticationController:getSessionProfile";
31
+ handler: () => Promise<{
32
+ identifierId: string;
33
+ profileId: string;
34
+ }>;
35
+ } | import("@metamask/keyring-controller").KeyringControllerGetStateAction | import("../../index.cjs").NotificationServicesControllerDisableNotificationServices | import("../../index.cjs").NotificationServicesControllerSelectIsNotificationServicesEnabled | import("@metamask/accounts-controller").AccountsControllerListAccountsAction | import("@metamask/accounts-controller").AccountsControllerUpdateAccountMetadataAction | import("@metamask/keyring-controller").KeyringControllerAddNewAccountAction | import("@metamask/network-controller").NetworkControllerGetStateAction | import("@metamask/network-controller").NetworkControllerAddNetworkAction | import("@metamask/network-controller").NetworkControllerRemoveNetworkAction | import("@metamask/network-controller").NetworkControllerUpdateNetworkAction, import("@metamask/keyring-controller").KeyringControllerLockEvent | import("@metamask/keyring-controller").KeyringControllerUnlockEvent | import("../../index.cjs").UserStorageControllerStateChangeEvent | import("../../index.cjs").UserStorageControllerAccountSyncingInProgress | import("../../index.cjs").UserStorageControllerAccountSyncingComplete | import("@metamask/accounts-controller").AccountsControllerAccountAddedEvent | import("@metamask/accounts-controller").AccountsControllerAccountRenamedEvent | import("@metamask/network-controller").NetworkControllerNetworkRemovedEvent, "SnapController:handleRequest" | "KeyringController:getState" | "AuthenticationController:isSignedIn" | "AuthenticationController:performSignIn" | "AuthenticationController:performSignOut" | "AuthenticationController:getBearerToken" | "AuthenticationController:getSessionProfile" | "NotificationServicesController:disableNotificationServices" | "NotificationServicesController:selectIsNotificationServicesEnabled" | "AccountsController:listAccounts" | "AccountsController:updateAccountMetadata" | "KeyringController:addNewAccount" | "NetworkController:getState" | "NetworkController:addNetwork" | "NetworkController:removeNetwork" | "NetworkController:updateNetwork", "KeyringController:lock" | "KeyringController:unlock" | "AccountsController:accountAdded" | "AccountsController:accountRenamed" | "NetworkController:networkRemoved">;
36
+ mockSnapGetPublicKey: jest.Mock<any, any>;
37
+ mockSnapSignMessage: jest.Mock<any, any>;
38
+ mockAuthGetBearerToken: jest.Mock<Promise<string>, []>;
39
+ mockAuthGetSessionProfile: jest.Mock<Promise<{
40
+ identifierId: string;
41
+ profileId: string;
42
+ }>, []>;
43
+ mockAuthPerformSignIn: jest.Mock<Promise<string>, []>;
44
+ mockAuthIsSignedIn: jest.Mock<boolean, []>;
45
+ mockNotificationServicesIsEnabled: jest.Mock<boolean, []>;
46
+ mockNotificationServicesDisableNotifications: jest.Mock<Promise<void>, []>;
47
+ mockAuthPerformSignOut: jest.Mock<void, []>;
48
+ mockKeyringAddNewAccount: jest.Mock<Promise<string>, [accountCount?: number | undefined]>;
49
+ mockAccountsUpdateAccountMetadata: jest.Mock<void, [accountId: string, metadata: Partial<{
50
+ name: string;
51
+ importTime: number;
52
+ keyring: {
53
+ type: string;
54
+ };
55
+ nameLastUpdatedAt?: number | undefined;
56
+ snap?: {
57
+ name: string;
58
+ id: string;
59
+ enabled: boolean;
60
+ } | undefined;
61
+ lastSelected?: number | undefined;
62
+ }>]>;
63
+ mockAccountsListAccounts: jest.Mock<any, any>;
64
+ mockNetworkControllerGetState: jest.Mock<import("@metamask/network-controller").NetworkState, []>;
65
+ mockNetworkControllerAddNetwork: jest.Mock<import("@metamask/network-controller").NetworkConfiguration, [fields: import("@metamask/network-controller").AddNetworkFields]>;
66
+ mockNetworkControllerRemoveNetwork: jest.Mock<void, [chainId: `0x${string}`]>;
67
+ mockNetworkControllerUpdateNetwork: jest.Mock<Promise<import("@metamask/network-controller").NetworkConfiguration>, [`0x${string}`, import("@metamask/network-controller").UpdateNetworkFields, ({
68
+ replacementSelectedRpcEndpointIndex?: number | undefined;
69
+ } | undefined)?]>;
70
+ };
71
+ /**
72
+ * Test Utility - creates a realistic expected batch upsert payload
73
+ * @param data - data supposed to be upserted
74
+ * @param storageKey - storage key
75
+ * @returns expected body
76
+ */
77
+ export declare function createExpectedAccountSyncBatchUpsertBody(data: [string, InternalAccount][], storageKey: string): string[][];
78
+ /**
79
+ * Test Utility - creates a realistic expected batch delete payload
80
+ * @param data - data supposed to be deleted
81
+ * @param storageKey - storage key
82
+ * @returns expected body
83
+ */
84
+ export declare function createExpectedAccountSyncBatchDeleteBody(data: string[], storageKey: string): string[];
85
+ //# sourceMappingURL=test-utils.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.cts","sourceRoot":"","sources":["../../../../../src/controllers/user-storage/account-syncing/__fixtures__/test-utils.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAOtE;;;;;;;GAOG;AACH,wBAAgB,yCAAyC,CAAC,OAAO,CAAC,EAAE;IAClE,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;KAClC,CAAC;CACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBA;AAED;;;;;GAKG;AACH,wBAAgB,wCAAwC,CACtD,IAAI,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,EACjC,UAAU,EAAE,MAAM,cAMnB;AAED;;;;;GAKG;AACH,wBAAgB,wCAAwC,CACtD,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,MAAM,YAKnB"}
@@ -0,0 +1,85 @@
1
+ /// <reference types="jest" />
2
+ import type { InternalAccount } from "@metamask/keyring-internal-api";
3
+ /**
4
+ * Test Utility - create a mock user storage messenger for account syncing tests
5
+ *
6
+ * @param options - options for the mock messenger
7
+ * @param options.accounts - options for the accounts part of the controller
8
+ * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action
9
+ * @returns Mock User Storage Messenger
10
+ */
11
+ export declare function mockUserStorageMessengerForAccountSyncing(options?: {
12
+ accounts?: {
13
+ accountsList?: InternalAccount[];
14
+ };
15
+ }): {
16
+ baseMessenger: import("@metamask/base-controller").ControllerMessenger<import("../../index.mjs").AllowedActions, import("../../index.mjs").AllowedEvents>;
17
+ messenger: import("@metamask/base-controller").RestrictedControllerMessenger<"UserStorageController", import("@metamask/snaps-controllers").HandleSnapRequest | {
18
+ type: "AuthenticationController:isSignedIn";
19
+ handler: () => boolean;
20
+ } | {
21
+ type: "AuthenticationController:performSignIn";
22
+ handler: () => Promise<string>;
23
+ } | {
24
+ type: "AuthenticationController:performSignOut";
25
+ handler: () => void;
26
+ } | {
27
+ type: "AuthenticationController:getBearerToken";
28
+ handler: () => Promise<string>;
29
+ } | {
30
+ type: "AuthenticationController:getSessionProfile";
31
+ handler: () => Promise<{
32
+ identifierId: string;
33
+ profileId: string;
34
+ }>;
35
+ } | import("@metamask/keyring-controller").KeyringControllerGetStateAction | import("../../index.mjs").NotificationServicesControllerDisableNotificationServices | import("../../index.mjs").NotificationServicesControllerSelectIsNotificationServicesEnabled | import("@metamask/accounts-controller").AccountsControllerListAccountsAction | import("@metamask/accounts-controller").AccountsControllerUpdateAccountMetadataAction | import("@metamask/keyring-controller").KeyringControllerAddNewAccountAction | import("@metamask/network-controller").NetworkControllerGetStateAction | import("@metamask/network-controller").NetworkControllerAddNetworkAction | import("@metamask/network-controller").NetworkControllerRemoveNetworkAction | import("@metamask/network-controller").NetworkControllerUpdateNetworkAction, import("@metamask/keyring-controller").KeyringControllerLockEvent | import("@metamask/keyring-controller").KeyringControllerUnlockEvent | import("../../index.mjs").UserStorageControllerStateChangeEvent | import("../../index.mjs").UserStorageControllerAccountSyncingInProgress | import("../../index.mjs").UserStorageControllerAccountSyncingComplete | import("@metamask/accounts-controller").AccountsControllerAccountAddedEvent | import("@metamask/accounts-controller").AccountsControllerAccountRenamedEvent | import("@metamask/network-controller").NetworkControllerNetworkRemovedEvent, "SnapController:handleRequest" | "KeyringController:getState" | "AuthenticationController:isSignedIn" | "AuthenticationController:performSignIn" | "AuthenticationController:performSignOut" | "AuthenticationController:getBearerToken" | "AuthenticationController:getSessionProfile" | "NotificationServicesController:disableNotificationServices" | "NotificationServicesController:selectIsNotificationServicesEnabled" | "AccountsController:listAccounts" | "AccountsController:updateAccountMetadata" | "KeyringController:addNewAccount" | "NetworkController:getState" | "NetworkController:addNetwork" | "NetworkController:removeNetwork" | "NetworkController:updateNetwork", "KeyringController:lock" | "KeyringController:unlock" | "AccountsController:accountAdded" | "AccountsController:accountRenamed" | "NetworkController:networkRemoved">;
36
+ mockSnapGetPublicKey: jest.Mock<any, any>;
37
+ mockSnapSignMessage: jest.Mock<any, any>;
38
+ mockAuthGetBearerToken: jest.Mock<Promise<string>, []>;
39
+ mockAuthGetSessionProfile: jest.Mock<Promise<{
40
+ identifierId: string;
41
+ profileId: string;
42
+ }>, []>;
43
+ mockAuthPerformSignIn: jest.Mock<Promise<string>, []>;
44
+ mockAuthIsSignedIn: jest.Mock<boolean, []>;
45
+ mockNotificationServicesIsEnabled: jest.Mock<boolean, []>;
46
+ mockNotificationServicesDisableNotifications: jest.Mock<Promise<void>, []>;
47
+ mockAuthPerformSignOut: jest.Mock<void, []>;
48
+ mockKeyringAddNewAccount: jest.Mock<Promise<string>, [accountCount?: number | undefined]>;
49
+ mockAccountsUpdateAccountMetadata: jest.Mock<void, [accountId: string, metadata: Partial<{
50
+ name: string;
51
+ importTime: number;
52
+ keyring: {
53
+ type: string;
54
+ };
55
+ nameLastUpdatedAt?: number | undefined;
56
+ snap?: {
57
+ name: string;
58
+ id: string;
59
+ enabled: boolean;
60
+ } | undefined;
61
+ lastSelected?: number | undefined;
62
+ }>]>;
63
+ mockAccountsListAccounts: jest.Mock<any, any>;
64
+ mockNetworkControllerGetState: jest.Mock<import("@metamask/network-controller").NetworkState, []>;
65
+ mockNetworkControllerAddNetwork: jest.Mock<import("@metamask/network-controller").NetworkConfiguration, [fields: import("@metamask/network-controller").AddNetworkFields]>;
66
+ mockNetworkControllerRemoveNetwork: jest.Mock<void, [chainId: `0x${string}`]>;
67
+ mockNetworkControllerUpdateNetwork: jest.Mock<Promise<import("@metamask/network-controller").NetworkConfiguration>, [`0x${string}`, import("@metamask/network-controller").UpdateNetworkFields, ({
68
+ replacementSelectedRpcEndpointIndex?: number | undefined;
69
+ } | undefined)?]>;
70
+ };
71
+ /**
72
+ * Test Utility - creates a realistic expected batch upsert payload
73
+ * @param data - data supposed to be upserted
74
+ * @param storageKey - storage key
75
+ * @returns expected body
76
+ */
77
+ export declare function createExpectedAccountSyncBatchUpsertBody(data: [string, InternalAccount][], storageKey: string): string[][];
78
+ /**
79
+ * Test Utility - creates a realistic expected batch delete payload
80
+ * @param data - data supposed to be deleted
81
+ * @param storageKey - storage key
82
+ * @returns expected body
83
+ */
84
+ export declare function createExpectedAccountSyncBatchDeleteBody(data: string[], storageKey: string): string[];
85
+ //# sourceMappingURL=test-utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.mts","sourceRoot":"","sources":["../../../../../src/controllers/user-storage/account-syncing/__fixtures__/test-utils.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAOtE;;;;;;;GAOG;AACH,wBAAgB,yCAAyC,CAAC,OAAO,CAAC,EAAE;IAClE,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;KAClC,CAAC;CACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBA;AAED;;;;;GAKG;AACH,wBAAgB,wCAAwC,CACtD,IAAI,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,EACjC,UAAU,EAAE,MAAM,cAMnB;AAED;;;;;GAKG;AACH,wBAAgB,wCAAwC,CACtD,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,MAAM,YAKnB"}
@@ -0,0 +1,44 @@
1
+ import { createSHA256Hash } from "../../../../shared/encryption/index.mjs";
2
+ import { mockUserStorageMessenger } from "../../__fixtures__/mockMessenger.mjs";
3
+ import { mapInternalAccountToUserStorageAccount } from "../utils.mjs";
4
+ import { MOCK_INTERNAL_ACCOUNTS } from "./mockAccounts.mjs";
5
+ /**
6
+ * Test Utility - create a mock user storage messenger for account syncing tests
7
+ *
8
+ * @param options - options for the mock messenger
9
+ * @param options.accounts - options for the accounts part of the controller
10
+ * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action
11
+ * @returns Mock User Storage Messenger
12
+ */
13
+ export function mockUserStorageMessengerForAccountSyncing(options) {
14
+ const messengerMocks = mockUserStorageMessenger();
15
+ messengerMocks.mockKeyringAddNewAccount.mockImplementation(async () => {
16
+ messengerMocks.baseMessenger.publish('AccountsController:accountAdded', MOCK_INTERNAL_ACCOUNTS.ONE[0]);
17
+ return MOCK_INTERNAL_ACCOUNTS.ONE[0].address;
18
+ });
19
+ messengerMocks.mockAccountsListAccounts.mockReturnValue((options?.accounts?.accountsList ??
20
+ MOCK_INTERNAL_ACCOUNTS.ALL));
21
+ return messengerMocks;
22
+ }
23
+ /**
24
+ * Test Utility - creates a realistic expected batch upsert payload
25
+ * @param data - data supposed to be upserted
26
+ * @param storageKey - storage key
27
+ * @returns expected body
28
+ */
29
+ export function createExpectedAccountSyncBatchUpsertBody(data, storageKey) {
30
+ return data.map(([entryKey, entryValue]) => [
31
+ createSHA256Hash(String(entryKey) + storageKey),
32
+ JSON.stringify(mapInternalAccountToUserStorageAccount(entryValue)),
33
+ ]);
34
+ }
35
+ /**
36
+ * Test Utility - creates a realistic expected batch delete payload
37
+ * @param data - data supposed to be deleted
38
+ * @param storageKey - storage key
39
+ * @returns expected body
40
+ */
41
+ export function createExpectedAccountSyncBatchDeleteBody(data, storageKey) {
42
+ return data.map((entryKey) => createSHA256Hash(String(entryKey) + storageKey));
43
+ }
44
+ //# sourceMappingURL=test-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.mjs","sourceRoot":"","sources":["../../../../../src/controllers/user-storage/account-syncing/__fixtures__/test-utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,gDAAsC;AACjE,OAAO,EAAE,wBAAwB,EAAE,6CAAyC;AAC5E,OAAO,EAAE,sCAAsC,EAAE,qBAAiB;AAClE,OAAO,EAAE,sBAAsB,EAAE,2BAAuB;AAExD;;;;;;;GAOG;AACH,MAAM,UAAU,yCAAyC,CAAC,OAIzD;IACC,MAAM,cAAc,GAAG,wBAAwB,EAAE,CAAC;IAElD,cAAc,CAAC,wBAAwB,CAAC,kBAAkB,CAAC,KAAK,IAAI,EAAE;QACpE,cAAc,CAAC,aAAa,CAAC,OAAO,CAClC,iCAAiC,EACjC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAoB,CACjD,CAAC;QACF,OAAO,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,wBAAwB,CAAC,eAAe,CACrD,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY;QAC9B,sBAAsB,CAAC,GAAG,CAAsB,CACnD,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wCAAwC,CACtD,IAAiC,EACjC,UAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC;QAC1C,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;QAC/C,IAAI,CAAC,SAAS,CAAC,sCAAsC,CAAC,UAAU,CAAC,CAAC;KACnE,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wCAAwC,CACtD,IAAc,EACd,UAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC3B,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,CAChD,CAAC;AACJ,CAAC","sourcesContent":["import type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { createSHA256Hash } from '../../../../shared/encryption';\nimport { mockUserStorageMessenger } from '../../__fixtures__/mockMessenger';\nimport { mapInternalAccountToUserStorageAccount } from '../utils';\nimport { MOCK_INTERNAL_ACCOUNTS } from './mockAccounts';\n\n/**\n * Test Utility - create a mock user storage messenger for account syncing tests\n *\n * @param options - options for the mock messenger\n * @param options.accounts - options for the accounts part of the controller\n * @param options.accounts.accountsList - list of accounts to return for the 'AccountsController:listAccounts' action\n * @returns Mock User Storage Messenger\n */\nexport function mockUserStorageMessengerForAccountSyncing(options?: {\n accounts?: {\n accountsList?: InternalAccount[];\n };\n}) {\n const messengerMocks = mockUserStorageMessenger();\n\n messengerMocks.mockKeyringAddNewAccount.mockImplementation(async () => {\n messengerMocks.baseMessenger.publish(\n 'AccountsController:accountAdded',\n MOCK_INTERNAL_ACCOUNTS.ONE[0] as InternalAccount,\n );\n return MOCK_INTERNAL_ACCOUNTS.ONE[0].address;\n });\n\n messengerMocks.mockAccountsListAccounts.mockReturnValue(\n (options?.accounts?.accountsList ??\n MOCK_INTERNAL_ACCOUNTS.ALL) as InternalAccount[],\n );\n\n return messengerMocks;\n}\n\n/**\n * Test Utility - creates a realistic expected batch upsert payload\n * @param data - data supposed to be upserted\n * @param storageKey - storage key\n * @returns expected body\n */\nexport function createExpectedAccountSyncBatchUpsertBody(\n data: [string, InternalAccount][],\n storageKey: string,\n) {\n return data.map(([entryKey, entryValue]) => [\n createSHA256Hash(String(entryKey) + storageKey),\n JSON.stringify(mapInternalAccountToUserStorageAccount(entryValue)),\n ]);\n}\n\n/**\n * Test Utility - creates a realistic expected batch delete payload\n * @param data - data supposed to be deleted\n * @param storageKey - storage key\n * @returns expected body\n */\nexport function createExpectedAccountSyncBatchDeleteBody(\n data: string[],\n storageKey: string,\n) {\n return data.map((entryKey) =>\n createSHA256Hash(String(entryKey) + storageKey),\n );\n}\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,oBAAoB,GAAG,GAAG,CAAC;AAExC,4FAA4F;AAC/E,QAAA,wBAAwB,GAAkB,GAAY,CAAC;AAEpE,qGAAqG;AACxF,QAAA,+BAA+B,GAAG;IAC7C,SAAS;IACT,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,MAAM;IACN,OAAO;IACP,aAAa;IACb,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;IACT,OAAO;IACP,QAAQ;IACR,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,IAAI;IACJ,SAAS;IACT,OAAO;IACP,WAAW;IACX,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,OAAO;IACP,iBAAiB;IACjB,WAAW;IACX,IAAI;IACJ,IAAI;CACI,CAAC","sourcesContent":["export const USER_STORAGE_VERSION = '1';\n\n// Force cast. We don't really care about the type here since we treat it as a unique symbol\nexport const USER_STORAGE_VERSION_KEY: unique symbol = 'v' as never;\n\n// We need this in order to know if an account is a default account or not when we do account syncing\nexport const LOCALIZED_DEFAULT_ACCOUNT_NAMES = [\n 'Account',\n 'መለያ',\n 'الحساب',\n 'Профил',\n 'অ্যাকাউন্ট',\n 'Compte',\n 'Účet',\n 'Konto',\n 'Λογαριασμός',\n 'Cuenta',\n 'حساب',\n 'Tili',\n 'એકાઉન્ટ',\n 'חשבון',\n 'अकाउंट',\n 'खाता',\n 'Račun',\n 'Kont',\n 'Fiók',\n 'Akun',\n 'アカウント',\n 'ಖಾತೆ',\n '계정',\n 'Paskyra',\n 'Konts',\n 'അക്കൗണ്ട്',\n 'खाते',\n 'Akaun',\n 'Conta',\n 'Cont',\n 'Счет',\n 'налог',\n 'Akaunti',\n 'கணக்கு',\n 'ఖాతా',\n 'บัญชี',\n 'Hesap',\n 'Обліковий запис',\n 'Tài khoản',\n '账户',\n '帳戶',\n] as const;\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAGxC,eAAO,MAAM,wBAAwB,EAAE,OAAO,MAAqB,CAAC;AAGpE,eAAO,MAAM,+BAA+B,gZA0ClC,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAGxC,eAAO,MAAM,wBAAwB,EAAE,OAAO,MAAqB,CAAC;AAGpE,eAAO,MAAM,+BAA+B,gZA0ClC,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC,4FAA4F;AAC5F,MAAM,CAAC,MAAM,wBAAwB,GAAkB,GAAY,CAAC;AAEpE,qGAAqG;AACrG,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,SAAS;IACT,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,MAAM;IACN,OAAO;IACP,aAAa;IACb,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;IACT,OAAO;IACP,QAAQ;IACR,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,IAAI;IACJ,SAAS;IACT,OAAO;IACP,WAAW;IACX,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,OAAO;IACP,iBAAiB;IACjB,WAAW;IACX,IAAI;IACJ,IAAI;CACI,CAAC","sourcesContent":["export const USER_STORAGE_VERSION = '1';\n\n// Force cast. We don't really care about the type here since we treat it as a unique symbol\nexport const USER_STORAGE_VERSION_KEY: unique symbol = 'v' as never;\n\n// We need this in order to know if an account is a default account or not when we do account syncing\nexport const LOCALIZED_DEFAULT_ACCOUNT_NAMES = [\n 'Account',\n 'መለያ',\n 'الحساب',\n 'Профил',\n 'অ্যাকাউন্ট',\n 'Compte',\n 'Účet',\n 'Konto',\n 'Λογαριασμός',\n 'Cuenta',\n 'حساب',\n 'Tili',\n 'એકાઉન્ટ',\n 'חשבון',\n 'अकाउंट',\n 'खाता',\n 'Račun',\n 'Kont',\n 'Fiók',\n 'Akun',\n 'アカウント',\n 'ಖಾತೆ',\n '계정',\n 'Paskyra',\n 'Konts',\n 'അക്കൗണ്ട്',\n 'खाते',\n 'Akaun',\n 'Conta',\n 'Cont',\n 'Счет',\n 'налог',\n 'Akaunti',\n 'கணக்கு',\n 'ఖాతా',\n 'บัญชี',\n 'Hesap',\n 'Обліковий запис',\n 'Tài khoản',\n '账户',\n '帳戶',\n] as const;\n"]}
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.syncInternalAccountsWithUserStorage = exports.saveInternalAccountsListToUserStorage = exports.saveInternalAccountToUserStorage = void 0;
4
+ const keyring_api_1 = require("@metamask/keyring-api");
5
+ const storage_schema_1 = require("../../../shared/storage-schema.cjs");
6
+ const sync_utils_1 = require("./sync-utils.cjs");
7
+ const utils_1 = require("./utils.cjs");
8
+ /**
9
+ * Saves an individual internal account to the user storage.
10
+ * @param internalAccount - The internal account to save
11
+ * @param config - parameters used for saving the internal account
12
+ * @param options - parameters used for saving the internal account
13
+ */
14
+ async function saveInternalAccountToUserStorage(internalAccount, config, options) {
15
+ const { isAccountSyncingEnabled } = config;
16
+ const { getUserStorageControllerInstance } = options;
17
+ if (!isAccountSyncingEnabled ||
18
+ !(0, sync_utils_1.canPerformAccountSyncing)(config, options) ||
19
+ !(0, keyring_api_1.isEvmAccountType)(internalAccount.type) ||
20
+ !(0, utils_1.doesInternalAccountHaveCorrectKeyringType)(internalAccount)) {
21
+ return;
22
+ }
23
+ try {
24
+ // Map the internal account to the user storage account schema
25
+ const mappedAccount = (0, utils_1.mapInternalAccountToUserStorageAccount)(internalAccount);
26
+ await getUserStorageControllerInstance().performSetStorage(
27
+ // ESLint is confused here.
28
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
29
+ `${storage_schema_1.USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`, JSON.stringify(mappedAccount));
30
+ }
31
+ catch (e) {
32
+ // istanbul ignore next
33
+ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
34
+ throw new Error(`UserStorageController - failed to save account to user storage - ${errorMessage}`);
35
+ }
36
+ }
37
+ exports.saveInternalAccountToUserStorage = saveInternalAccountToUserStorage;
38
+ /**
39
+ * Saves the list of internal accounts to the user storage.
40
+ * @param config - parameters used for saving the list of internal accounts
41
+ * @param options - parameters used for saving the list of internal accounts
42
+ */
43
+ async function saveInternalAccountsListToUserStorage(config, options) {
44
+ const { isAccountSyncingEnabled } = config;
45
+ const { getUserStorageControllerInstance } = options;
46
+ if (!isAccountSyncingEnabled) {
47
+ return;
48
+ }
49
+ const internalAccountsList = await (0, sync_utils_1.getInternalAccountsList)(options);
50
+ if (!internalAccountsList?.length) {
51
+ return;
52
+ }
53
+ const internalAccountsListFormattedForUserStorage = internalAccountsList.map(utils_1.mapInternalAccountToUserStorageAccount);
54
+ await getUserStorageControllerInstance().performBatchSetStorage(storage_schema_1.USER_STORAGE_FEATURE_NAMES.accounts, internalAccountsListFormattedForUserStorage.map((account) => [
55
+ account.a,
56
+ JSON.stringify(account),
57
+ ]));
58
+ }
59
+ exports.saveInternalAccountsListToUserStorage = saveInternalAccountsListToUserStorage;
60
+ /**
61
+ * Syncs the internal accounts list with the user storage accounts list.
62
+ * This method is used to make sure that the internal accounts list is up-to-date with the user storage accounts list and vice-versa.
63
+ * It will add new accounts to the internal accounts list, update/merge conflicting names and re-upload the results in some cases to the user storage.
64
+ * @param config - parameters used for syncing the internal accounts list with the user storage accounts list
65
+ * @param options - parameters used for syncing the internal accounts list with the user storage accounts list
66
+ */
67
+ async function syncInternalAccountsWithUserStorage(config, options) {
68
+ const { isAccountSyncingEnabled } = config;
69
+ if (!(0, sync_utils_1.canPerformAccountSyncing)(config, options) || !isAccountSyncingEnabled) {
70
+ return;
71
+ }
72
+ const { maxNumberOfAccountsToAdd = 100, onAccountAdded, onAccountNameUpdated, onAccountSyncErroneousSituation, } = config;
73
+ const { getMessenger, getUserStorageControllerInstance } = options;
74
+ try {
75
+ await getUserStorageControllerInstance().setIsAccountSyncingInProgress(true);
76
+ const userStorageAccountsList = await (0, sync_utils_1.getUserStorageAccountsList)(options);
77
+ if (!userStorageAccountsList || !userStorageAccountsList.length) {
78
+ await saveInternalAccountsListToUserStorage({ isAccountSyncingEnabled }, options);
79
+ await getUserStorageControllerInstance().setHasAccountSyncingSyncedAtLeastOnce(true);
80
+ return;
81
+ }
82
+ // Prepare an array of internal accounts to be saved to the user storage
83
+ const internalAccountsToBeSavedToUserStorage = [];
84
+ // Compare internal accounts list with user storage accounts list
85
+ // First step: compare lengths
86
+ const internalAccountsList = await (0, sync_utils_1.getInternalAccountsList)(options);
87
+ if (!internalAccountsList || !internalAccountsList.length) {
88
+ throw new Error(`Failed to get internal accounts list`);
89
+ }
90
+ const hasMoreUserStorageAccountsThanInternalAccounts = userStorageAccountsList.length > internalAccountsList.length;
91
+ // We don't want to remove existing accounts for a user
92
+ // so we only add new accounts if the user has more accounts in user storage than internal accounts
93
+ if (hasMoreUserStorageAccountsThanInternalAccounts) {
94
+ const numberOfAccountsToAdd = Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -
95
+ internalAccountsList.length;
96
+ // Create new accounts to match the user storage accounts list
97
+ for (let i = 0; i < numberOfAccountsToAdd; i++) {
98
+ await getMessenger().call('KeyringController:addNewAccount');
99
+ onAccountAdded?.();
100
+ }
101
+ }
102
+ // Second step: compare account names
103
+ // Get the internal accounts list again since new accounts might have been added in the previous step
104
+ const refreshedInternalAccountsList = await (0, sync_utils_1.getInternalAccountsList)(options);
105
+ const newlyAddedAccounts = refreshedInternalAccountsList.filter((account) => !internalAccountsList.find((a) => a.address === account.address));
106
+ for (const internalAccount of refreshedInternalAccountsList) {
107
+ const userStorageAccount = userStorageAccountsList.find((account) => account.a === internalAccount.address);
108
+ // If the account is not present in user storage
109
+ // istanbul ignore next
110
+ if (!userStorageAccount) {
111
+ // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account
112
+ if (newlyAddedAccounts.includes(internalAccount)) {
113
+ onAccountSyncErroneousSituation?.('An account was added to the internal accounts list but was not present in the user storage accounts list');
114
+ continue;
115
+ }
116
+ // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage
117
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
118
+ continue;
119
+ }
120
+ // From this point on, we know that the account is present in
121
+ // both the internal accounts list and the user storage accounts list
122
+ // One or both accounts have default names
123
+ const isInternalAccountNameDefault = (0, utils_1.isNameDefaultAccountName)(internalAccount.metadata.name);
124
+ const isUserStorageAccountNameDefault = (0, utils_1.isNameDefaultAccountName)(userStorageAccount.n);
125
+ // Internal account has default name
126
+ if (isInternalAccountNameDefault) {
127
+ if (!isUserStorageAccountNameDefault) {
128
+ getMessenger().call('AccountsController:updateAccountMetadata', internalAccount.id, {
129
+ name: userStorageAccount.n,
130
+ });
131
+ onAccountNameUpdated?.();
132
+ }
133
+ continue;
134
+ }
135
+ // Internal account has custom name but user storage account has default name
136
+ if (isUserStorageAccountNameDefault) {
137
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
138
+ continue;
139
+ }
140
+ // Both accounts have custom names
141
+ // User storage account has a nameLastUpdatedAt timestamp
142
+ // Note: not storing the undefined checks in constants to act as a type guard
143
+ if (userStorageAccount.nlu !== undefined) {
144
+ if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
145
+ const isInternalAccountNameNewer = internalAccount.metadata.nameLastUpdatedAt > userStorageAccount.nlu;
146
+ if (isInternalAccountNameNewer) {
147
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
148
+ continue;
149
+ }
150
+ }
151
+ getMessenger().call('AccountsController:updateAccountMetadata', internalAccount.id, {
152
+ name: userStorageAccount.n,
153
+ nameLastUpdatedAt: userStorageAccount.nlu,
154
+ });
155
+ const areInternalAndUserStorageAccountNamesEqual = internalAccount.metadata.name === userStorageAccount.n;
156
+ if (!areInternalAndUserStorageAccountNamesEqual) {
157
+ onAccountNameUpdated?.();
158
+ }
159
+ continue;
160
+ }
161
+ else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {
162
+ internalAccountsToBeSavedToUserStorage.push(internalAccount);
163
+ continue;
164
+ }
165
+ }
166
+ // Save the internal accounts list to the user storage
167
+ if (internalAccountsToBeSavedToUserStorage.length) {
168
+ await getUserStorageControllerInstance().performBatchSetStorage(storage_schema_1.USER_STORAGE_FEATURE_NAMES.accounts, internalAccountsToBeSavedToUserStorage.map((account) => [
169
+ account.address,
170
+ JSON.stringify((0, utils_1.mapInternalAccountToUserStorageAccount)(account)),
171
+ ]));
172
+ }
173
+ // In case we have corrupted user storage with accounts that don't exist in the internal accounts list
174
+ // Delete those accounts from the user storage
175
+ const userStorageAccountsToBeDeleted = userStorageAccountsList.filter((account) => !refreshedInternalAccountsList.find((a) => a.address === account.a));
176
+ if (userStorageAccountsToBeDeleted.length) {
177
+ await getUserStorageControllerInstance().performBatchDeleteStorage(storage_schema_1.USER_STORAGE_FEATURE_NAMES.accounts, userStorageAccountsToBeDeleted.map((account) => account.a));
178
+ onAccountSyncErroneousSituation?.('An account was present in the user storage accounts list but was not found in the internal accounts list after the sync');
179
+ }
180
+ // We do this here and not in the finally statement because we want to make sure that
181
+ // the accounts are saved / updated / deleted at least once before we set this flag
182
+ await getUserStorageControllerInstance().setHasAccountSyncingSyncedAtLeastOnce(true);
183
+ }
184
+ catch (e) {
185
+ // istanbul ignore next
186
+ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);
187
+ throw new Error(`UserStorageController - failed to sync user storage accounts list - ${errorMessage}`);
188
+ }
189
+ finally {
190
+ await getUserStorageControllerInstance().setIsAccountSyncingInProgress(false);
191
+ }
192
+ }
193
+ exports.syncInternalAccountsWithUserStorage = syncInternalAccountsWithUserStorage;
194
+ //# sourceMappingURL=controller-integration.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-integration.cjs","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/controller-integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { isEvmAccountType } from '@metamask/keyring-api';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\n\nimport { USER_STORAGE_FEATURE_NAMES } from '../../../shared/storage-schema';\nimport {\n canPerformAccountSyncing,\n getInternalAccountsList,\n getUserStorageAccountsList,\n} from './sync-utils';\nimport type { AccountSyncingConfig, AccountSyncingOptions } from './types';\nimport {\n doesInternalAccountHaveCorrectKeyringType,\n isNameDefaultAccountName,\n mapInternalAccountToUserStorageAccount,\n} from './utils';\n\n/**\n * Saves an individual internal account to the user storage.\n * @param internalAccount - The internal account to save\n * @param config - parameters used for saving the internal account\n * @param options - parameters used for saving the internal account\n */\nexport async function saveInternalAccountToUserStorage(\n internalAccount: InternalAccount,\n config: AccountSyncingConfig,\n options: AccountSyncingOptions,\n): Promise<void> {\n const { isAccountSyncingEnabled } = config;\n const { getUserStorageControllerInstance } = options;\n\n if (\n !isAccountSyncingEnabled ||\n !canPerformAccountSyncing(config, options) ||\n !isEvmAccountType(internalAccount.type) ||\n !doesInternalAccountHaveCorrectKeyringType(internalAccount)\n ) {\n return;\n }\n\n try {\n // Map the internal account to the user storage account schema\n const mappedAccount =\n mapInternalAccountToUserStorageAccount(internalAccount);\n\n await getUserStorageControllerInstance().performSetStorage(\n // ESLint is confused here.\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `${USER_STORAGE_FEATURE_NAMES.accounts}.${internalAccount.address}`,\n JSON.stringify(mappedAccount),\n );\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to save account to user storage - ${errorMessage}`,\n );\n }\n}\n\n/**\n * Saves the list of internal accounts to the user storage.\n * @param config - parameters used for saving the list of internal accounts\n * @param options - parameters used for saving the list of internal accounts\n */\nexport async function saveInternalAccountsListToUserStorage(\n config: AccountSyncingConfig,\n options: AccountSyncingOptions,\n): Promise<void> {\n const { isAccountSyncingEnabled } = config;\n const { getUserStorageControllerInstance } = options;\n\n if (!isAccountSyncingEnabled) {\n return;\n }\n\n const internalAccountsList = await getInternalAccountsList(options);\n\n if (!internalAccountsList?.length) {\n return;\n }\n\n const internalAccountsListFormattedForUserStorage = internalAccountsList.map(\n mapInternalAccountToUserStorageAccount,\n );\n\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsListFormattedForUserStorage.map((account) => [\n account.a,\n JSON.stringify(account),\n ]),\n );\n}\n\ntype SyncInternalAccountsWithUserStorageConfig = AccountSyncingConfig & {\n maxNumberOfAccountsToAdd?: number;\n onAccountAdded?: () => void;\n onAccountNameUpdated?: () => void;\n onAccountSyncErroneousSituation?: (errorMessage: string) => void;\n};\n\n/**\n * Syncs the internal accounts list with the user storage accounts list.\n * This method is used to make sure that the internal accounts list is up-to-date with the user storage accounts list and vice-versa.\n * It will add new accounts to the internal accounts list, update/merge conflicting names and re-upload the results in some cases to the user storage.\n * @param config - parameters used for syncing the internal accounts list with the user storage accounts list\n * @param options - parameters used for syncing the internal accounts list with the user storage accounts list\n */\nexport async function syncInternalAccountsWithUserStorage(\n config: SyncInternalAccountsWithUserStorageConfig,\n options: AccountSyncingOptions,\n): Promise<void> {\n const { isAccountSyncingEnabled } = config;\n\n if (!canPerformAccountSyncing(config, options) || !isAccountSyncingEnabled) {\n return;\n }\n\n const {\n maxNumberOfAccountsToAdd = 100,\n onAccountAdded,\n onAccountNameUpdated,\n onAccountSyncErroneousSituation,\n } = config;\n const { getMessenger, getUserStorageControllerInstance } = options;\n\n try {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n true,\n );\n\n const userStorageAccountsList = await getUserStorageAccountsList(options);\n\n if (!userStorageAccountsList || !userStorageAccountsList.length) {\n await saveInternalAccountsListToUserStorage(\n { isAccountSyncingEnabled },\n options,\n );\n await getUserStorageControllerInstance().setHasAccountSyncingSyncedAtLeastOnce(\n true,\n );\n return;\n }\n\n // Prepare an array of internal accounts to be saved to the user storage\n const internalAccountsToBeSavedToUserStorage: InternalAccount[] = [];\n\n // Compare internal accounts list with user storage accounts list\n // First step: compare lengths\n const internalAccountsList = await getInternalAccountsList(options);\n\n if (!internalAccountsList || !internalAccountsList.length) {\n throw new Error(`Failed to get internal accounts list`);\n }\n\n const hasMoreUserStorageAccountsThanInternalAccounts =\n userStorageAccountsList.length > internalAccountsList.length;\n\n // We don't want to remove existing accounts for a user\n // so we only add new accounts if the user has more accounts in user storage than internal accounts\n if (hasMoreUserStorageAccountsThanInternalAccounts) {\n const numberOfAccountsToAdd =\n Math.min(userStorageAccountsList.length, maxNumberOfAccountsToAdd) -\n internalAccountsList.length;\n\n // Create new accounts to match the user storage accounts list\n for (let i = 0; i < numberOfAccountsToAdd; i++) {\n await getMessenger().call('KeyringController:addNewAccount');\n onAccountAdded?.();\n }\n }\n\n // Second step: compare account names\n // Get the internal accounts list again since new accounts might have been added in the previous step\n const refreshedInternalAccountsList = await getInternalAccountsList(\n options,\n );\n\n const newlyAddedAccounts = refreshedInternalAccountsList.filter(\n (account) =>\n !internalAccountsList.find((a) => a.address === account.address),\n );\n\n for (const internalAccount of refreshedInternalAccountsList) {\n const userStorageAccount = userStorageAccountsList.find(\n (account) => account.a === internalAccount.address,\n );\n\n // If the account is not present in user storage\n // istanbul ignore next\n if (!userStorageAccount) {\n // If the account was just added in the previous step, skip saving it, it's likely to be a bogus account\n if (newlyAddedAccounts.includes(internalAccount)) {\n onAccountSyncErroneousSituation?.(\n 'An account was added to the internal accounts list but was not present in the user storage accounts list',\n );\n continue;\n }\n // Otherwise, it means that this internal account was present before the sync, and needs to be saved to the user storage\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // From this point on, we know that the account is present in\n // both the internal accounts list and the user storage accounts list\n\n // One or both accounts have default names\n const isInternalAccountNameDefault = isNameDefaultAccountName(\n internalAccount.metadata.name,\n );\n const isUserStorageAccountNameDefault = isNameDefaultAccountName(\n userStorageAccount.n,\n );\n\n // Internal account has default name\n if (isInternalAccountNameDefault) {\n if (!isUserStorageAccountNameDefault) {\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n },\n );\n\n onAccountNameUpdated?.();\n }\n continue;\n }\n\n // Internal account has custom name but user storage account has default name\n if (isUserStorageAccountNameDefault) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n\n // Both accounts have custom names\n\n // User storage account has a nameLastUpdatedAt timestamp\n // Note: not storing the undefined checks in constants to act as a type guard\n if (userStorageAccount.nlu !== undefined) {\n if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n const isInternalAccountNameNewer =\n internalAccount.metadata.nameLastUpdatedAt > userStorageAccount.nlu;\n\n if (isInternalAccountNameNewer) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n getMessenger().call(\n 'AccountsController:updateAccountMetadata',\n internalAccount.id,\n {\n name: userStorageAccount.n,\n nameLastUpdatedAt: userStorageAccount.nlu,\n },\n );\n\n const areInternalAndUserStorageAccountNamesEqual =\n internalAccount.metadata.name === userStorageAccount.n;\n\n if (!areInternalAndUserStorageAccountNamesEqual) {\n onAccountNameUpdated?.();\n }\n\n continue;\n } else if (internalAccount.metadata.nameLastUpdatedAt !== undefined) {\n internalAccountsToBeSavedToUserStorage.push(internalAccount);\n continue;\n }\n }\n\n // Save the internal accounts list to the user storage\n if (internalAccountsToBeSavedToUserStorage.length) {\n await getUserStorageControllerInstance().performBatchSetStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n internalAccountsToBeSavedToUserStorage.map((account) => [\n account.address,\n JSON.stringify(mapInternalAccountToUserStorageAccount(account)),\n ]),\n );\n }\n\n // In case we have corrupted user storage with accounts that don't exist in the internal accounts list\n // Delete those accounts from the user storage\n const userStorageAccountsToBeDeleted = userStorageAccountsList.filter(\n (account) =>\n !refreshedInternalAccountsList.find((a) => a.address === account.a),\n );\n\n if (userStorageAccountsToBeDeleted.length) {\n await getUserStorageControllerInstance().performBatchDeleteStorage(\n USER_STORAGE_FEATURE_NAMES.accounts,\n userStorageAccountsToBeDeleted.map((account) => account.a),\n );\n onAccountSyncErroneousSituation?.(\n 'An account was present in the user storage accounts list but was not found in the internal accounts list after the sync',\n );\n }\n\n // We do this here and not in the finally statement because we want to make sure that\n // the accounts are saved / updated / deleted at least once before we set this flag\n await getUserStorageControllerInstance().setHasAccountSyncingSyncedAtLeastOnce(\n true,\n );\n } catch (e) {\n // istanbul ignore next\n const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n throw new Error(\n `UserStorageController - failed to sync user storage accounts list - ${errorMessage}`,\n );\n } finally {\n await getUserStorageControllerInstance().setIsAccountSyncingInProgress(\n false,\n );\n }\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import type { InternalAccount } from "@metamask/keyring-internal-api";
2
+ import type { AccountSyncingConfig, AccountSyncingOptions } from "./types.cjs";
3
+ /**
4
+ * Saves an individual internal account to the user storage.
5
+ * @param internalAccount - The internal account to save
6
+ * @param config - parameters used for saving the internal account
7
+ * @param options - parameters used for saving the internal account
8
+ */
9
+ export declare function saveInternalAccountToUserStorage(internalAccount: InternalAccount, config: AccountSyncingConfig, options: AccountSyncingOptions): Promise<void>;
10
+ /**
11
+ * Saves the list of internal accounts to the user storage.
12
+ * @param config - parameters used for saving the list of internal accounts
13
+ * @param options - parameters used for saving the list of internal accounts
14
+ */
15
+ export declare function saveInternalAccountsListToUserStorage(config: AccountSyncingConfig, options: AccountSyncingOptions): Promise<void>;
16
+ type SyncInternalAccountsWithUserStorageConfig = AccountSyncingConfig & {
17
+ maxNumberOfAccountsToAdd?: number;
18
+ onAccountAdded?: () => void;
19
+ onAccountNameUpdated?: () => void;
20
+ onAccountSyncErroneousSituation?: (errorMessage: string) => void;
21
+ };
22
+ /**
23
+ * Syncs the internal accounts list with the user storage accounts list.
24
+ * This method is used to make sure that the internal accounts list is up-to-date with the user storage accounts list and vice-versa.
25
+ * It will add new accounts to the internal accounts list, update/merge conflicting names and re-upload the results in some cases to the user storage.
26
+ * @param config - parameters used for syncing the internal accounts list with the user storage accounts list
27
+ * @param options - parameters used for syncing the internal accounts list with the user storage accounts list
28
+ */
29
+ export declare function syncInternalAccountsWithUserStorage(config: SyncInternalAccountsWithUserStorageConfig, options: AccountSyncingOptions): Promise<void>;
30
+ export {};
31
+ //# sourceMappingURL=controller-integration.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller-integration.d.cts","sourceRoot":"","sources":["../../../../src/controllers/user-storage/account-syncing/controller-integration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAQtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAgB;AAO3E;;;;;GAKG;AACH,wBAAsB,gCAAgC,CACpD,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED;;;;GAIG;AACH,wBAAsB,qCAAqC,CACzD,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,KAAK,yCAAyC,GAAG,oBAAoB,GAAG;IACtE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,+BAA+B,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,yCAAyC,EACjD,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA+Mf"}