@metamask-previews/notification-services-controller 0.0.0-preview-7ff4bd7f → 0.1.0-preview-95089367

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 (44) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/dist/NotificationServicesController/NotificationServicesController.js +3 -3
  3. package/dist/NotificationServicesController/NotificationServicesController.mjs +2 -2
  4. package/dist/NotificationServicesController/index.js +4 -4
  5. package/dist/NotificationServicesController/index.mjs +3 -3
  6. package/dist/NotificationServicesController/services/onchain-notifications.js +2 -2
  7. package/dist/NotificationServicesController/services/onchain-notifications.mjs +1 -1
  8. package/dist/NotificationServicesPushController/NotificationServicesPushController.js +3 -3
  9. package/dist/NotificationServicesPushController/NotificationServicesPushController.mjs +3 -3
  10. package/dist/NotificationServicesPushController/index.js +5 -5
  11. package/dist/NotificationServicesPushController/index.mjs +4 -4
  12. package/dist/NotificationServicesPushController/services/push/push-web.js +3 -3
  13. package/dist/NotificationServicesPushController/services/push/push-web.mjs +3 -3
  14. package/dist/NotificationServicesPushController/services/services.js +3 -3
  15. package/dist/NotificationServicesPushController/services/services.mjs +3 -3
  16. package/dist/NotificationServicesPushController/utils/get-notification-message.js +3 -3
  17. package/dist/NotificationServicesPushController/utils/get-notification-message.mjs +3 -3
  18. package/dist/NotificationServicesPushController/utils/index.js +3 -3
  19. package/dist/NotificationServicesPushController/utils/index.mjs +3 -3
  20. package/dist/{chunk-3O5NGZWB.js → chunk-4KZO4UUC.js} +892 -2266
  21. package/dist/chunk-4KZO4UUC.js.map +1 -0
  22. package/dist/{chunk-IG3CMJBW.mjs → chunk-HCOBC2R5.mjs} +898 -2272
  23. package/dist/chunk-HCOBC2R5.mjs.map +1 -0
  24. package/dist/{chunk-RNE2I5IN.mjs → chunk-LFD7J7KR.mjs} +2 -2
  25. package/dist/{chunk-EG5NZ5DA.js → chunk-NXXY4CAP.js} +3 -3
  26. package/dist/{chunk-UZXBH6WS.mjs → chunk-RYAHBEX2.mjs} +2 -2
  27. package/dist/chunk-UIRZIKC3.mjs +187 -0
  28. package/dist/chunk-UIRZIKC3.mjs.map +1 -0
  29. package/dist/chunk-VOZ7Y2OO.js +187 -0
  30. package/dist/chunk-VOZ7Y2OO.js.map +1 -0
  31. package/dist/{chunk-3NF7QYJN.js → chunk-YRWUXGL3.js} +7 -7
  32. package/dist/index.js +5 -5
  33. package/dist/index.mjs +4 -4
  34. package/package.json +4 -2
  35. package/dist/chunk-3O5NGZWB.js.map +0 -1
  36. package/dist/chunk-IG3CMJBW.mjs.map +0 -1
  37. package/dist/chunk-KPO4QJHS.js +0 -965
  38. package/dist/chunk-KPO4QJHS.js.map +0 -1
  39. package/dist/chunk-ZJRT7ACU.mjs +0 -965
  40. package/dist/chunk-ZJRT7ACU.mjs.map +0 -1
  41. /package/dist/{chunk-RNE2I5IN.mjs.map → chunk-LFD7J7KR.mjs.map} +0 -0
  42. /package/dist/{chunk-EG5NZ5DA.js.map → chunk-NXXY4CAP.js.map} +0 -0
  43. /package/dist/{chunk-UZXBH6WS.mjs.map → chunk-RYAHBEX2.mjs.map} +0 -0
  44. /package/dist/{chunk-3NF7QYJN.js.map → chunk-YRWUXGL3.js.map} +0 -0
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-IKWNHNJQ.mjs";
13
13
  import {
14
14
  require_nock
15
- } from "./chunk-IG3CMJBW.mjs";
15
+ } from "./chunk-HCOBC2R5.mjs";
16
16
  import {
17
17
  __export,
18
18
  __toESM
@@ -116,4 +116,4 @@ export {
116
116
  fixtures_exports,
117
117
  NotificationServicesPushController_exports
118
118
  };
119
- //# sourceMappingURL=chunk-RNE2I5IN.mjs.map
119
+ //# sourceMappingURL=chunk-LFD7J7KR.mjs.map
@@ -12,7 +12,7 @@ var _chunkDKQBDI4Cjs = require('./chunk-DKQBDI4C.js');
12
12
  var _chunkB25TJ7KSjs = require('./chunk-B25TJ7KS.js');
13
13
 
14
14
 
15
- var _chunk3O5NGZWBjs = require('./chunk-3O5NGZWB.js');
15
+ var _chunk4KZO4UUCjs = require('./chunk-4KZO4UUC.js');
16
16
 
17
17
 
18
18
 
@@ -92,7 +92,7 @@ var getMockDeleteFCMRegistrationTokenResponse = () => {
92
92
  };
93
93
 
94
94
  // src/NotificationServicesPushController/__fixtures__/mockServices.ts
95
- var import_nock = _chunkV46WVGWNjs.__toESM.call(void 0, _chunk3O5NGZWBjs.require_nock.call(void 0, ));
95
+ var import_nock = _chunkV46WVGWNjs.__toESM.call(void 0, _chunk4KZO4UUCjs.require_nock.call(void 0, ));
96
96
  var mockEndpointGetPushNotificationLinks = (mockReply) => {
97
97
  const mockResponse = getMockRetrievePushNotificationLinksResponse();
98
98
  const reply = mockReply ?? {
@@ -116,4 +116,4 @@ var mockEndpointUpdatePushNotificationLinks = (mockReply) => {
116
116
 
117
117
 
118
118
  exports.fixtures_exports = fixtures_exports; exports.NotificationServicesPushController_exports = NotificationServicesPushController_exports;
119
- //# sourceMappingURL=chunk-EG5NZ5DA.js.map
119
+ //# sourceMappingURL=chunk-NXXY4CAP.js.map
@@ -9,7 +9,7 @@ import {
9
9
  deleteOnChainTriggers,
10
10
  getOnChainNotifications,
11
11
  markNotificationsAsRead
12
- } from "./chunk-IG3CMJBW.mjs";
12
+ } from "./chunk-UIRZIKC3.mjs";
13
13
  import {
14
14
  checkAccountsPresence,
15
15
  getAllUUIDs,
@@ -799,4 +799,4 @@ export {
799
799
  defaultState,
800
800
  NotificationServicesController
801
801
  };
802
- //# sourceMappingURL=chunk-UZXBH6WS.mjs.map
802
+ //# sourceMappingURL=chunk-RYAHBEX2.mjs.map
@@ -0,0 +1,187 @@
1
+ import {
2
+ makeApiCall,
3
+ toggleUserStorageTriggerStatus,
4
+ traverseUserStorageTriggers
5
+ } from "./chunk-SMKJEA45.mjs";
6
+
7
+ // src/NotificationServicesController/services/onchain-notifications.ts
8
+ import { UserStorageController } from "@metamask/profile-sync-controller";
9
+ import log from "loglevel";
10
+ var TRIGGER_API = "https://trigger.api.cx.metamask.io";
11
+ var NOTIFICATION_API = "https://notification.api.cx.metamask.io";
12
+ var TRIGGER_API_BATCH_ENDPOINT = `${TRIGGER_API}/api/v1/triggers/batch`;
13
+ var NOTIFICATION_API_LIST_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications`;
14
+ var NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = (page) => `${NOTIFICATION_API_LIST_ENDPOINT}?page=${page}&per_page=100`;
15
+ var NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications/mark-as-read`;
16
+ async function createOnChainTriggers(userStorage, storageKey, bearerToken, triggers) {
17
+ const triggersToCreate = triggers.map((t) => ({
18
+ id: t.id,
19
+ token: UserStorageController.createSHA256Hash(t.id + storageKey),
20
+ config: {
21
+ kind: t.kind,
22
+ // eslint-disable-next-line @typescript-eslint/naming-convention
23
+ chain_id: Number(t.chainId),
24
+ address: t.address
25
+ }
26
+ }));
27
+ if (triggersToCreate.length === 0) {
28
+ return;
29
+ }
30
+ const response = await makeApiCall(
31
+ bearerToken,
32
+ TRIGGER_API_BATCH_ENDPOINT,
33
+ "POST",
34
+ triggersToCreate
35
+ );
36
+ if (!response.ok) {
37
+ const errorData = await response.json().catch(() => void 0);
38
+ log.error("Error creating triggers:", errorData);
39
+ throw new Error("OnChain Notifications - unable to create triggers");
40
+ }
41
+ for (const trigger of triggersToCreate) {
42
+ toggleUserStorageTriggerStatus(
43
+ userStorage,
44
+ trigger.config.address,
45
+ String(trigger.config.chain_id),
46
+ trigger.id,
47
+ true
48
+ );
49
+ }
50
+ }
51
+ async function deleteOnChainTriggers(userStorage, storageKey, bearerToken, uuids) {
52
+ const triggersToDelete = uuids.map((uuid) => ({
53
+ id: uuid,
54
+ token: UserStorageController.createSHA256Hash(uuid + storageKey)
55
+ }));
56
+ try {
57
+ const response = await makeApiCall(
58
+ bearerToken,
59
+ TRIGGER_API_BATCH_ENDPOINT,
60
+ "DELETE",
61
+ triggersToDelete
62
+ );
63
+ if (!response.ok) {
64
+ throw new Error(
65
+ `Failed to delete on-chain notifications for uuids ${uuids.join(", ")}`
66
+ );
67
+ }
68
+ for (const uuid of uuids) {
69
+ for (const address in userStorage) {
70
+ if (address in userStorage) {
71
+ for (const chainId in userStorage[address]) {
72
+ if (userStorage?.[address]?.[chainId]?.[uuid]) {
73
+ delete userStorage[address][chainId][uuid];
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ const isEmpty = (obj = {}) => Object.keys(obj).length === 0;
80
+ for (const address in userStorage) {
81
+ if (address in userStorage) {
82
+ for (const chainId in userStorage[address]) {
83
+ if (isEmpty(userStorage?.[address]?.[chainId])) {
84
+ delete userStorage[address][chainId];
85
+ }
86
+ }
87
+ if (isEmpty(userStorage?.[address])) {
88
+ delete userStorage[address];
89
+ }
90
+ }
91
+ }
92
+ } catch (err) {
93
+ log.error(
94
+ `Error deleting on-chain notifications for uuids ${uuids.join(", ")}:`,
95
+ err
96
+ );
97
+ throw err;
98
+ }
99
+ return userStorage;
100
+ }
101
+ async function getOnChainNotifications(userStorage, bearerToken) {
102
+ const triggerIds = traverseUserStorageTriggers(userStorage, {
103
+ mapTrigger: (t) => {
104
+ if (!t.enabled) {
105
+ return void 0;
106
+ }
107
+ return t.id;
108
+ }
109
+ });
110
+ if (triggerIds.length === 0) {
111
+ return [];
112
+ }
113
+ const onChainNotifications = [];
114
+ const PAGE_LIMIT = 2;
115
+ for (let page = 1; page <= PAGE_LIMIT; page++) {
116
+ try {
117
+ const response = await makeApiCall(
118
+ bearerToken,
119
+ NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY(page),
120
+ "POST",
121
+ // eslint-disable-next-line @typescript-eslint/naming-convention
122
+ { trigger_ids: triggerIds }
123
+ );
124
+ const notifications = await response.json();
125
+ const transformedNotifications = notifications.map(
126
+ (n) => {
127
+ if (!n.data?.kind) {
128
+ return void 0;
129
+ }
130
+ return {
131
+ ...n,
132
+ type: n.data.kind
133
+ };
134
+ }
135
+ ).filter((n) => Boolean(n));
136
+ onChainNotifications.push(...transformedNotifications);
137
+ if (notifications.length < 100) {
138
+ page = PAGE_LIMIT + 1;
139
+ break;
140
+ }
141
+ } catch (err) {
142
+ log.error(
143
+ `Error fetching on-chain notifications for trigger IDs ${triggerIds.join(
144
+ ", "
145
+ )}:`,
146
+ err
147
+ );
148
+ }
149
+ }
150
+ return onChainNotifications;
151
+ }
152
+ async function markNotificationsAsRead(bearerToken, notificationIds) {
153
+ if (notificationIds.length === 0) {
154
+ return;
155
+ }
156
+ try {
157
+ const response = await makeApiCall(
158
+ bearerToken,
159
+ NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,
160
+ "POST",
161
+ { ids: notificationIds }
162
+ );
163
+ if (response.status !== 200) {
164
+ const errorData = await response.json().catch(() => void 0);
165
+ throw new Error(
166
+ `Error marking notifications as read: ${errorData?.message}`
167
+ );
168
+ }
169
+ } catch (err) {
170
+ log.error("Error marking notifications as read:", err);
171
+ throw err;
172
+ }
173
+ }
174
+
175
+ export {
176
+ TRIGGER_API,
177
+ NOTIFICATION_API,
178
+ TRIGGER_API_BATCH_ENDPOINT,
179
+ NOTIFICATION_API_LIST_ENDPOINT,
180
+ NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY,
181
+ NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,
182
+ createOnChainTriggers,
183
+ deleteOnChainTriggers,
184
+ getOnChainNotifications,
185
+ markNotificationsAsRead
186
+ };
187
+ //# sourceMappingURL=chunk-UIRZIKC3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/NotificationServicesController/services/onchain-notifications.ts"],"sourcesContent":["import { UserStorageController } from '@metamask/profile-sync-controller';\nimport log from 'loglevel';\n\nimport type { TRIGGER_TYPES } from '../constants/notification-schema';\nimport type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification';\nimport type { components } from '../types/on-chain-notification/schema';\nimport type { UserStorage } from '../types/user-storage/user-storage';\nimport {\n traverseUserStorageTriggers,\n toggleUserStorageTriggerStatus,\n makeApiCall,\n} from '../utils/utils';\n\nexport type NotificationTrigger = {\n id: string;\n chainId: string;\n kind: string;\n address: string;\n};\n\nexport const TRIGGER_API = 'https://trigger.api.cx.metamask.io';\nexport const NOTIFICATION_API = 'https://notification.api.cx.metamask.io';\nexport const TRIGGER_API_BATCH_ENDPOINT = `${TRIGGER_API}/api/v1/triggers/batch`;\nexport const NOTIFICATION_API_LIST_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications`;\nexport const NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = (page: number) =>\n `${NOTIFICATION_API_LIST_ENDPOINT}?page=${page}&per_page=100`;\nexport const NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications/mark-as-read`;\n\n/**\n * Creates on-chain triggers based on the provided notification triggers.\n * This method generates a unique token for each trigger using the trigger ID and storage key,\n * proving ownership of the trigger being updated. It then makes an API call to create these triggers.\n * Upon successful creation, it updates the userStorage to reflect the new trigger status.\n *\n * @param userStorage - The user's storage object where triggers and their statuses are stored.\n * @param storageKey - A key used along with the trigger ID to generate a unique token for each trigger.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param triggers - An array of notification triggers to be created. Each trigger includes an ID, chain ID, kind, and address.\n * @returns A promise that resolves to void. Throws an error if the API call fails or if there's an issue creating the triggers.\n */\nexport async function createOnChainTriggers(\n userStorage: UserStorage,\n storageKey: string,\n bearerToken: string,\n triggers: NotificationTrigger[],\n): Promise<void> {\n type RequestPayloadTrigger = {\n id: string;\n // this is the trigger token, generated by using the uuid + storage key. It proves you own the trigger you are updating\n token: string;\n config: {\n kind: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n chain_id: number;\n address: string;\n };\n };\n const triggersToCreate: RequestPayloadTrigger[] = triggers.map((t) => ({\n id: t.id,\n token: UserStorageController.createSHA256Hash(t.id + storageKey),\n config: {\n kind: t.kind,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n chain_id: Number(t.chainId),\n address: t.address,\n },\n }));\n\n if (triggersToCreate.length === 0) {\n return;\n }\n\n const response = await makeApiCall(\n bearerToken,\n TRIGGER_API_BATCH_ENDPOINT,\n 'POST',\n triggersToCreate,\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => undefined);\n log.error('Error creating triggers:', errorData);\n throw new Error('OnChain Notifications - unable to create triggers');\n }\n\n // If the trigger creation was fine\n // then update the userStorage\n for (const trigger of triggersToCreate) {\n toggleUserStorageTriggerStatus(\n userStorage,\n trigger.config.address,\n String(trigger.config.chain_id),\n trigger.id,\n true,\n );\n }\n}\n\n/**\n * Deletes on-chain triggers based on the provided UUIDs.\n * This method generates a unique token for each trigger using the UUID and storage key,\n * proving ownership of the trigger being deleted. It then makes an API call to delete these triggers.\n * Upon successful deletion, it updates the userStorage to remove the deleted trigger statuses.\n *\n * @param userStorage - The user's storage object where triggers and their statuses are stored.\n * @param storageKey - A key used along with the UUID to generate a unique token for each trigger.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param uuids - An array of UUIDs representing the triggers to be deleted.\n * @returns A promise that resolves to the updated UserStorage object. Throws an error if the API call fails or if there's an issue deleting the triggers.\n */\nexport async function deleteOnChainTriggers(\n userStorage: UserStorage,\n storageKey: string,\n bearerToken: string,\n uuids: string[],\n): Promise<UserStorage> {\n const triggersToDelete = uuids.map((uuid) => ({\n id: uuid,\n token: UserStorageController.createSHA256Hash(uuid + storageKey),\n }));\n\n try {\n const response = await makeApiCall(\n bearerToken,\n TRIGGER_API_BATCH_ENDPOINT,\n 'DELETE',\n triggersToDelete,\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to delete on-chain notifications for uuids ${uuids.join(', ')}`,\n );\n }\n\n // Update the state of the deleted trigger to false\n for (const uuid of uuids) {\n for (const address in userStorage) {\n if (address in userStorage) {\n for (const chainId in userStorage[address]) {\n if (userStorage?.[address]?.[chainId]?.[uuid]) {\n delete userStorage[address][chainId][uuid];\n }\n }\n }\n }\n }\n\n // Follow-up cleanup, if an address had no triggers whatsoever, then we can delete the address\n const isEmpty = (obj = {}) => Object.keys(obj).length === 0;\n for (const address in userStorage) {\n if (address in userStorage) {\n for (const chainId in userStorage[address]) {\n // Chain isEmpty Check\n if (isEmpty(userStorage?.[address]?.[chainId])) {\n delete userStorage[address][chainId];\n }\n }\n\n // Address isEmpty Check\n if (isEmpty(userStorage?.[address])) {\n delete userStorage[address];\n }\n }\n }\n } catch (err) {\n log.error(\n `Error deleting on-chain notifications for uuids ${uuids.join(', ')}:`,\n err,\n );\n throw err;\n }\n\n return userStorage;\n}\n\n/**\n * Fetches on-chain notifications for the given user storage and BearerToken.\n * This method iterates through the userStorage to find enabled triggers and fetches notifications for those triggers.\n * It makes paginated API calls to the notifications service, transforming and aggregating the notifications into a single array.\n * The process stops either when all pages have been fetched or when a page has less than 100 notifications, indicating the end of the data.\n *\n * @param userStorage - The user's storage object containing trigger information.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @returns A promise that resolves to an array of OnChainRawNotification objects. If no triggers are enabled or an error occurs, it may return an empty array.\n */\nexport async function getOnChainNotifications(\n userStorage: UserStorage,\n bearerToken: string,\n): Promise<OnChainRawNotification[]> {\n const triggerIds = traverseUserStorageTriggers(userStorage, {\n mapTrigger: (t) => {\n if (!t.enabled) {\n return undefined;\n }\n return t.id;\n },\n });\n\n if (triggerIds.length === 0) {\n return [];\n }\n\n const onChainNotifications: OnChainRawNotification[] = [];\n const PAGE_LIMIT = 2;\n for (let page = 1; page <= PAGE_LIMIT; page++) {\n try {\n const response = await makeApiCall(\n bearerToken,\n NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY(page),\n 'POST',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n { trigger_ids: triggerIds },\n );\n\n const notifications = (await response.json()) as OnChainRawNotification[];\n\n // Transform and sort notifications\n const transformedNotifications = notifications\n .map(\n (\n n: components['schemas']['Notification'],\n ): OnChainRawNotification | undefined => {\n if (!n.data?.kind) {\n return undefined;\n }\n\n return {\n ...n,\n type: n.data.kind as TRIGGER_TYPES,\n } as OnChainRawNotification;\n },\n )\n .filter((n): n is OnChainRawNotification => Boolean(n));\n\n onChainNotifications.push(...transformedNotifications);\n\n // if less than 100 notifications on page, then means we reached end\n if (notifications.length < 100) {\n page = PAGE_LIMIT + 1;\n break;\n }\n } catch (err) {\n log.error(\n `Error fetching on-chain notifications for trigger IDs ${triggerIds.join(\n ', ',\n )}:`,\n err,\n );\n // do nothing\n }\n }\n\n return onChainNotifications;\n}\n\n/**\n * Marks the specified notifications as read.\n * This method sends a POST request to the notifications service to mark the provided notification IDs as read.\n * If the operation is successful, it completes without error. If the operation fails, it throws an error with details.\n *\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param notificationIds - An array of notification IDs to be marked as read.\n * @returns A promise that resolves to void. The promise will reject if there's an error during the API call or if the response status is not 200.\n */\nexport async function markNotificationsAsRead(\n bearerToken: string,\n notificationIds: string[],\n): Promise<void> {\n if (notificationIds.length === 0) {\n return;\n }\n\n try {\n const response = await makeApiCall(\n bearerToken,\n NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,\n 'POST',\n { ids: notificationIds },\n );\n\n if (response.status !== 200) {\n const errorData = await response.json().catch(() => undefined);\n throw new Error(\n `Error marking notifications as read: ${errorData?.message as string}`,\n );\n }\n } catch (err) {\n log.error('Error marking notifications as read:', err);\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,187 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
+
3
+
4
+
5
+ var _chunkPIZCE3JDjs = require('./chunk-PIZCE3JD.js');
6
+
7
+ // src/NotificationServicesController/services/onchain-notifications.ts
8
+ var _profilesynccontroller = require('@metamask/profile-sync-controller');
9
+ var _loglevel = require('loglevel'); var _loglevel2 = _interopRequireDefault(_loglevel);
10
+ var TRIGGER_API = "https://trigger.api.cx.metamask.io";
11
+ var NOTIFICATION_API = "https://notification.api.cx.metamask.io";
12
+ var TRIGGER_API_BATCH_ENDPOINT = `${TRIGGER_API}/api/v1/triggers/batch`;
13
+ var NOTIFICATION_API_LIST_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications`;
14
+ var NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = (page) => `${NOTIFICATION_API_LIST_ENDPOINT}?page=${page}&per_page=100`;
15
+ var NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications/mark-as-read`;
16
+ async function createOnChainTriggers(userStorage, storageKey, bearerToken, triggers) {
17
+ const triggersToCreate = triggers.map((t) => ({
18
+ id: t.id,
19
+ token: _profilesynccontroller.UserStorageController.createSHA256Hash(t.id + storageKey),
20
+ config: {
21
+ kind: t.kind,
22
+ // eslint-disable-next-line @typescript-eslint/naming-convention
23
+ chain_id: Number(t.chainId),
24
+ address: t.address
25
+ }
26
+ }));
27
+ if (triggersToCreate.length === 0) {
28
+ return;
29
+ }
30
+ const response = await _chunkPIZCE3JDjs.makeApiCall.call(void 0,
31
+ bearerToken,
32
+ TRIGGER_API_BATCH_ENDPOINT,
33
+ "POST",
34
+ triggersToCreate
35
+ );
36
+ if (!response.ok) {
37
+ const errorData = await response.json().catch(() => void 0);
38
+ _loglevel2.default.error("Error creating triggers:", errorData);
39
+ throw new Error("OnChain Notifications - unable to create triggers");
40
+ }
41
+ for (const trigger of triggersToCreate) {
42
+ _chunkPIZCE3JDjs.toggleUserStorageTriggerStatus.call(void 0,
43
+ userStorage,
44
+ trigger.config.address,
45
+ String(trigger.config.chain_id),
46
+ trigger.id,
47
+ true
48
+ );
49
+ }
50
+ }
51
+ async function deleteOnChainTriggers(userStorage, storageKey, bearerToken, uuids) {
52
+ const triggersToDelete = uuids.map((uuid) => ({
53
+ id: uuid,
54
+ token: _profilesynccontroller.UserStorageController.createSHA256Hash(uuid + storageKey)
55
+ }));
56
+ try {
57
+ const response = await _chunkPIZCE3JDjs.makeApiCall.call(void 0,
58
+ bearerToken,
59
+ TRIGGER_API_BATCH_ENDPOINT,
60
+ "DELETE",
61
+ triggersToDelete
62
+ );
63
+ if (!response.ok) {
64
+ throw new Error(
65
+ `Failed to delete on-chain notifications for uuids ${uuids.join(", ")}`
66
+ );
67
+ }
68
+ for (const uuid of uuids) {
69
+ for (const address in userStorage) {
70
+ if (address in userStorage) {
71
+ for (const chainId in userStorage[address]) {
72
+ if (userStorage?.[address]?.[chainId]?.[uuid]) {
73
+ delete userStorage[address][chainId][uuid];
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ const isEmpty = (obj = {}) => Object.keys(obj).length === 0;
80
+ for (const address in userStorage) {
81
+ if (address in userStorage) {
82
+ for (const chainId in userStorage[address]) {
83
+ if (isEmpty(userStorage?.[address]?.[chainId])) {
84
+ delete userStorage[address][chainId];
85
+ }
86
+ }
87
+ if (isEmpty(userStorage?.[address])) {
88
+ delete userStorage[address];
89
+ }
90
+ }
91
+ }
92
+ } catch (err) {
93
+ _loglevel2.default.error(
94
+ `Error deleting on-chain notifications for uuids ${uuids.join(", ")}:`,
95
+ err
96
+ );
97
+ throw err;
98
+ }
99
+ return userStorage;
100
+ }
101
+ async function getOnChainNotifications(userStorage, bearerToken) {
102
+ const triggerIds = _chunkPIZCE3JDjs.traverseUserStorageTriggers.call(void 0, userStorage, {
103
+ mapTrigger: (t) => {
104
+ if (!t.enabled) {
105
+ return void 0;
106
+ }
107
+ return t.id;
108
+ }
109
+ });
110
+ if (triggerIds.length === 0) {
111
+ return [];
112
+ }
113
+ const onChainNotifications = [];
114
+ const PAGE_LIMIT = 2;
115
+ for (let page = 1; page <= PAGE_LIMIT; page++) {
116
+ try {
117
+ const response = await _chunkPIZCE3JDjs.makeApiCall.call(void 0,
118
+ bearerToken,
119
+ NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY(page),
120
+ "POST",
121
+ // eslint-disable-next-line @typescript-eslint/naming-convention
122
+ { trigger_ids: triggerIds }
123
+ );
124
+ const notifications = await response.json();
125
+ const transformedNotifications = notifications.map(
126
+ (n) => {
127
+ if (!n.data?.kind) {
128
+ return void 0;
129
+ }
130
+ return {
131
+ ...n,
132
+ type: n.data.kind
133
+ };
134
+ }
135
+ ).filter((n) => Boolean(n));
136
+ onChainNotifications.push(...transformedNotifications);
137
+ if (notifications.length < 100) {
138
+ page = PAGE_LIMIT + 1;
139
+ break;
140
+ }
141
+ } catch (err) {
142
+ _loglevel2.default.error(
143
+ `Error fetching on-chain notifications for trigger IDs ${triggerIds.join(
144
+ ", "
145
+ )}:`,
146
+ err
147
+ );
148
+ }
149
+ }
150
+ return onChainNotifications;
151
+ }
152
+ async function markNotificationsAsRead(bearerToken, notificationIds) {
153
+ if (notificationIds.length === 0) {
154
+ return;
155
+ }
156
+ try {
157
+ const response = await _chunkPIZCE3JDjs.makeApiCall.call(void 0,
158
+ bearerToken,
159
+ NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,
160
+ "POST",
161
+ { ids: notificationIds }
162
+ );
163
+ if (response.status !== 200) {
164
+ const errorData = await response.json().catch(() => void 0);
165
+ throw new Error(
166
+ `Error marking notifications as read: ${errorData?.message}`
167
+ );
168
+ }
169
+ } catch (err) {
170
+ _loglevel2.default.error("Error marking notifications as read:", err);
171
+ throw err;
172
+ }
173
+ }
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+ exports.TRIGGER_API = TRIGGER_API; exports.NOTIFICATION_API = NOTIFICATION_API; exports.TRIGGER_API_BATCH_ENDPOINT = TRIGGER_API_BATCH_ENDPOINT; exports.NOTIFICATION_API_LIST_ENDPOINT = NOTIFICATION_API_LIST_ENDPOINT; exports.NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY; exports.NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT; exports.createOnChainTriggers = createOnChainTriggers; exports.deleteOnChainTriggers = deleteOnChainTriggers; exports.getOnChainNotifications = getOnChainNotifications; exports.markNotificationsAsRead = markNotificationsAsRead;
187
+ //# sourceMappingURL=chunk-VOZ7Y2OO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/NotificationServicesController/services/onchain-notifications.ts"],"names":[],"mappings":"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","sourcesContent":["import { UserStorageController } from '@metamask/profile-sync-controller';\nimport log from 'loglevel';\n\nimport type { TRIGGER_TYPES } from '../constants/notification-schema';\nimport type { OnChainRawNotification } from '../types/on-chain-notification/on-chain-notification';\nimport type { components } from '../types/on-chain-notification/schema';\nimport type { UserStorage } from '../types/user-storage/user-storage';\nimport {\n traverseUserStorageTriggers,\n toggleUserStorageTriggerStatus,\n makeApiCall,\n} from '../utils/utils';\n\nexport type NotificationTrigger = {\n id: string;\n chainId: string;\n kind: string;\n address: string;\n};\n\nexport const TRIGGER_API = 'https://trigger.api.cx.metamask.io';\nexport const NOTIFICATION_API = 'https://notification.api.cx.metamask.io';\nexport const TRIGGER_API_BATCH_ENDPOINT = `${TRIGGER_API}/api/v1/triggers/batch`;\nexport const NOTIFICATION_API_LIST_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications`;\nexport const NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY = (page: number) =>\n `${NOTIFICATION_API_LIST_ENDPOINT}?page=${page}&per_page=100`;\nexport const NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT = `${NOTIFICATION_API}/api/v1/notifications/mark-as-read`;\n\n/**\n * Creates on-chain triggers based on the provided notification triggers.\n * This method generates a unique token for each trigger using the trigger ID and storage key,\n * proving ownership of the trigger being updated. It then makes an API call to create these triggers.\n * Upon successful creation, it updates the userStorage to reflect the new trigger status.\n *\n * @param userStorage - The user's storage object where triggers and their statuses are stored.\n * @param storageKey - A key used along with the trigger ID to generate a unique token for each trigger.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param triggers - An array of notification triggers to be created. Each trigger includes an ID, chain ID, kind, and address.\n * @returns A promise that resolves to void. Throws an error if the API call fails or if there's an issue creating the triggers.\n */\nexport async function createOnChainTriggers(\n userStorage: UserStorage,\n storageKey: string,\n bearerToken: string,\n triggers: NotificationTrigger[],\n): Promise<void> {\n type RequestPayloadTrigger = {\n id: string;\n // this is the trigger token, generated by using the uuid + storage key. It proves you own the trigger you are updating\n token: string;\n config: {\n kind: string;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n chain_id: number;\n address: string;\n };\n };\n const triggersToCreate: RequestPayloadTrigger[] = triggers.map((t) => ({\n id: t.id,\n token: UserStorageController.createSHA256Hash(t.id + storageKey),\n config: {\n kind: t.kind,\n // eslint-disable-next-line @typescript-eslint/naming-convention\n chain_id: Number(t.chainId),\n address: t.address,\n },\n }));\n\n if (triggersToCreate.length === 0) {\n return;\n }\n\n const response = await makeApiCall(\n bearerToken,\n TRIGGER_API_BATCH_ENDPOINT,\n 'POST',\n triggersToCreate,\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => undefined);\n log.error('Error creating triggers:', errorData);\n throw new Error('OnChain Notifications - unable to create triggers');\n }\n\n // If the trigger creation was fine\n // then update the userStorage\n for (const trigger of triggersToCreate) {\n toggleUserStorageTriggerStatus(\n userStorage,\n trigger.config.address,\n String(trigger.config.chain_id),\n trigger.id,\n true,\n );\n }\n}\n\n/**\n * Deletes on-chain triggers based on the provided UUIDs.\n * This method generates a unique token for each trigger using the UUID and storage key,\n * proving ownership of the trigger being deleted. It then makes an API call to delete these triggers.\n * Upon successful deletion, it updates the userStorage to remove the deleted trigger statuses.\n *\n * @param userStorage - The user's storage object where triggers and their statuses are stored.\n * @param storageKey - A key used along with the UUID to generate a unique token for each trigger.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param uuids - An array of UUIDs representing the triggers to be deleted.\n * @returns A promise that resolves to the updated UserStorage object. Throws an error if the API call fails or if there's an issue deleting the triggers.\n */\nexport async function deleteOnChainTriggers(\n userStorage: UserStorage,\n storageKey: string,\n bearerToken: string,\n uuids: string[],\n): Promise<UserStorage> {\n const triggersToDelete = uuids.map((uuid) => ({\n id: uuid,\n token: UserStorageController.createSHA256Hash(uuid + storageKey),\n }));\n\n try {\n const response = await makeApiCall(\n bearerToken,\n TRIGGER_API_BATCH_ENDPOINT,\n 'DELETE',\n triggersToDelete,\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to delete on-chain notifications for uuids ${uuids.join(', ')}`,\n );\n }\n\n // Update the state of the deleted trigger to false\n for (const uuid of uuids) {\n for (const address in userStorage) {\n if (address in userStorage) {\n for (const chainId in userStorage[address]) {\n if (userStorage?.[address]?.[chainId]?.[uuid]) {\n delete userStorage[address][chainId][uuid];\n }\n }\n }\n }\n }\n\n // Follow-up cleanup, if an address had no triggers whatsoever, then we can delete the address\n const isEmpty = (obj = {}) => Object.keys(obj).length === 0;\n for (const address in userStorage) {\n if (address in userStorage) {\n for (const chainId in userStorage[address]) {\n // Chain isEmpty Check\n if (isEmpty(userStorage?.[address]?.[chainId])) {\n delete userStorage[address][chainId];\n }\n }\n\n // Address isEmpty Check\n if (isEmpty(userStorage?.[address])) {\n delete userStorage[address];\n }\n }\n }\n } catch (err) {\n log.error(\n `Error deleting on-chain notifications for uuids ${uuids.join(', ')}:`,\n err,\n );\n throw err;\n }\n\n return userStorage;\n}\n\n/**\n * Fetches on-chain notifications for the given user storage and BearerToken.\n * This method iterates through the userStorage to find enabled triggers and fetches notifications for those triggers.\n * It makes paginated API calls to the notifications service, transforming and aggregating the notifications into a single array.\n * The process stops either when all pages have been fetched or when a page has less than 100 notifications, indicating the end of the data.\n *\n * @param userStorage - The user's storage object containing trigger information.\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @returns A promise that resolves to an array of OnChainRawNotification objects. If no triggers are enabled or an error occurs, it may return an empty array.\n */\nexport async function getOnChainNotifications(\n userStorage: UserStorage,\n bearerToken: string,\n): Promise<OnChainRawNotification[]> {\n const triggerIds = traverseUserStorageTriggers(userStorage, {\n mapTrigger: (t) => {\n if (!t.enabled) {\n return undefined;\n }\n return t.id;\n },\n });\n\n if (triggerIds.length === 0) {\n return [];\n }\n\n const onChainNotifications: OnChainRawNotification[] = [];\n const PAGE_LIMIT = 2;\n for (let page = 1; page <= PAGE_LIMIT; page++) {\n try {\n const response = await makeApiCall(\n bearerToken,\n NOTIFICATION_API_LIST_ENDPOINT_PAGE_QUERY(page),\n 'POST',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n { trigger_ids: triggerIds },\n );\n\n const notifications = (await response.json()) as OnChainRawNotification[];\n\n // Transform and sort notifications\n const transformedNotifications = notifications\n .map(\n (\n n: components['schemas']['Notification'],\n ): OnChainRawNotification | undefined => {\n if (!n.data?.kind) {\n return undefined;\n }\n\n return {\n ...n,\n type: n.data.kind as TRIGGER_TYPES,\n } as OnChainRawNotification;\n },\n )\n .filter((n): n is OnChainRawNotification => Boolean(n));\n\n onChainNotifications.push(...transformedNotifications);\n\n // if less than 100 notifications on page, then means we reached end\n if (notifications.length < 100) {\n page = PAGE_LIMIT + 1;\n break;\n }\n } catch (err) {\n log.error(\n `Error fetching on-chain notifications for trigger IDs ${triggerIds.join(\n ', ',\n )}:`,\n err,\n );\n // do nothing\n }\n }\n\n return onChainNotifications;\n}\n\n/**\n * Marks the specified notifications as read.\n * This method sends a POST request to the notifications service to mark the provided notification IDs as read.\n * If the operation is successful, it completes without error. If the operation fails, it throws an error with details.\n *\n * @param bearerToken - The JSON Web Token used for authentication in the API call.\n * @param notificationIds - An array of notification IDs to be marked as read.\n * @returns A promise that resolves to void. The promise will reject if there's an error during the API call or if the response status is not 200.\n */\nexport async function markNotificationsAsRead(\n bearerToken: string,\n notificationIds: string[],\n): Promise<void> {\n if (notificationIds.length === 0) {\n return;\n }\n\n try {\n const response = await makeApiCall(\n bearerToken,\n NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,\n 'POST',\n { ids: notificationIds },\n );\n\n if (response.status !== 200) {\n const errorData = await response.json().catch(() => undefined);\n throw new Error(\n `Error marking notifications as read: ${errorData?.message as string}`,\n );\n }\n } catch (err) {\n log.error('Error marking notifications as read:', err);\n throw err;\n }\n}\n"]}
@@ -9,7 +9,7 @@ var _chunkZMNXLHACjs = require('./chunk-ZMNXLHAC.js');
9
9
 
10
10
 
11
11
 
12
- var _chunk3O5NGZWBjs = require('./chunk-3O5NGZWB.js');
12
+ var _chunkVOZ7Y2OOjs = require('./chunk-VOZ7Y2OO.js');
13
13
 
14
14
 
15
15
 
@@ -390,7 +390,7 @@ var NotificationServicesController = class extends _basecontroller.BaseControlle
390
390
  await _chunkV46WVGWNjs.__privateGet.call(void 0, this, _storage).setNotificationStorage(JSON.stringify(userStorage));
391
391
  }
392
392
  const triggers = _chunkPIZCE3JDjs.traverseUserStorageTriggers.call(void 0, userStorage);
393
- await _chunk3O5NGZWBjs.createOnChainTriggers.call(void 0,
393
+ await _chunkVOZ7Y2OOjs.createOnChainTriggers.call(void 0,
394
394
  userStorage,
395
395
  storageKey,
396
396
  bearerToken,
@@ -484,7 +484,7 @@ var NotificationServicesController = class extends _basecontroller.BaseControlle
484
484
  if (UUIDs.length === 0) {
485
485
  return userStorage;
486
486
  }
487
- await _chunk3O5NGZWBjs.deleteOnChainTriggers.call(void 0,
487
+ await _chunkVOZ7Y2OOjs.deleteOnChainTriggers.call(void 0,
488
488
  userStorage,
489
489
  storageKey,
490
490
  bearerToken,
@@ -540,7 +540,7 @@ var NotificationServicesController = class extends _basecontroller.BaseControlle
540
540
  return void 0;
541
541
  }
542
542
  });
543
- await _chunk3O5NGZWBjs.createOnChainTriggers.call(void 0,
543
+ await _chunkVOZ7Y2OOjs.createOnChainTriggers.call(void 0,
544
544
  userStorage,
545
545
  storageKey,
546
546
  bearerToken,
@@ -576,7 +576,7 @@ var NotificationServicesController = class extends _basecontroller.BaseControlle
576
576
  const userStorage = await _chunkV46WVGWNjs.__privateGet.call(void 0, this, _storage).getNotificationStorage().then((s) => s && JSON.parse(s)).catch(() => null);
577
577
  const bearerToken = await _chunkV46WVGWNjs.__privateGet.call(void 0, this, _auth).getBearerToken().catch(() => null);
578
578
  if (userStorage && bearerToken) {
579
- const notifications = await _chunk3O5NGZWBjs.getOnChainNotifications.call(void 0,
579
+ const notifications = await _chunkVOZ7Y2OOjs.getOnChainNotifications.call(void 0,
580
580
  userStorage,
581
581
  bearerToken
582
582
  ).catch(() => []);
@@ -629,7 +629,7 @@ var NotificationServicesController = class extends _basecontroller.BaseControlle
629
629
  onchainNotificationIds = onChainNotifications.map(
630
630
  (notification) => notification.id
631
631
  );
632
- await _chunk3O5NGZWBjs.markNotificationsAsRead.call(void 0,
632
+ await _chunkVOZ7Y2OOjs.markNotificationsAsRead.call(void 0,
633
633
  bearerToken,
634
634
  onchainNotificationIds
635
635
  ).catch(() => {
@@ -799,4 +799,4 @@ clearUpdatingAccountsState_fn = function(accounts) {
799
799
 
800
800
 
801
801
  exports.defaultState = defaultState; exports.NotificationServicesController = NotificationServicesController;
802
- //# sourceMappingURL=chunk-3NF7QYJN.js.map
802
+ //# sourceMappingURL=chunk-YRWUXGL3.js.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkEG5NZ5DAjs = require('./chunk-EG5NZ5DA.js');
3
+ var _chunkNXXY4CAPjs = require('./chunk-NXXY4CAP.js');
4
4
  require('./chunk-FFQNSBPU.js');
5
5
  require('./chunk-7LWR54U7.js');
6
6
  require('./chunk-GETQWOTI.js');
@@ -12,7 +12,7 @@ require('./chunk-NJBJIZLR.js');
12
12
  require('./chunk-B25TJ7KS.js');
13
13
 
14
14
 
15
- var _chunkKPO4QJHSjs = require('./chunk-KPO4QJHS.js');
15
+ var _chunk4KZO4UUCjs = require('./chunk-4KZO4UUC.js');
16
16
  require('./chunk-UPVIT75F.js');
17
17
  require('./chunk-232HZSEV.js');
18
18
  require('./chunk-IPI7BAW3.js');
@@ -25,12 +25,12 @@ require('./chunk-XZEVRYUE.js');
25
25
  require('./chunk-3ZS2HAEG.js');
26
26
  require('./chunk-ZV3DFBO4.js');
27
27
  require('./chunk-DMH4NSLF.js');
28
- require('./chunk-3NF7QYJN.js');
28
+ require('./chunk-YRWUXGL3.js');
29
29
  require('./chunk-GFAESVZA.js');
30
30
  require('./chunk-LYEXYTOI.js');
31
31
  require('./chunk-ZMNXLHAC.js');
32
32
  require('./chunk-52CALMRA.js');
33
- require('./chunk-3O5NGZWB.js');
33
+ require('./chunk-VOZ7Y2OO.js');
34
34
  require('./chunk-PIZCE3JD.js');
35
35
  require('./chunk-CQ6CGSKZ.js');
36
36
  require('./chunk-DY4ELDRQ.js');
@@ -39,5 +39,5 @@ require('./chunk-V46WVGWN.js');
39
39
 
40
40
 
41
41
 
42
- exports.NotificationServicesController = _chunkKPO4QJHSjs.NotificationServicesController_exports; exports.NotificationsServicesPushController = _chunkEG5NZ5DAjs.NotificationServicesPushController_exports;
42
+ exports.NotificationServicesController = _chunk4KZO4UUCjs.NotificationServicesController_exports; exports.NotificationsServicesPushController = _chunkNXXY4CAPjs.NotificationServicesPushController_exports;
43
43
  //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NotificationServicesPushController_exports
3
- } from "./chunk-RNE2I5IN.mjs";
3
+ } from "./chunk-LFD7J7KR.mjs";
4
4
  import "./chunk-JLHFZ2UG.mjs";
5
5
  import "./chunk-IOMDG67D.mjs";
6
6
  import "./chunk-RAUV5UV4.mjs";
@@ -12,7 +12,7 @@ import "./chunk-52NKJDI2.mjs";
12
12
  import "./chunk-IKWNHNJQ.mjs";
13
13
  import {
14
14
  NotificationServicesController_exports
15
- } from "./chunk-ZJRT7ACU.mjs";
15
+ } from "./chunk-HCOBC2R5.mjs";
16
16
  import "./chunk-QTK2RMF7.mjs";
17
17
  import "./chunk-B4ECJJ5C.mjs";
18
18
  import "./chunk-4QXAPVW3.mjs";
@@ -25,12 +25,12 @@ import "./chunk-U74Q3BRP.mjs";
25
25
  import "./chunk-G52DNXFH.mjs";
26
26
  import "./chunk-7RM3YNTD.mjs";
27
27
  import "./chunk-PNCS6GEX.mjs";
28
- import "./chunk-UZXBH6WS.mjs";
28
+ import "./chunk-RYAHBEX2.mjs";
29
29
  import "./chunk-RQWUD2FB.mjs";
30
30
  import "./chunk-BONB66A2.mjs";
31
31
  import "./chunk-EQWVJX6K.mjs";
32
32
  import "./chunk-D42BBXBM.mjs";
33
- import "./chunk-IG3CMJBW.mjs";
33
+ import "./chunk-UIRZIKC3.mjs";
34
34
  import "./chunk-SMKJEA45.mjs";
35
35
  import "./chunk-VE4DTN4R.mjs";
36
36
  import "./chunk-VC6J62JI.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/notification-services-controller",
3
- "version": "0.0.0-preview-7ff4bd7f",
3
+ "version": "0.1.0-preview-95089367",
4
4
  "description": "Manages New MetaMask decentralized Notification system",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -45,6 +45,7 @@
45
45
  "@metamask/base-controller": "^6.0.0",
46
46
  "@metamask/controller-utils": "^11.0.0",
47
47
  "@metamask/keyring-controller": "^17.1.0",
48
+ "@metamask/profile-sync-controller": "^0.1.0",
48
49
  "bignumber.js": "^4.1.0",
49
50
  "contentful": "^10.3.6",
50
51
  "firebase": "^10.11.0",
@@ -66,7 +67,8 @@
66
67
  "typescript": "~4.9.5"
67
68
  },
68
69
  "peerDependencies": {
69
- "@metamask/keyring-controller": "^17.0.0"
70
+ "@metamask/keyring-controller": "^17.0.0",
71
+ "@metamask/profile-sync-controller": "^0.1.0"
70
72
  },
71
73
  "engines": {
72
74
  "node": "^18.18 || >=20"