{"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} 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  // 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 NotificationServicesControllerMessengerEvents =\n  ControllerStateChangeEvent<\n    typeof controllerName,\n    NotificationServicesControllerState\n  >;\n\n// Allowed Events\nexport type AllowedEvents =\n  | KeyringControllerStateChangeEvent\n  | NotificationServicesPushControllerOnNewNotification;\n\n// Type for the messenger of NotificationServicesController\nexport type NotificationServicesControllerMessenger =\n  RestrictedControllerMessenger<\n    typeof controllerName,\n    Actions | AllowedActions,\n    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 class NotificationServicesController extends BaseController<\n  typeof controllerName,\n  NotificationServicesControllerState,\n  NotificationServicesControllerMessenger\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        'notificationSettings',\n      );\n    },\n    setNotificationStorage: async (state: string) => {\n      return await this.messagingSystem.call(\n        'UserStorageController:performSetStorage',\n        'notificationSettings',\n        state,\n      );\n    },\n  };\n\n  #pushNotifications = {\n    enablePushNotifications: async (UUIDs: string[]) => {\n      return await this.messagingSystem.call(\n        'NotificationServicesPushController:enablePushNotifications',\n        UUIDs,\n      );\n    },\n    disablePushNotifications: async (UUIDs: string[]) => {\n      return await this.messagingSystem.call(\n        'NotificationServicesPushController:disablePushNotifications',\n        UUIDs,\n      );\n    },\n    updatePushNotifications: async (UUIDs: string[]) => {\n      return await this.messagingSystem.call(\n        'NotificationServicesPushController:updateTriggerPushNotifications',\n        UUIDs,\n      );\n    },\n    subscribe: () => {\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.state.isNotificationServicesEnabled) {\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    },\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   */\n  constructor({\n    messenger,\n    state,\n    env,\n  }: {\n    messenger: NotificationServicesControllerMessenger;\n    state?: Partial<NotificationServicesControllerState>;\n    env: {\n      featureAnnouncements: FeatureAnnouncementEnv;\n    };\n  }) {\n    super({\n      messenger,\n      metadata,\n      name: controllerName,\n      state: { ...defaultState, ...state },\n    });\n\n    this.#featureAnnouncementEnv = env.featureAnnouncements;\n    this.#registerMessageHandlers();\n    this.#clearLoadingStates();\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.#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\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        }\n      });\n    }\n  }\n}\n"],"mappings":"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","names":[]}