@metamask-previews/notification-services-controller 0.2.0-preview-c081c503 → 0.2.0-preview-f59de5e

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 (75) hide show
  1. package/dist/NotificationServicesController/NotificationServicesController.js +4 -3
  2. package/dist/NotificationServicesController/NotificationServicesController.mjs +3 -2
  3. package/dist/NotificationServicesController/index.js +17 -16
  4. package/dist/NotificationServicesController/index.mjs +16 -15
  5. package/dist/NotificationServicesController/services/onchain-notifications.js +3 -2
  6. package/dist/NotificationServicesController/services/onchain-notifications.mjs +2 -1
  7. package/dist/NotificationServicesController/types/index.js +2 -2
  8. package/dist/NotificationServicesController/types/index.mjs +2 -2
  9. package/dist/NotificationServicesPushController/NotificationServicesPushController.js +14 -13
  10. package/dist/NotificationServicesPushController/NotificationServicesPushController.mjs +13 -12
  11. package/dist/NotificationServicesPushController/index.js +18 -17
  12. package/dist/NotificationServicesPushController/index.mjs +17 -16
  13. package/dist/NotificationServicesPushController/services/push/push-web.js +12 -11
  14. package/dist/NotificationServicesPushController/services/push/push-web.mjs +11 -10
  15. package/dist/NotificationServicesPushController/services/services.js +13 -12
  16. package/dist/NotificationServicesPushController/services/services.mjs +12 -11
  17. package/dist/NotificationServicesPushController/utils/get-notification-message.js +10 -9
  18. package/dist/NotificationServicesPushController/utils/get-notification-message.mjs +10 -9
  19. package/dist/NotificationServicesPushController/utils/index.js +10 -9
  20. package/dist/NotificationServicesPushController/utils/index.mjs +10 -9
  21. package/dist/{chunk-MT4VCZEE.js → chunk-2BCJRWFF.js} +6 -6
  22. package/dist/{chunk-CGQRVA4Q.js → chunk-323GXNRE.js} +53 -8
  23. package/dist/chunk-323GXNRE.js.map +1 -0
  24. package/dist/{chunk-GJHW5Z65.js → chunk-4HOEZMSV.js} +4 -4
  25. package/dist/{chunk-5TUHE2FM.js → chunk-6GXEFQ64.js} +11 -11
  26. package/dist/chunk-6GXEFQ64.js.map +1 -0
  27. package/dist/chunk-DINCLRZT.mjs +12 -0
  28. package/dist/chunk-DINCLRZT.mjs.map +1 -0
  29. package/dist/chunk-DT6SLUWJ.js +12 -0
  30. package/dist/chunk-DT6SLUWJ.js.map +1 -0
  31. package/dist/{chunk-EZHMYHBX.mjs → chunk-FN6GVBCU.mjs} +9 -11
  32. package/dist/chunk-FN6GVBCU.mjs.map +1 -0
  33. package/dist/{chunk-72H2V4J5.js → chunk-GDKHOBJT.js} +7 -3
  34. package/dist/chunk-GDKHOBJT.js.map +1 -0
  35. package/dist/{chunk-DNVD3CHQ.js → chunk-H73GATCU.js} +9 -11
  36. package/dist/chunk-H73GATCU.js.map +1 -0
  37. package/dist/{chunk-R373BQEU.mjs → chunk-N4EKQQX7.mjs} +5 -5
  38. package/dist/{chunk-F2X3OS5R.js → chunk-OE2TTTBQ.js} +14 -14
  39. package/dist/{chunk-DSLFFOGF.mjs → chunk-OLYCBAVW.mjs} +48 -3
  40. package/dist/chunk-OLYCBAVW.mjs.map +1 -0
  41. package/dist/{chunk-W7PLAK7T.mjs → chunk-PGXUX4TK.mjs} +9 -9
  42. package/dist/{chunk-ADYRLXWY.mjs → chunk-WGGW6VCR.mjs} +2 -2
  43. package/dist/{chunk-XVIUHFC3.mjs → chunk-X3ZU3HL7.mjs} +4 -4
  44. package/dist/{chunk-XVIUHFC3.mjs.map → chunk-X3ZU3HL7.mjs.map} +1 -1
  45. package/dist/{chunk-A5QFYBTR.mjs → chunk-YHVXD5WW.mjs} +7 -3
  46. package/dist/chunk-YHVXD5WW.mjs.map +1 -0
  47. package/dist/index.js +16 -15
  48. package/dist/index.mjs +15 -14
  49. package/dist/shared/to-raw-notification.js +8 -0
  50. package/dist/shared/to-raw-notification.js.map +1 -0
  51. package/dist/shared/to-raw-notification.mjs +8 -0
  52. package/dist/shared/to-raw-notification.mjs.map +1 -0
  53. package/dist/tsconfig.build.tsbuildinfo +1 -1
  54. package/dist/types/NotificationServicesController/NotificationServicesController.d.ts +14 -5
  55. package/dist/types/NotificationServicesController/NotificationServicesController.d.ts.map +1 -1
  56. package/dist/types/NotificationServicesController/services/onchain-notifications.d.ts.map +1 -1
  57. package/dist/types/NotificationServicesController/types/on-chain-notification/on-chain-notification.d.ts +1 -0
  58. package/dist/types/NotificationServicesController/types/on-chain-notification/on-chain-notification.d.ts.map +1 -1
  59. package/dist/types/NotificationServicesPushController/services/push/push-web.d.ts.map +1 -1
  60. package/dist/types/shared/to-raw-notification.d.ts +11 -0
  61. package/dist/types/shared/to-raw-notification.d.ts.map +1 -0
  62. package/package.json +1 -1
  63. package/dist/chunk-5TUHE2FM.js.map +0 -1
  64. package/dist/chunk-72H2V4J5.js.map +0 -1
  65. package/dist/chunk-A5QFYBTR.mjs.map +0 -1
  66. package/dist/chunk-CGQRVA4Q.js.map +0 -1
  67. package/dist/chunk-DNVD3CHQ.js.map +0 -1
  68. package/dist/chunk-DSLFFOGF.mjs.map +0 -1
  69. package/dist/chunk-EZHMYHBX.mjs.map +0 -1
  70. /package/dist/{chunk-MT4VCZEE.js.map → chunk-2BCJRWFF.js.map} +0 -0
  71. /package/dist/{chunk-GJHW5Z65.js.map → chunk-4HOEZMSV.js.map} +0 -0
  72. /package/dist/{chunk-R373BQEU.mjs.map → chunk-N4EKQQX7.mjs.map} +0 -0
  73. /package/dist/{chunk-F2X3OS5R.js.map → chunk-OE2TTTBQ.js.map} +0 -0
  74. /package/dist/{chunk-W7PLAK7T.mjs.map → chunk-PGXUX4TK.mjs.map} +0 -0
  75. /package/dist/{chunk-ADYRLXWY.mjs.map → chunk-WGGW6VCR.mjs.map} +0 -0
@@ -0,0 +1,12 @@
1
+ // src/shared/to-raw-notification.ts
2
+ function toRawOnChainNotification(data) {
3
+ return {
4
+ ...data,
5
+ type: data?.data?.kind
6
+ };
7
+ }
8
+
9
+ export {
10
+ toRawOnChainNotification
11
+ };
12
+ //# sourceMappingURL=chunk-DINCLRZT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/to-raw-notification.ts"],"sourcesContent":["import type {\n OnChainRawNotification,\n UnprocessedOnChainRawNotification,\n} from 'src/NotificationServicesController/types';\n\n/**\n * A true \"raw notification\" does not have some fields that exist on this type. E.g. the `type` field.\n * This is retro-actively added when we fetch notifications to be able to easily type-discriminate notifications.\n * We use this to ensure that the correct missing fields are added to the raw shapes\n *\n * @param data - raw onchain notification\n * @returns a complete raw onchain notification\n */\nexport function toRawOnChainNotification(\n data: UnprocessedOnChainRawNotification,\n): OnChainRawNotification {\n return {\n ...data,\n type: data?.data?.kind,\n } as OnChainRawNotification;\n}\n"],"mappings":";AAaO,SAAS,yBACd,MACwB;AACxB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,MAAM,MAAM;AAAA,EACpB;AACF;","names":[]}
@@ -0,0 +1,12 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/shared/to-raw-notification.ts
2
+ function toRawOnChainNotification(data) {
3
+ return {
4
+ ...data,
5
+ type: data?.data?.kind
6
+ };
7
+ }
8
+
9
+
10
+
11
+ exports.toRawOnChainNotification = toRawOnChainNotification;
12
+ //# sourceMappingURL=chunk-DT6SLUWJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/to-raw-notification.ts"],"names":[],"mappings":";AAaO,SAAS,yBACd,MACwB;AACxB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM,MAAM,MAAM;AAAA,EACpB;AACF","sourcesContent":["import type {\n OnChainRawNotification,\n UnprocessedOnChainRawNotification,\n} from 'src/NotificationServicesController/types';\n\n/**\n * A true \"raw notification\" does not have some fields that exist on this type. E.g. the `type` field.\n * This is retro-actively added when we fetch notifications to be able to easily type-discriminate notifications.\n * We use this to ensure that the correct missing fields are added to the raw shapes\n *\n * @param data - raw onchain notification\n * @returns a complete raw onchain notification\n */\nexport function toRawOnChainNotification(\n data: UnprocessedOnChainRawNotification,\n): OnChainRawNotification {\n return {\n ...data,\n type: data?.data?.kind,\n } as OnChainRawNotification;\n}\n"]}
@@ -3,6 +3,9 @@ import {
3
3
  toggleUserStorageTriggerStatus,
4
4
  traverseUserStorageTriggers
5
5
  } from "./chunk-ILPTPB4U.mjs";
6
+ import {
7
+ toRawOnChainNotification
8
+ } from "./chunk-DINCLRZT.mjs";
6
9
 
7
10
  // src/NotificationServicesController/services/onchain-notifications.ts
8
11
  import { UserStorageController } from "@metamask/profile-sync-controller";
@@ -122,17 +125,12 @@ async function getOnChainNotifications(userStorage, bearerToken) {
122
125
  { trigger_ids: triggerIds }
123
126
  );
124
127
  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
- };
128
+ const transformedNotifications = notifications.map((n) => {
129
+ if (!n.data?.kind) {
130
+ return void 0;
134
131
  }
135
- ).filter((n) => Boolean(n));
132
+ return toRawOnChainNotification(n);
133
+ }).filter((n) => Boolean(n));
136
134
  onChainNotifications.push(...transformedNotifications);
137
135
  if (notifications.length < 100) {
138
136
  page = PAGE_LIMIT + 1;
@@ -184,4 +182,4 @@ export {
184
182
  getOnChainNotifications,
185
183
  markNotificationsAsRead
186
184
  };
187
- //# sourceMappingURL=chunk-EZHMYHBX.mjs.map
185
+ //# sourceMappingURL=chunk-FN6GVBCU.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 { toRawOnChainNotification } from '../../shared/to-raw-notification';\nimport type {\n OnChainRawNotification,\n UnprocessedOnChainRawNotification,\n} from '../types/on-chain-notification/on-chain-notification';\nimport type { UserStorage } from '../types/user-storage/user-storage';\nimport {\n makeApiCall,\n toggleUserStorageTriggerStatus,\n traverseUserStorageTriggers,\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 =\n (await response.json()) as UnprocessedOnChainRawNotification[];\n\n // Transform and sort notifications\n const transformedNotifications = notifications\n .map((n): OnChainRawNotification | undefined => {\n if (!n.data?.kind) {\n return undefined;\n }\n\n return toRawOnChainNotification(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":[]}
@@ -2,6 +2,9 @@
2
2
 
3
3
  var _chunkKWTSMLNDjs = require('./chunk-KWTSMLND.js');
4
4
 
5
+
6
+ var _chunkDT6SLUWJjs = require('./chunk-DT6SLUWJ.js');
7
+
5
8
  // src/NotificationServicesPushController/services/push/push-web.ts
6
9
  var _app = require('firebase/app');
7
10
  var _messaging = require('firebase/messaging');
@@ -55,10 +58,11 @@ async function listenToPushNotificationsReceived(env, handler) {
55
58
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
56
59
  async (payload) => {
57
60
  try {
58
- const notificationData = payload?.data?.data ? JSON.parse(payload?.data?.data) : void 0;
59
- if (!notificationData) {
61
+ const data = payload?.data?.data ? JSON.parse(payload?.data?.data) : void 0;
62
+ if (!data) {
60
63
  return;
61
64
  }
65
+ const notificationData = _chunkDT6SLUWJjs.toRawOnChainNotification.call(void 0, data);
62
66
  const notification = _chunkKWTSMLNDjs.processors_exports.processNotification(notificationData);
63
67
  await handler(notification);
64
68
  } catch (error) {
@@ -89,4 +93,4 @@ function listenToPushNotificationsClicked(handler) {
89
93
 
90
94
 
91
95
  exports.createRegToken = createRegToken; exports.deleteRegToken = deleteRegToken; exports.listenToPushNotificationsReceived = listenToPushNotificationsReceived; exports.listenToPushNotificationsClicked = listenToPushNotificationsClicked;
92
- //# sourceMappingURL=chunk-72H2V4J5.js.map
96
+ //# sourceMappingURL=chunk-GDKHOBJT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/NotificationServicesPushController/services/push/push-web.ts"],"names":[],"mappings":";;;;;;;;AAIA,SAAS,QAAQ,qBAAqB;AACtC,SAAS,UAAU,mBAAmB;AACtC,SAAS,cAAc,2BAA2B;AAElD,OAAO,SAAS;AAShB,IAAM,oBAAoB,OACxB,QACyB;AACzB,MAAI;AACF,WAAO,OAAO;AAAA,EAChB,QAAQ;AACN,UAAM,iBAAiB;AAAA,MACrB,QAAQ,IAAI;AAAA,MACZ,YAAY,IAAI;AAAA,MAChB,eAAe,IAAI;AAAA,MACnB,WAAW,IAAI;AAAA,MACf,mBAAmB,IAAI;AAAA,MACvB,OAAO,IAAI;AAAA,MACX,eAAe,IAAI;AAAA,IACrB;AACA,WAAO,cAAc,cAAc;AAAA,EACrC;AACF;AAEA,IAAM,uBAAuB,OAC3B,QACuB;AACvB,QAAM,MAAM,MAAM,kBAAkB,GAAG;AACvC,SAAO,aAAa,GAAG;AACzB;AAQA,eAAsB,eACpB,KACwB;AACxB,MAAI;AACF,UAAM,YAAY,MAAM,qBAAqB,GAAG;AAChD,UAAM,QAAQ,MAAM,SAAS,WAAW;AAAA,MACtC,2BAA2B,KAAK;AAAA,MAChC,UAAU,IAAI;AAAA,IAChB,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,eACpB,KACkB;AAClB,MAAI;AACF,UAAM,YAAY,MAAM,qBAAqB,GAAG;AAChD,UAAM,YAAY,SAAS;AAC3B,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,kCACpB,KACA,SACA;AACA,QAAM,YAAY,MAAM,qBAAqB,GAAG;AAChD,QAAM,+BAA+B;AAAA,IACnC;AAAA;AAAA,IAEA,OAAO,YAA4B;AACjC,UAAI;AACF,cAAM,OACJ,SAAS,MAAM,OAAO,KAAK,MAAM,SAAS,MAAM,IAAI,IAAI;AAE1D,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AAEA,cAAM,mBAAmB,yBAAyB,IAAI;AACtD,cAAM,eAAe,mBAAW,oBAAoB,gBAAgB;AACpE,cAAM,QAAQ,YAAY;AAAA,MAC5B,SAAS,OAAO;AAEd,YAAI,MAAM,qCAAqC;AAAA,UAC7C,cAAc,SAAS,MAAM;AAAA,UAC7B;AAAA,QACF,CAAC;AACD,cAAM,IAAI,MAAM,kCAAkC;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,MAAM,6BAA6B;AACvD,SAAO;AACT;AAQO,SAAS,iCACd,SACA;AACA,QAAM,eAAe,CAAC,UAA6B;AAEjD,UAAM,OAA4B,OAAO,cAAc;AACvD,YAAQ,OAAO,IAAI;AAAA,EACrB;AAEA,OAAK,iBAAiB,qBAAqB,YAAY;AACvD,QAAM,cAAc,MAClB,KAAK,oBAAoB,qBAAqB,YAAY;AAC5D,SAAO;AACT","sourcesContent":["// We are defining that this file uses a webworker global scope.\n// eslint-disable-next-line spaced-comment\n/// <reference lib=\"webworker\" />\nimport type { FirebaseApp } from 'firebase/app';\nimport { getApp, initializeApp } from 'firebase/app';\nimport { getToken, deleteToken } from 'firebase/messaging';\nimport { getMessaging, onBackgroundMessage } from 'firebase/messaging/sw';\nimport type { Messaging, MessagePayload } from 'firebase/messaging/sw';\nimport log from 'loglevel';\n\nimport type { Types } from '../../../NotificationServicesController';\nimport { Processors } from '../../../NotificationServicesController';\nimport { toRawOnChainNotification } from '../../../shared/to-raw-notification';\nimport type { PushNotificationEnv } from '../../types/firebase';\n\ndeclare const self: ServiceWorkerGlobalScope;\n\nconst createFirebaseApp = async (\n env: PushNotificationEnv,\n): Promise<FirebaseApp> => {\n try {\n return getApp();\n } catch {\n const firebaseConfig = {\n apiKey: env.apiKey,\n authDomain: env.authDomain,\n storageBucket: env.storageBucket,\n projectId: env.projectId,\n messagingSenderId: env.messagingSenderId,\n appId: env.appId,\n measurementId: env.measurementId,\n };\n return initializeApp(firebaseConfig);\n }\n};\n\nconst getFirebaseMessaging = async (\n env: PushNotificationEnv,\n): Promise<Messaging> => {\n const app = await createFirebaseApp(env);\n return getMessaging(app);\n};\n\n/**\n * Creates a registration token for Firebase Cloud Messaging.\n *\n * @param env - env to configure push notifications\n * @returns A promise that resolves with the registration token or null if an error occurs.\n */\nexport async function createRegToken(\n env: PushNotificationEnv,\n): Promise<string | null> {\n try {\n const messaging = await getFirebaseMessaging(env);\n const token = await getToken(messaging, {\n serviceWorkerRegistration: self.registration,\n vapidKey: env.vapidKey,\n });\n return token;\n } catch {\n return null;\n }\n}\n\n/**\n * Deletes the Firebase Cloud Messaging registration token.\n *\n * @param env - env to configure push notifications\n * @returns A promise that resolves with true if the token was successfully deleted, false otherwise.\n */\nexport async function deleteRegToken(\n env: PushNotificationEnv,\n): Promise<boolean> {\n try {\n const messaging = await getFirebaseMessaging(env);\n await deleteToken(messaging);\n return true;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Service Worker Listener for when push notifications are received.\n * @param env - push notification environment\n * @param handler - handler to actually showing notification, MUST BE PROVEDED\n * @returns unsubscribe handler\n */\nexport async function listenToPushNotificationsReceived(\n env: PushNotificationEnv,\n handler: (notification: Types.INotification) => void | Promise<void>,\n) {\n const messaging = await getFirebaseMessaging(env);\n const unsubscribePushNotifications = onBackgroundMessage(\n messaging,\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (payload: MessagePayload) => {\n try {\n const data: Types.UnprocessedOnChainRawNotification | undefined =\n payload?.data?.data ? JSON.parse(payload?.data?.data) : undefined;\n\n if (!data) {\n return;\n }\n\n const notificationData = toRawOnChainNotification(data);\n const notification = Processors.processNotification(notificationData);\n await handler(notification);\n } catch (error) {\n // Do Nothing, cannot parse a bad notification\n log.error('Unable to send push notification:', {\n notification: payload?.data?.data,\n error,\n });\n throw new Error('Unable to send push notification');\n }\n },\n );\n\n const unsubscribe = () => unsubscribePushNotifications();\n return unsubscribe;\n}\n\n/**\n * Service Worker Listener for when a notification is clicked\n *\n * @param handler - listen to NotificationEvent from the service worker\n * @returns unsubscribe handler\n */\nexport function listenToPushNotificationsClicked(\n handler: (e: NotificationEvent, notification?: Types.INotification) => void,\n) {\n const clickHandler = (event: NotificationEvent) => {\n // Get Data\n const data: Types.INotification = event?.notification?.data;\n handler(event, data);\n };\n\n self.addEventListener('notificationclick', clickHandler);\n const unsubscribe = () =>\n self.removeEventListener('notificationclick', clickHandler);\n return unsubscribe;\n}\n"]}
@@ -4,6 +4,9 @@
4
4
 
5
5
  var _chunkNOYP2T77js = require('./chunk-NOYP2T77.js');
6
6
 
7
+
8
+ var _chunkDT6SLUWJjs = require('./chunk-DT6SLUWJ.js');
9
+
7
10
  // src/NotificationServicesController/services/onchain-notifications.ts
8
11
  var _profilesynccontroller = require('@metamask/profile-sync-controller');
9
12
  var _loglevel = require('loglevel'); var _loglevel2 = _interopRequireDefault(_loglevel);
@@ -122,17 +125,12 @@ async function getOnChainNotifications(userStorage, bearerToken) {
122
125
  { trigger_ids: triggerIds }
123
126
  );
124
127
  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
- };
128
+ const transformedNotifications = notifications.map((n) => {
129
+ if (!n.data?.kind) {
130
+ return void 0;
134
131
  }
135
- ).filter((n) => Boolean(n));
132
+ return _chunkDT6SLUWJjs.toRawOnChainNotification.call(void 0, n);
133
+ }).filter((n) => Boolean(n));
136
134
  onChainNotifications.push(...transformedNotifications);
137
135
  if (notifications.length < 100) {
138
136
  page = PAGE_LIMIT + 1;
@@ -184,4 +182,4 @@ async function markNotificationsAsRead(bearerToken, notificationIds) {
184
182
 
185
183
 
186
184
  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-DNVD3CHQ.js.map
185
+ //# sourceMappingURL=chunk-H73GATCU.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 { toRawOnChainNotification } from '../../shared/to-raw-notification';\nimport type {\n OnChainRawNotification,\n UnprocessedOnChainRawNotification,\n} from '../types/on-chain-notification/on-chain-notification';\nimport type { UserStorage } from '../types/user-storage/user-storage';\nimport {\n makeApiCall,\n toggleUserStorageTriggerStatus,\n traverseUserStorageTriggers,\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 =\n (await response.json()) as UnprocessedOnChainRawNotification[];\n\n // Transform and sort notifications\n const transformedNotifications = notifications\n .map((n): OnChainRawNotification | undefined => {\n if (!n.data?.kind) {\n return undefined;\n }\n\n return toRawOnChainNotification(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"]}
@@ -1,13 +1,13 @@
1
- import {
2
- utils_exports
3
- } from "./chunk-DCADU5QI.mjs";
4
1
  import {
5
2
  types_exports
6
3
  } from "./chunk-IOMDG67D.mjs";
4
+ import {
5
+ utils_exports
6
+ } from "./chunk-DCADU5QI.mjs";
7
7
  import {
8
8
  NotificationServicesPushController,
9
9
  defaultState
10
- } from "./chunk-XVIUHFC3.mjs";
10
+ } from "./chunk-X3ZU3HL7.mjs";
11
11
  import {
12
12
  REGISTRATION_TOKENS_ENDPOINT
13
13
  } from "./chunk-IKWNHNJQ.mjs";
@@ -91,4 +91,4 @@ export {
91
91
  fixtures_exports,
92
92
  NotificationServicesPushController_exports
93
93
  };
94
- //# sourceMappingURL=chunk-R373BQEU.mjs.map
94
+ //# sourceMappingURL=chunk-N4EKQQX7.mjs.map
@@ -1,16 +1,19 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
+ var _chunk232HZSEVjs = require('./chunk-232HZSEV.js');
4
+
5
+
3
6
  var _chunkIG3KWCQUjs = require('./chunk-IG3KWCQU.js');
4
7
 
5
8
 
6
- var _chunkKWTSMLNDjs = require('./chunk-KWTSMLND.js');
9
+ var _chunkQY4UST5Vjs = require('./chunk-QY4UST5V.js');
7
10
 
8
11
 
9
- var _chunk232HZSEVjs = require('./chunk-232HZSEV.js');
12
+ var _chunkKWTSMLNDjs = require('./chunk-KWTSMLND.js');
10
13
 
11
14
 
12
15
 
13
- var _chunkCGQRVA4Qjs = require('./chunk-CGQRVA4Q.js');
16
+ var _chunk323GXNREjs = require('./chunk-323GXNRE.js');
14
17
 
15
18
 
16
19
  var _chunkHZEB53A6js = require('./chunk-HZEB53A6.js');
@@ -18,15 +21,12 @@ var _chunkHZEB53A6js = require('./chunk-HZEB53A6.js');
18
21
 
19
22
 
20
23
 
21
- var _chunkDNVD3CHQjs = require('./chunk-DNVD3CHQ.js');
24
+ var _chunkH73GATCUjs = require('./chunk-H73GATCU.js');
22
25
 
23
26
 
24
27
  var _chunkNOYP2T77js = require('./chunk-NOYP2T77.js');
25
28
 
26
29
 
27
- var _chunkQY4UST5Vjs = require('./chunk-QY4UST5V.js');
28
-
29
-
30
30
  var _chunkTLX5QQK5js = require('./chunk-TLX5QQK5.js');
31
31
 
32
32
 
@@ -36,12 +36,12 @@ var _chunkIGY2S5BCjs = require('./chunk-IGY2S5BC.js');
36
36
  var NotificationServicesController_exports = {};
37
37
  _chunkIGY2S5BCjs.__export.call(void 0, NotificationServicesController_exports, {
38
38
  Constants: () => _chunkQY4UST5Vjs.constants_exports,
39
- Controller: () => _chunkCGQRVA4Qjs.NotificationServicesController,
39
+ Controller: () => _chunk323GXNREjs.NotificationServicesController,
40
40
  Mocks: () => fixtures_exports,
41
41
  Processors: () => _chunkKWTSMLNDjs.processors_exports,
42
42
  Types: () => _chunk232HZSEVjs.types_exports,
43
43
  UI: () => _chunkIG3KWCQUjs.ui_exports,
44
- defaultState: () => _chunkCGQRVA4Qjs.defaultState
44
+ defaultState: () => _chunk323GXNREjs.defaultState
45
45
  });
46
46
 
47
47
  // src/NotificationServicesController/__fixtures__/index.ts
@@ -894,14 +894,14 @@ var getMockFeatureAnnouncementResponse = () => {
894
894
  };
895
895
  var getMockBatchCreateTriggersResponse = () => {
896
896
  return {
897
- url: _chunkDNVD3CHQjs.TRIGGER_API_BATCH_ENDPOINT,
897
+ url: _chunkH73GATCUjs.TRIGGER_API_BATCH_ENDPOINT,
898
898
  requestMethod: "POST",
899
899
  response: null
900
900
  };
901
901
  };
902
902
  var getMockBatchDeleteTriggersResponse = () => {
903
903
  return {
904
- url: _chunkDNVD3CHQjs.TRIGGER_API_BATCH_ENDPOINT,
904
+ url: _chunkH73GATCUjs.TRIGGER_API_BATCH_ENDPOINT,
905
905
  requestMethod: "DELETE",
906
906
  response: null
907
907
  };
@@ -909,14 +909,14 @@ var getMockBatchDeleteTriggersResponse = () => {
909
909
  var MOCK_RAW_ON_CHAIN_NOTIFICATIONS = createMockRawOnChainNotifications();
910
910
  var getMockListNotificationsResponse = () => {
911
911
  return {
912
- url: _chunkDNVD3CHQjs.NOTIFICATION_API_LIST_ENDPOINT,
912
+ url: _chunkH73GATCUjs.NOTIFICATION_API_LIST_ENDPOINT,
913
913
  requestMethod: "POST",
914
914
  response: MOCK_RAW_ON_CHAIN_NOTIFICATIONS
915
915
  };
916
916
  };
917
917
  var getMockMarkNotificationsAsReadResponse = () => {
918
918
  return {
919
- url: _chunkDNVD3CHQjs.NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,
919
+ url: _chunkH73GATCUjs.NOTIFICATION_API_MARK_ALL_AS_READ_ENDPOINT,
920
920
  requestMethod: "POST",
921
921
  response: null
922
922
  };
@@ -926,4 +926,4 @@ var getMockMarkNotificationsAsReadResponse = () => {
926
926
 
927
927
 
928
928
  exports.fixtures_exports = fixtures_exports; exports.NotificationServicesController_exports = NotificationServicesController_exports;
929
- //# sourceMappingURL=chunk-F2X3OS5R.js.map
929
+ //# sourceMappingURL=chunk-OE2TTTBQ.js.map
@@ -9,7 +9,7 @@ import {
9
9
  deleteOnChainTriggers,
10
10
  getOnChainNotifications,
11
11
  markNotificationsAsRead
12
- } from "./chunk-EZHMYHBX.mjs";
12
+ } from "./chunk-FN6GVBCU.mjs";
13
13
  import {
14
14
  checkAccountsPresence,
15
15
  getAllUUIDs,
@@ -87,7 +87,7 @@ var defaultState = {
87
87
  isUpdatingMetamaskNotificationsAccount: [],
88
88
  isCheckingAccountsPresence: false
89
89
  };
90
- var _isPushIntegrated, _auth, _storage, _pushNotifications, _accounts, _featureAnnouncementEnv, _registerMessageHandlers, registerMessageHandlers_fn, _clearLoadingStates, clearLoadingStates_fn, _assertAuthEnabled, assertAuthEnabled_fn, _getValidStorageKeyAndBearerToken, getValidStorageKeyAndBearerToken_fn, _performEnableProfileSyncing, _assertUserStorage, assertUserStorage_fn, _getUserStorage, getUserStorage_fn, _setIsUpdatingMetamaskNotifications, setIsUpdatingMetamaskNotifications_fn, _setIsFetchingMetamaskNotifications, setIsFetchingMetamaskNotifications_fn, _setIsCheckingAccountsPresence, setIsCheckingAccountsPresence_fn, _updateUpdatingAccountsState, updateUpdatingAccountsState_fn, _clearUpdatingAccountsState, clearUpdatingAccountsState_fn;
90
+ var _isPushIntegrated, _isPushNotificationsSetup, _isUnlocked, _keyringController, _auth, _storage, _pushNotifications, _accounts, _featureAnnouncementEnv, _registerMessageHandlers, registerMessageHandlers_fn, _clearLoadingStates, clearLoadingStates_fn, _assertAuthEnabled, assertAuthEnabled_fn, _getValidStorageKeyAndBearerToken, getValidStorageKeyAndBearerToken_fn, _performEnableProfileSyncing, _assertUserStorage, assertUserStorage_fn, _getUserStorage, getUserStorage_fn, _setIsUpdatingMetamaskNotifications, setIsUpdatingMetamaskNotifications_fn, _setIsFetchingMetamaskNotifications, setIsFetchingMetamaskNotifications_fn, _setIsCheckingAccountsPresence, setIsCheckingAccountsPresence_fn, _updateUpdatingAccountsState, updateUpdatingAccountsState_fn, _clearUpdatingAccountsState, clearUpdatingAccountsState_fn;
91
91
  var NotificationServicesController = class extends BaseController {
92
92
  /**
93
93
  * Creates a NotificationServicesController instance.
@@ -170,6 +170,26 @@ var NotificationServicesController = class extends BaseController {
170
170
  __privateAdd(this, _clearUpdatingAccountsState);
171
171
  // Temporary boolean as push notifications are not yet enabled on mobile
172
172
  __privateAdd(this, _isPushIntegrated, true);
173
+ // Flag to check is notifications have been setup when the browser/extension is initialized.
174
+ // We want to re-initialize push notifications when the browser/extension is refreshed
175
+ // To ensure we subscribe to the most up-to-date notifications
176
+ __privateAdd(this, _isPushNotificationsSetup, false);
177
+ __privateAdd(this, _isUnlocked, false);
178
+ __privateAdd(this, _keyringController, {
179
+ setupLockedStateSubscriptions: (onUnlock) => {
180
+ const { isUnlocked } = this.messagingSystem.call(
181
+ "KeyringController:getState"
182
+ );
183
+ __privateSet(this, _isUnlocked, isUnlocked);
184
+ this.messagingSystem.subscribe("KeyringController:unlock", () => {
185
+ __privateSet(this, _isUnlocked, true);
186
+ onUnlock();
187
+ });
188
+ this.messagingSystem.subscribe("KeyringController:lock", () => {
189
+ __privateSet(this, _isUnlocked, false);
190
+ });
191
+ }
192
+ });
173
193
  __privateAdd(this, _auth, {
174
194
  getBearerToken: async () => {
175
195
  return await this.messagingSystem.call(
@@ -261,12 +281,19 @@ var NotificationServicesController = class extends BaseController {
261
281
  if (!this.state.isNotificationServicesEnabled) {
262
282
  return;
263
283
  }
284
+ if (__privateGet(this, _isPushNotificationsSetup)) {
285
+ return;
286
+ }
287
+ if (!__privateGet(this, _isUnlocked)) {
288
+ return;
289
+ }
264
290
  const storage = await __privateMethod(this, _getUserStorage, getUserStorage_fn).call(this);
265
291
  if (!storage) {
266
292
  return;
267
293
  }
268
294
  const uuids = getAllUUIDs(storage);
269
295
  await __privateGet(this, _pushNotifications).enablePushNotifications(uuids);
296
+ __privateSet(this, _isPushNotificationsSetup, true);
270
297
  }
271
298
  });
272
299
  __privateAdd(this, _accounts, {
@@ -349,6 +376,9 @@ var NotificationServicesController = class extends BaseController {
349
376
  __privateSet(this, _featureAnnouncementEnv, env.featureAnnouncements);
350
377
  __privateMethod(this, _registerMessageHandlers, registerMessageHandlers_fn).call(this);
351
378
  __privateMethod(this, _clearLoadingStates, clearLoadingStates_fn).call(this);
379
+ __privateGet(this, _keyringController).setupLockedStateSubscriptions(
380
+ __privateGet(this, _pushNotifications).initializePushNotifications
381
+ );
352
382
  __privateGet(this, _accounts).initialize();
353
383
  __privateGet(this, _pushNotifications).initializePushNotifications();
354
384
  __privateGet(this, _accounts).subscribe();
@@ -630,6 +660,10 @@ var NotificationServicesController = class extends BaseController {
630
660
  this.update((state) => {
631
661
  state.metamaskNotificationsList = metamaskNotifications;
632
662
  });
663
+ this.messagingSystem.publish(
664
+ `${controllerName}:notificationsListUpdated`,
665
+ this.state.metamaskNotificationsList
666
+ );
633
667
  __privateMethod(this, _setIsFetchingMetamaskNotifications, setIsFetchingMetamaskNotifications_fn).call(this, false);
634
668
  return metamaskNotifications;
635
669
  } catch (err) {
@@ -692,6 +726,10 @@ var NotificationServicesController = class extends BaseController {
692
726
  }
693
727
  );
694
728
  });
729
+ this.messagingSystem.publish(
730
+ `${controllerName}:markNotificationsAsRead`,
731
+ this.state.metamaskNotificationsList
732
+ );
695
733
  }
696
734
  /**
697
735
  * Updates the list of MetaMask notifications by adding a new notification at the beginning of the list.
@@ -715,12 +753,19 @@ var NotificationServicesController = class extends BaseController {
715
753
  notification,
716
754
  ...state.metamaskNotificationsList
717
755
  ];
756
+ this.messagingSystem.publish(
757
+ `${controllerName}:notificationsListUpdated`,
758
+ state.metamaskNotificationsList
759
+ );
718
760
  }
719
761
  });
720
762
  }
721
763
  }
722
764
  };
723
765
  _isPushIntegrated = new WeakMap();
766
+ _isPushNotificationsSetup = new WeakMap();
767
+ _isUnlocked = new WeakMap();
768
+ _keyringController = new WeakMap();
724
769
  _auth = new WeakMap();
725
770
  _storage = new WeakMap();
726
771
  _pushNotifications = new WeakMap();
@@ -831,4 +876,4 @@ export {
831
876
  defaultState,
832
877
  NotificationServicesController
833
878
  };
834
- //# sourceMappingURL=chunk-DSLFFOGF.mjs.map
879
+ //# sourceMappingURL=chunk-OLYCBAVW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/NotificationServicesController/NotificationServicesController.ts"],"sourcesContent":["import type {\n RestrictedControllerMessenger,\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport type {\n KeyringControllerGetAccountsAction,\n KeyringControllerStateChangeEvent,\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type {\n AuthenticationController,\n UserStorageController,\n} from '@metamask/profile-sync-controller';\nimport log from 'loglevel';\n\nimport { USER_STORAGE_VERSION_KEY } from './constants/constants';\nimport { TRIGGER_TYPES } from './constants/notification-schema';\nimport { safeProcessNotification } from './processors/process-notifications';\nimport * as FeatureNotifications from './services/feature-announcements';\nimport * as OnChainNotifications from './services/onchain-notifications';\nimport type {\n INotification,\n MarkAsReadNotificationsParam,\n NotificationUnion,\n} from './types/notification/notification';\nimport type { OnChainRawNotification } from './types/on-chain-notification/on-chain-notification';\nimport type { UserStorage } from './types/user-storage/user-storage';\nimport * as Utils from './utils/utils';\n\n// TODO: Fix Circular Type Dependencies\n// This indicates that control flow of messages is everywhere, lets orchestrate these better\nexport type NotificationServicesPushControllerEnablePushNotifications = {\n type: `NotificationServicesPushController:enablePushNotifications`;\n handler: (UUIDs: string[]) => Promise<void>;\n};\n\nexport type NotificationServicesPushControllerDisablePushNotifications = {\n type: `NotificationServicesPushController:disablePushNotifications`;\n handler: (UUIDs: string[]) => Promise<void>;\n};\n\nexport type NotificationServicesPushControllerUpdateTriggerPushNotifications = {\n type: `NotificationServicesPushController:updateTriggerPushNotifications`;\n handler: (UUIDs: string[]) => Promise<void>;\n};\n\nexport type NotificationServicesPushControllerOnNewNotification = {\n type: `NotificationServicesPushController:onNewNotifications`;\n payload: [INotification];\n};\n\n// Unique name for the controller\nconst controllerName = 'NotificationServicesController';\n\n/**\n * State shape for NotificationServicesController\n */\nexport type NotificationServicesControllerState = {\n /**\n * We store and manage accounts that have been seen/visted through the\n * account subscription. This allows us to track and add notifications for new accounts and not previous accounts added.\n */\n subscriptionAccountsSeen: string[];\n\n /**\n * Flag that indicates if the metamask notifications feature has been seen\n */\n isMetamaskNotificationsFeatureSeen: boolean;\n\n /**\n * Flag that indicates if the metamask notifications are enabled\n */\n isNotificationServicesEnabled: boolean;\n\n /**\n * Flag that indicates if the feature announcements are enabled\n */\n isFeatureAnnouncementsEnabled: boolean;\n\n /**\n * List of metamask notifications\n */\n metamaskNotificationsList: INotification[];\n\n /**\n * List of read metamask notifications\n */\n metamaskNotificationsReadList: string[];\n /**\n * Flag that indicates that the creating notifications is in progress\n */\n isUpdatingMetamaskNotifications: boolean;\n /**\n * Flag that indicates that the fetching notifications is in progress\n * This is used to show a loading spinner in the UI\n * when fetching notifications\n */\n isFetchingMetamaskNotifications: boolean;\n /**\n * Flag that indicates that the updating notifications for a specific address is in progress\n */\n isUpdatingMetamaskNotificationsAccount: string[];\n /**\n * Flag that indicates that the checking accounts presence is in progress\n */\n isCheckingAccountsPresence: boolean;\n};\n\nconst metadata: StateMetadata<NotificationServicesControllerState> = {\n subscriptionAccountsSeen: {\n persist: true,\n anonymous: true,\n },\n\n isMetamaskNotificationsFeatureSeen: {\n persist: true,\n anonymous: false,\n },\n isNotificationServicesEnabled: {\n persist: true,\n anonymous: false,\n },\n isFeatureAnnouncementsEnabled: {\n persist: true,\n anonymous: false,\n },\n metamaskNotificationsList: {\n persist: true,\n anonymous: true,\n },\n metamaskNotificationsReadList: {\n persist: true,\n anonymous: true,\n },\n isUpdatingMetamaskNotifications: {\n persist: false,\n anonymous: false,\n },\n isFetchingMetamaskNotifications: {\n persist: false,\n anonymous: false,\n },\n isUpdatingMetamaskNotificationsAccount: {\n persist: false,\n anonymous: false,\n },\n isCheckingAccountsPresence: {\n persist: false,\n anonymous: false,\n },\n};\nexport const defaultState: NotificationServicesControllerState = {\n subscriptionAccountsSeen: [],\n isMetamaskNotificationsFeatureSeen: false,\n isNotificationServicesEnabled: false,\n isFeatureAnnouncementsEnabled: false,\n metamaskNotificationsList: [],\n metamaskNotificationsReadList: [],\n isUpdatingMetamaskNotifications: false,\n isFetchingMetamaskNotifications: false,\n isUpdatingMetamaskNotificationsAccount: [],\n isCheckingAccountsPresence: false,\n};\n\nexport type NotificationServicesControllerUpdateMetamaskNotificationsList = {\n type: `${typeof controllerName}:updateMetamaskNotificationsList`;\n handler: NotificationServicesController['updateMetamaskNotificationsList'];\n};\n\nexport type NotificationServicesControllerDisableNotificationServices = {\n type: `${typeof controllerName}:disableNotificationServices`;\n handler: NotificationServicesController['disableNotificationServices'];\n};\n\nexport type NotificationServicesControllerSelectIsNotificationServicesEnabled =\n {\n type: `${typeof controllerName}:selectIsNotificationServicesEnabled`;\n handler: NotificationServicesController['selectIsNotificationServicesEnabled'];\n };\n\n// Messenger Actions\nexport type Actions =\n | NotificationServicesControllerUpdateMetamaskNotificationsList\n | NotificationServicesControllerDisableNotificationServices\n | NotificationServicesControllerSelectIsNotificationServicesEnabled\n | ControllerGetStateAction<'state', NotificationServicesControllerState>;\n\n// Allowed Actions\nexport type AllowedActions =\n // Keyring Controller Requests\n | KeyringControllerGetAccountsAction\n | KeyringControllerGetStateAction\n // Auth Controller Requests\n | AuthenticationController.AuthenticationControllerGetBearerToken\n | AuthenticationController.AuthenticationControllerIsSignedIn\n // User Storage Controller Requests\n | UserStorageController.UserStorageControllerEnableProfileSyncing\n | UserStorageController.UserStorageControllerGetStorageKey\n | UserStorageController.UserStorageControllerPerformGetStorage\n | UserStorageController.UserStorageControllerPerformSetStorage\n // Push Notifications Controller Requests\n | NotificationServicesPushControllerEnablePushNotifications\n | NotificationServicesPushControllerDisablePushNotifications\n | NotificationServicesPushControllerUpdateTriggerPushNotifications;\n\n// Events\nexport type NotificationServicesControllerChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n NotificationServicesControllerState\n >;\n\nexport type MetamaskNotificationsControllerNotificationsListUpdatedEvent = {\n type: `${typeof controllerName}:notificationsListUpdated`;\n payload: [INotification[]];\n};\n\nexport type MetamaskNotificationsControllerMarkNotificationsAsRead = {\n type: `${typeof controllerName}:markNotificationsAsRead`;\n payload: [INotification[]];\n};\n\n// Events\nexport type Events =\n | NotificationServicesControllerChangeEvent\n | MetamaskNotificationsControllerNotificationsListUpdatedEvent\n | MetamaskNotificationsControllerMarkNotificationsAsRead;\n\n// Allowed Events\nexport type AllowedEvents =\n // Keyring Events\n | KeyringControllerStateChangeEvent\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n // Push Notification Events\n | NotificationServicesPushControllerOnNewNotification;\n\n// Type for the messenger of NotificationServicesController\nexport type NotificationServicesControllerMessenger =\n RestrictedControllerMessenger<\n typeof controllerName,\n Actions | AllowedActions,\n Events | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n >;\n\ntype FeatureAnnouncementEnv = {\n spaceId: string;\n accessToken: string;\n platform: 'extension' | 'mobile';\n};\n\n/**\n * Controller that enables wallet notifications and feature announcements\n */\nexport default class NotificationServicesController extends BaseController<\n typeof controllerName,\n NotificationServicesControllerState,\n NotificationServicesControllerMessenger\n> {\n // Temporary boolean as push notifications are not yet enabled on mobile\n #isPushIntegrated = true;\n\n // Flag to check is notifications have been setup when the browser/extension is initialized.\n // We want to re-initialize push notifications when the browser/extension is refreshed\n // To ensure we subscribe to the most up-to-date notifications\n #isPushNotificationsSetup = false;\n\n #isUnlocked = false;\n\n #keyringController = {\n setupLockedStateSubscriptions: (onUnlock: () => Promise<void>) => {\n const { isUnlocked } = this.messagingSystem.call(\n 'KeyringController:getState',\n );\n this.#isUnlocked = isUnlocked;\n\n this.messagingSystem.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n // messaging system cannot await promises\n // we don't need to wait for a result on this.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n onUnlock();\n });\n\n this.messagingSystem.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n },\n };\n\n #auth = {\n getBearerToken: async () => {\n return await this.messagingSystem.call(\n 'AuthenticationController:getBearerToken',\n );\n },\n isSignedIn: () => {\n return this.messagingSystem.call('AuthenticationController:isSignedIn');\n },\n };\n\n #storage = {\n enableProfileSyncing: async () => {\n return await this.messagingSystem.call(\n 'UserStorageController:enableProfileSyncing',\n );\n },\n getStorageKey: () => {\n return this.messagingSystem.call('UserStorageController:getStorageKey');\n },\n getNotificationStorage: async () => {\n return await this.messagingSystem.call(\n 'UserStorageController:performGetStorage',\n 'notifications.notificationSettings',\n );\n },\n setNotificationStorage: async (state: string) => {\n return await this.messagingSystem.call(\n 'UserStorageController:performSetStorage',\n 'notifications.notificationSettings',\n state,\n );\n },\n };\n\n #pushNotifications = {\n enablePushNotifications: async (UUIDs: string[]) => {\n if (!this.#isPushIntegrated) {\n return;\n }\n try {\n await this.messagingSystem.call(\n 'NotificationServicesPushController:enablePushNotifications',\n UUIDs,\n );\n } catch (e) {\n log.error('Silently failed to enable push notifications', e);\n }\n },\n disablePushNotifications: async (UUIDs: string[]) => {\n if (!this.#isPushIntegrated) {\n return;\n }\n try {\n await this.messagingSystem.call(\n 'NotificationServicesPushController:disablePushNotifications',\n UUIDs,\n );\n } catch (e) {\n log.error('Silently failed to disable push notifications', e);\n }\n },\n updatePushNotifications: async (UUIDs: string[]) => {\n if (!this.#isPushIntegrated) {\n return;\n }\n try {\n await this.messagingSystem.call(\n 'NotificationServicesPushController:updateTriggerPushNotifications',\n UUIDs,\n );\n } catch (e) {\n log.error('Silently failed to update push notifications', e);\n }\n },\n subscribe: () => {\n if (!this.#isPushIntegrated) {\n return;\n }\n this.messagingSystem.subscribe(\n 'NotificationServicesPushController:onNewNotifications',\n (notification) => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.updateMetamaskNotificationsList(notification);\n },\n );\n },\n initializePushNotifications: async () => {\n if (!this.#isPushIntegrated) {\n return;\n }\n if (!this.state.isNotificationServicesEnabled) {\n return;\n }\n if (this.#isPushNotificationsSetup) {\n return;\n }\n if (!this.#isUnlocked) {\n return;\n }\n\n const storage = await this.#getUserStorage();\n if (!storage) {\n return;\n }\n\n const uuids = Utils.getAllUUIDs(storage);\n await this.#pushNotifications.enablePushNotifications(uuids);\n this.#isPushNotificationsSetup = true;\n },\n };\n\n #accounts = {\n /**\n * Used to get list of addresses from keyring (wallet addresses)\n *\n * @returns addresses removed, added, and latest list of addresses\n */\n listAccounts: async () => {\n // Get previous and current account sets\n const nonChecksumAccounts = await this.messagingSystem.call(\n 'KeyringController:getAccounts',\n );\n const accounts = nonChecksumAccounts.map((a) => toChecksumHexAddress(a));\n const currentAccountsSet = new Set(accounts);\n const prevAccountsSet = new Set(this.state.subscriptionAccountsSeen);\n\n // Invalid value you cannot have zero accounts\n // Only occurs when the Accounts controller is initializing.\n if (accounts.length === 0) {\n return {\n accountsAdded: [],\n accountsRemoved: [],\n accounts: [],\n };\n }\n\n // Calculate added and removed addresses\n const accountsAdded = accounts.filter((a) => !prevAccountsSet.has(a));\n const accountsRemoved = [...prevAccountsSet.values()].filter(\n (a) => !currentAccountsSet.has(a),\n );\n\n // Update accounts seen\n this.update((state) => {\n state.subscriptionAccountsSeen = [...prevAccountsSet, ...accountsAdded];\n });\n\n return {\n accountsAdded,\n accountsRemoved,\n accounts,\n };\n },\n\n /**\n * Initializes the cache/previous list. This is handy so we have an accurate in-mem state of the previous list of accounts.\n *\n * @returns result from list accounts\n */\n initialize: () => {\n return this.#accounts.listAccounts();\n },\n\n /**\n * Subscription to any state change in the keyring controller (aka wallet accounts).\n * We can call the `listAccounts` defined above to find out about any accounts added, removed\n * And call effects to subscribe/unsubscribe to notifications.\n */\n subscribe: () => {\n this.messagingSystem.subscribe(\n 'KeyringController:stateChange',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async () => {\n if (!this.state.isNotificationServicesEnabled) {\n return;\n }\n\n const { accountsAdded, accountsRemoved } =\n await this.#accounts.listAccounts();\n\n const promises: Promise<unknown>[] = [];\n if (accountsAdded.length > 0) {\n promises.push(this.updateOnChainTriggersByAccount(accountsAdded));\n }\n if (accountsRemoved.length > 0) {\n promises.push(this.deleteOnChainTriggersByAccount(accountsRemoved));\n }\n await Promise.all(promises);\n },\n );\n },\n };\n\n #featureAnnouncementEnv: FeatureAnnouncementEnv;\n\n /**\n * Creates a NotificationServicesController instance.\n *\n * @param args - The arguments to this function.\n * @param args.messenger - Messenger used to communicate with BaseV2 controller.\n * @param args.state - Initial state to set on this controller.\n * @param args.env - environment variables for a given controller.\n * @param args.env.featureAnnouncements - env variables for feature announcements.\n * @param args.env.isPushIntegrated - toggle push notifications on/off if client has integrated them.\n */\n constructor({\n messenger,\n state,\n env,\n }: {\n messenger: NotificationServicesControllerMessenger;\n state?: Partial<NotificationServicesControllerState>;\n env: {\n featureAnnouncements: FeatureAnnouncementEnv;\n isPushIntegrated?: boolean;\n };\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: { ...defaultState, ...state },\n });\n\n this.#isPushIntegrated = env.isPushIntegrated ?? true;\n this.#featureAnnouncementEnv = env.featureAnnouncements;\n this.#registerMessageHandlers();\n this.#clearLoadingStates();\n\n this.#keyringController.setupLockedStateSubscriptions(\n this.#pushNotifications.initializePushNotifications,\n );\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#accounts.initialize();\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.#pushNotifications.initializePushNotifications();\n this.#accounts.subscribe();\n this.#pushNotifications.subscribe();\n }\n\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:updateMetamaskNotificationsList`,\n this.updateMetamaskNotificationsList.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:disableNotificationServices`,\n this.disableNotificationServices.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:selectIsNotificationServicesEnabled`,\n this.selectIsNotificationServicesEnabled.bind(this),\n );\n }\n\n #clearLoadingStates(): void {\n this.update((state) => {\n state.isUpdatingMetamaskNotifications = false;\n state.isCheckingAccountsPresence = false;\n state.isFetchingMetamaskNotifications = false;\n state.isUpdatingMetamaskNotificationsAccount = [];\n });\n }\n\n #assertAuthEnabled() {\n if (!this.#auth.isSignedIn()) {\n this.update((state) => {\n state.isNotificationServicesEnabled = false;\n });\n throw new Error('User is not signed in.');\n }\n }\n\n async #getValidStorageKeyAndBearerToken() {\n this.#assertAuthEnabled();\n\n const bearerToken = await this.#auth.getBearerToken();\n const storageKey = await this.#storage.getStorageKey();\n\n if (!bearerToken || !storageKey) {\n throw new Error('Missing BearerToken or storage key');\n }\n\n return { bearerToken, storageKey };\n }\n\n #performEnableProfileSyncing = async () => {\n try {\n await this.#storage.enableProfileSyncing();\n } catch (e) {\n log.error('Failed to enable profile syncing', e);\n throw new Error('Failed to enable profile syncing');\n }\n };\n\n #assertUserStorage(\n storage: UserStorage | null,\n ): asserts storage is UserStorage {\n if (!storage) {\n throw new Error('User Storage does not exist');\n }\n }\n\n /**\n * Retrieves and parses the user storage from the storage key.\n *\n * This method attempts to retrieve the user storage using the specified storage key,\n * then parses the JSON string to an object. If the storage is not found or cannot be parsed,\n * it throws an error.\n *\n * @returns The parsed user storage object or null\n */\n async #getUserStorage(): Promise<UserStorage | null> {\n const userStorageString: string | null =\n await this.#storage.getNotificationStorage();\n\n if (!userStorageString) {\n return null;\n }\n\n try {\n const userStorage: UserStorage = JSON.parse(userStorageString);\n return userStorage;\n } catch (error) {\n log.error('Unable to parse User Storage');\n return null;\n }\n }\n\n /**\n * Retrieves the current enabled state of MetaMask notifications.\n *\n * This method directly returns the boolean value of `isMetamaskNotificationsEnabled`\n * from the controller's state, indicating whether MetaMask notifications are currently enabled.\n *\n * @returns The enabled state of MetaMask notifications.\n */\n public selectIsNotificationServicesEnabled(): boolean {\n return this.state.isNotificationServicesEnabled;\n }\n\n /**\n * Sets the state of notification creation process.\n *\n * This method updates the `isUpdatingMetamaskNotifications` state, which can be used to indicate\n * whether the notification creation process is currently active or not. This is useful\n * for UI elements that need to reflect the state of ongoing operations, such as loading\n * indicators or disabled buttons during processing.\n *\n * @param isUpdatingMetamaskNotifications - A boolean value representing the new state of the notification creation process.\n */\n #setIsUpdatingMetamaskNotifications(\n isUpdatingMetamaskNotifications: boolean,\n ) {\n this.update((state) => {\n state.isUpdatingMetamaskNotifications = isUpdatingMetamaskNotifications;\n });\n }\n\n /**\n * Updates the state to indicate whether fetching of MetaMask notifications is in progress.\n *\n * This method is used to set the `isFetchingMetamaskNotifications` state, which can be utilized\n * to show or hide loading indicators in the UI when notifications are being fetched.\n *\n * @param isFetchingMetamaskNotifications - A boolean value representing the fetching state.\n */\n #setIsFetchingMetamaskNotifications(\n isFetchingMetamaskNotifications: boolean,\n ) {\n this.update((state) => {\n state.isFetchingMetamaskNotifications = isFetchingMetamaskNotifications;\n });\n }\n\n /**\n * Updates the state to indicate that the checking of accounts presence is in progress.\n *\n * This method modifies the `isCheckingAccountsPresence` state, which can be used to manage UI elements\n * that depend on the status of account presence checks, such as displaying loading indicators or disabling\n * buttons while the check is ongoing.\n *\n * @param isCheckingAccountsPresence - A boolean value indicating whether the account presence check is currently active.\n */\n #setIsCheckingAccountsPresence(isCheckingAccountsPresence: boolean) {\n this.update((state) => {\n state.isCheckingAccountsPresence = isCheckingAccountsPresence;\n });\n }\n\n /**\n * Updates the state to indicate that account updates are in progress.\n * Removes duplicate accounts before updating the state.\n *\n * @param accounts - The accounts being updated.\n */\n #updateUpdatingAccountsState(accounts: string[]) {\n this.update((state) => {\n const uniqueAccounts = new Set([\n ...state.isUpdatingMetamaskNotificationsAccount,\n ...accounts,\n ]);\n state.isUpdatingMetamaskNotificationsAccount = Array.from(uniqueAccounts);\n });\n }\n\n /**\n * Clears the state indicating that account updates are complete.\n *\n * @param accounts - The accounts that have finished updating.\n */\n #clearUpdatingAccountsState(accounts: string[]) {\n this.update((state) => {\n state.isUpdatingMetamaskNotificationsAccount =\n state.isUpdatingMetamaskNotificationsAccount.filter(\n (existingAccount) => !accounts.includes(existingAccount),\n );\n });\n }\n\n public async checkAccountsPresence(\n accounts: string[],\n ): Promise<Record<string, boolean>> {\n try {\n this.#setIsCheckingAccountsPresence(true);\n\n // Retrieve user storage\n const userStorage = await this.#getUserStorage();\n this.#assertUserStorage(userStorage);\n\n const presence = Utils.checkAccountsPresence(userStorage, accounts);\n return presence;\n } catch (error) {\n log.error('Failed to check accounts presence', error);\n throw error;\n } finally {\n this.#setIsCheckingAccountsPresence(false);\n }\n }\n\n /**\n * Sets the enabled state of feature announcements.\n *\n * **Action** - used in the notification settings to enable/disable feature announcements.\n *\n * @param featureAnnouncementsEnabled - A boolean value indicating the desired enabled state of the feature announcements.\n * @async\n * @throws {Error} If fails to update\n */\n public async setFeatureAnnouncementsEnabled(\n featureAnnouncementsEnabled: boolean,\n ) {\n try {\n this.update((s) => {\n s.isFeatureAnnouncementsEnabled = featureAnnouncementsEnabled;\n });\n } catch (e) {\n log.error('Unable to toggle feature announcements', e);\n throw new Error('Unable to toggle feature announcements');\n }\n }\n\n /**\n * This creates/re-creates on-chain triggers defined in User Storage.\n *\n * **Action** - Used during Sign In / Enabling of notifications.\n *\n * @returns The updated or newly created user storage.\n * @throws {Error} Throws an error if unauthenticated or from other operations.\n */\n public async createOnChainTriggers(): Promise<UserStorage> {\n try {\n this.#setIsUpdatingMetamaskNotifications(true);\n\n await this.#performEnableProfileSyncing();\n\n const { bearerToken, storageKey } =\n await this.#getValidStorageKeyAndBearerToken();\n\n const { accounts } = await this.#accounts.listAccounts();\n\n let userStorage = await this.#getUserStorage();\n\n // If userStorage does not exist, create a new one\n // All the triggers created are set as: \"disabled\"\n if (userStorage?.[USER_STORAGE_VERSION_KEY] === undefined) {\n userStorage = Utils.initializeUserStorage(\n accounts.map((account) => ({ address: account })),\n false,\n );\n\n // Write the userStorage\n await this.#storage.setNotificationStorage(JSON.stringify(userStorage));\n }\n\n // Create the triggers\n const triggers = Utils.traverseUserStorageTriggers(userStorage);\n await OnChainNotifications.createOnChainTriggers(\n userStorage,\n storageKey,\n bearerToken,\n triggers,\n );\n\n // Create push notifications triggers\n const allUUIDS = Utils.getAllUUIDs(userStorage);\n await this.#pushNotifications.enablePushNotifications(allUUIDS);\n\n // Write the new userStorage (triggers are now \"enabled\")\n await this.#storage.setNotificationStorage(JSON.stringify(userStorage));\n\n // Update the state of the controller\n this.update((state) => {\n state.isNotificationServicesEnabled = true;\n state.isFeatureAnnouncementsEnabled = true;\n state.isMetamaskNotificationsFeatureSeen = true;\n });\n\n return userStorage;\n } catch (err) {\n log.error('Failed to create On Chain triggers', err);\n throw new Error('Failed to create On Chain triggers');\n } finally {\n this.#setIsUpdatingMetamaskNotifications(false);\n }\n }\n\n /**\n * Enables all MetaMask notifications for the user.\n * This is identical flow when initializing notifications for the first time.\n * 1. Enable Profile Syncing\n * 2. Get or Create Notification User Storage\n * 3. Upsert Triggers\n * 4. Update Push notifications\n *\n * @throws {Error} If there is an error during the process of enabling notifications.\n */\n public async enableMetamaskNotifications() {\n try {\n this.#setIsUpdatingMetamaskNotifications(true);\n await this.createOnChainTriggers();\n } catch (e) {\n log.error('Unable to enable notifications', e);\n throw new Error('Unable to enable notifications');\n } finally {\n this.#setIsUpdatingMetamaskNotifications(false);\n }\n }\n\n /**\n * Disables all MetaMask notifications for the user.\n * This method ensures that the user is authenticated, retrieves all linked accounts,\n * and disables on-chain triggers for each account. It also sets the global notification\n * settings for MetaMask, feature announcements to false.\n *\n * @throws {Error} If the user is not authenticated or if there is an error during the process.\n */\n public async disableNotificationServices() {\n try {\n this.#setIsUpdatingMetamaskNotifications(true);\n\n // Disable Push Notifications\n const userStorage = await this.#getUserStorage();\n this.#assertUserStorage(userStorage);\n const UUIDs = Utils.getAllUUIDs(userStorage);\n await this.#pushNotifications.disablePushNotifications(UUIDs);\n\n // Clear Notification States (toggles and list)\n this.update((state) => {\n state.isNotificationServicesEnabled = false;\n state.isFeatureAnnouncementsEnabled = false;\n state.metamaskNotificationsList = [];\n });\n } catch (e) {\n log.error('Unable to disable notifications', e);\n throw new Error('Unable to disable notifications');\n } finally {\n this.#setIsUpdatingMetamaskNotifications(false);\n }\n }\n\n /**\n * Deletes on-chain triggers associated with a specific account.\n * This method performs several key operations:\n * 1. Validates Auth & Storage\n * 2. Finds and deletes all triggers associated with the account\n * 3. Disables any related push notifications\n * 4. Updates Storage to reflect new state.\n *\n * **Action** - When a user disables notifications for a given account in settings.\n *\n * @param accounts - The account for which on-chain triggers are to be deleted.\n * @returns A promise that resolves to void or an object containing a success message.\n * @throws {Error} Throws an error if unauthenticated or from other operations.\n */\n public async deleteOnChainTriggersByAccount(\n accounts: string[],\n ): Promise<UserStorage> {\n try {\n this.#updateUpdatingAccountsState(accounts);\n // Get and Validate BearerToken and User Storage Key\n const { bearerToken, storageKey } =\n await this.#getValidStorageKeyAndBearerToken();\n\n // Get & Validate User Storage\n const userStorage = await this.#getUserStorage();\n this.#assertUserStorage(userStorage);\n\n // Get the UUIDs to delete\n const UUIDs = accounts\n .map((a) => Utils.getUUIDsForAccount(userStorage, a.toLowerCase()))\n .flat();\n\n if (UUIDs.length === 0) {\n return userStorage;\n }\n\n // Delete these UUIDs (Mutates User Storage)\n await OnChainNotifications.deleteOnChainTriggers(\n userStorage,\n storageKey,\n bearerToken,\n UUIDs,\n );\n\n // Delete these UUIDs from the push notifications\n await this.#pushNotifications.disablePushNotifications(UUIDs);\n\n // Update User Storage\n await this.#storage.setNotificationStorage(JSON.stringify(userStorage));\n return userStorage;\n } catch (err) {\n log.error('Failed to delete OnChain triggers', err);\n throw new Error('Failed to delete OnChain triggers');\n } finally {\n this.#clearUpdatingAccountsState(accounts);\n }\n }\n\n /**\n * Updates/Creates on-chain triggers for a specific account.\n *\n * This method performs several key operations:\n * 1. Validates Auth & Storage\n * 2. Finds and creates any missing triggers associated with the account\n * 3. Enables any related push notifications\n * 4. Updates Storage to reflect new state.\n *\n * **Action** - When a user enables notifications for an account\n *\n * @param accounts - List of accounts you want to update.\n * @returns A promise that resolves to the updated user storage.\n * @throws {Error} Throws an error if unauthenticated or from other operations.\n */\n public async updateOnChainTriggersByAccount(\n accounts: string[],\n ): Promise<UserStorage> {\n try {\n this.#updateUpdatingAccountsState(accounts);\n // Get and Validate BearerToken and User Storage Key\n const { bearerToken, storageKey } =\n await this.#getValidStorageKeyAndBearerToken();\n\n // Get & Validate User Storage\n const userStorage = await this.#getUserStorage();\n this.#assertUserStorage(userStorage);\n\n // Add any missing triggers\n accounts.forEach((a) => Utils.upsertAddressTriggers(a, userStorage));\n\n const newTriggers = Utils.traverseUserStorageTriggers(userStorage, {\n mapTrigger: (t) => {\n if (!t.enabled) {\n return t;\n }\n return undefined;\n },\n });\n\n // Create any missing triggers.\n if (newTriggers.length > 0) {\n // Write te updated userStorage (where triggers are disabled)\n await this.#storage.setNotificationStorage(JSON.stringify(userStorage));\n\n // Create the triggers\n const triggers = Utils.traverseUserStorageTriggers(userStorage, {\n mapTrigger: (t) => {\n if (\n accounts.some((a) => a.toLowerCase() === t.address.toLowerCase())\n ) {\n return t;\n }\n return undefined;\n },\n });\n await OnChainNotifications.createOnChainTriggers(\n userStorage,\n storageKey,\n bearerToken,\n triggers,\n );\n }\n\n // Update Push Notifications Triggers\n const UUIDs = Utils.getAllUUIDs(userStorage);\n await this.#pushNotifications.updatePushNotifications(UUIDs);\n\n // Update the userStorage (where triggers are enabled)\n await this.#storage.setNotificationStorage(JSON.stringify(userStorage));\n return userStorage;\n } catch (err) {\n log.error('Failed to update OnChain triggers', err);\n throw new Error('Failed to update OnChain triggers');\n } finally {\n this.#clearUpdatingAccountsState(accounts);\n }\n }\n\n /**\n * Fetches the list of metamask notifications.\n * This includes OnChain notifications and Feature Announcements.\n *\n * **Action** - When a user views the notification list page/dropdown\n *\n * @throws {Error} Throws an error if unauthenticated or from other operations.\n */\n public async fetchAndUpdateMetamaskNotifications(): Promise<INotification[]> {\n try {\n this.#setIsFetchingMetamaskNotifications(true);\n\n // Raw Feature Notifications\n const rawFeatureAnnouncementNotifications = this.state\n .isFeatureAnnouncementsEnabled\n ? await FeatureNotifications.getFeatureAnnouncementNotifications(\n this.#featureAnnouncementEnv,\n ).catch(() => [])\n : [];\n\n // Raw On Chain Notifications\n const rawOnChainNotifications: OnChainRawNotification[] = [];\n const userStorage = await this.#storage\n .getNotificationStorage()\n .then((s) => s && (JSON.parse(s) as UserStorage))\n .catch(() => null);\n const bearerToken = await this.#auth.getBearerToken().catch(() => null);\n if (userStorage && bearerToken) {\n const notifications =\n await OnChainNotifications.getOnChainNotifications(\n userStorage,\n bearerToken,\n ).catch(() => []);\n\n rawOnChainNotifications.push(...notifications);\n }\n\n const readIds = this.state.metamaskNotificationsReadList;\n\n // Combined Notifications\n const isNotUndefined = <Item>(t?: Item): t is Item => Boolean(t);\n const processAndFilter = (ns: NotificationUnion[]) =>\n ns\n .map((n) => safeProcessNotification(n, readIds))\n .filter(isNotUndefined);\n\n const featureAnnouncementNotifications = processAndFilter(\n rawFeatureAnnouncementNotifications,\n );\n const onChainNotifications = processAndFilter(rawOnChainNotifications);\n\n const metamaskNotifications: INotification[] = [\n ...featureAnnouncementNotifications,\n ...onChainNotifications,\n ];\n metamaskNotifications.sort(\n (a, b) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),\n );\n\n // Update State\n this.update((state) => {\n state.metamaskNotificationsList = metamaskNotifications;\n });\n\n this.messagingSystem.publish(\n `${controllerName}:notificationsListUpdated`,\n this.state.metamaskNotificationsList,\n );\n\n this.#setIsFetchingMetamaskNotifications(false);\n return metamaskNotifications;\n } catch (err) {\n this.#setIsFetchingMetamaskNotifications(false);\n log.error('Failed to fetch notifications', err);\n throw new Error('Failed to fetch notifications');\n }\n }\n\n /**\n * Marks specified metamask notifications as read.\n *\n * @param notifications - An array of notifications to be marked as read. Each notification should include its type and read status.\n * @returns A promise that resolves when the operation is complete.\n */\n public async markMetamaskNotificationsAsRead(\n notifications: MarkAsReadNotificationsParam,\n ): Promise<void> {\n let onchainNotificationIds: string[] = [];\n let featureAnnouncementNotificationIds: string[] = [];\n\n try {\n // Filter unread on/off chain notifications\n const onChainNotifications = notifications.filter(\n (notification) =>\n notification.type !== TRIGGER_TYPES.FEATURES_ANNOUNCEMENT &&\n !notification.isRead,\n );\n\n const featureAnnouncementNotifications = notifications.filter(\n (notification) =>\n notification.type === TRIGGER_TYPES.FEATURES_ANNOUNCEMENT &&\n !notification.isRead,\n );\n\n // Mark On-Chain Notifications as Read\n if (onChainNotifications.length > 0) {\n const bearerToken = await this.#auth.getBearerToken();\n\n if (bearerToken) {\n onchainNotificationIds = onChainNotifications.map(\n (notification) => notification.id,\n );\n await OnChainNotifications.markNotificationsAsRead(\n bearerToken,\n onchainNotificationIds,\n ).catch(() => {\n onchainNotificationIds = [];\n log.warn('Unable to mark onchain notifications as read');\n });\n }\n }\n\n // Mark Off-Chain notifications as Read\n if (featureAnnouncementNotifications.length > 0) {\n featureAnnouncementNotificationIds =\n featureAnnouncementNotifications.map(\n (notification) => notification.id,\n );\n }\n } catch (err) {\n log.warn('Something failed when marking notifications as read', err);\n }\n\n // Update the state (state is also used on counter & badge)\n this.update((state) => {\n const currentReadList = state.metamaskNotificationsReadList;\n const newReadIds = [...featureAnnouncementNotificationIds];\n state.metamaskNotificationsReadList = [\n ...new Set([...currentReadList, ...newReadIds]),\n ];\n\n state.metamaskNotificationsList = state.metamaskNotificationsList.map(\n (notification: INotification) => {\n if (\n newReadIds.includes(notification.id) ||\n onchainNotificationIds.includes(notification.id)\n ) {\n return { ...notification, isRead: true };\n }\n return notification;\n },\n );\n });\n\n this.messagingSystem.publish(\n `${controllerName}:markNotificationsAsRead`,\n this.state.metamaskNotificationsList,\n );\n }\n\n /**\n * Updates the list of MetaMask notifications by adding a new notification at the beginning of the list.\n * This method ensures that the most recent notification is displayed first in the UI.\n *\n * @param notification - The new notification object to be added to the list.\n * @returns A promise that resolves when the notification list has been successfully updated.\n */\n public async updateMetamaskNotificationsList(\n notification: INotification,\n ): Promise<void> {\n if (\n this.state.metamaskNotificationsList.some((n) => n.id === notification.id)\n ) {\n return;\n }\n\n const processedNotification = safeProcessNotification(notification);\n\n if (processedNotification) {\n this.update((state) => {\n const existingNotificationIds = new Set(\n state.metamaskNotificationsList.map((n) => n.id),\n );\n // Add the new notification only if its ID is not already present in the list\n if (!existingNotificationIds.has(notification.id)) {\n state.metamaskNotificationsList = [\n notification,\n ...state.metamaskNotificationsList,\n ];\n this.messagingSystem.publish(\n `${controllerName}:notificationsListUpdated`,\n state.metamaskNotificationsList,\n );\n }\n });\n }\n }\n}\n"],"mappings":"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","names":[]}