{"version":3,"sources":["../src/NotificationServicesPushController/services/services.ts"],"sourcesContent":["import log from 'loglevel';\n\nimport type { Types } from '../../NotificationServicesController';\nimport type { PushNotificationEnv } from '../types';\nimport * as endpoints from './endpoints';\nimport type { CreateRegToken, DeleteRegToken } from './push';\nimport {\n  listenToPushNotificationsClicked,\n  listenToPushNotificationsReceived,\n} from './push/push-web';\n\nexport type RegToken = {\n  token: string;\n  platform: 'extension' | 'mobile' | 'portfolio';\n};\n\n/**\n * Links API Response Shape\n */\nexport type LinksResult = {\n  // eslint-disable-next-line @typescript-eslint/naming-convention\n  trigger_ids: string[];\n  // eslint-disable-next-line @typescript-eslint/naming-convention\n  registration_tokens: RegToken[];\n};\n\n/**\n * Fetches push notification links from a remote endpoint using a BearerToken for authorization.\n *\n * @param bearerToken - The JSON Web Token used for authorization.\n * @returns A promise that resolves with the links result or null if an error occurs.\n */\nexport async function getPushNotificationLinks(\n  bearerToken: string,\n): Promise<LinksResult | null> {\n  try {\n    const response = await fetch(endpoints.REGISTRATION_TOKENS_ENDPOINT, {\n      headers: { Authorization: `Bearer ${bearerToken}` },\n    });\n    if (!response.ok) {\n      log.error('Failed to fetch the push notification links');\n      throw new Error('Failed to fetch the push notification links');\n    }\n    return response.json() as Promise<LinksResult>;\n  } catch (error) {\n    log.error('Failed to fetch the push notification links', error);\n    return null;\n  }\n}\n\n/**\n * Updates the push notification links on a remote API.\n *\n * @param bearerToken - The JSON Web Token used for authorization.\n * @param triggers - An array of trigger identifiers.\n * @param regTokens - An array of registration tokens.\n * @returns A promise that resolves with true if the update was successful, false otherwise.\n */\nexport async function updateLinksAPI(\n  bearerToken: string,\n  triggers: string[],\n  regTokens: RegToken[],\n): Promise<boolean> {\n  try {\n    const body: LinksResult = {\n      // eslint-disable-next-line @typescript-eslint/naming-convention\n      trigger_ids: triggers,\n      // eslint-disable-next-line @typescript-eslint/naming-convention\n      registration_tokens: regTokens,\n    };\n    const response = await fetch(endpoints.REGISTRATION_TOKENS_ENDPOINT, {\n      method: 'POST',\n      headers: {\n        Authorization: `Bearer ${bearerToken}`,\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify(body),\n    });\n    return response.status === 200;\n  } catch {\n    return false;\n  }\n}\n\ntype ActivatePushNotificationsParams = {\n  // Push Links\n  bearerToken: string;\n  triggers: string[];\n\n  // Push Registration\n  env: PushNotificationEnv;\n  createRegToken: CreateRegToken;\n  platform: 'extension' | 'mobile' | 'portfolio';\n};\n\n/**\n * Enables push notifications by registering the device and linking triggers.\n *\n * @param params - Activate Push Params\n * @returns A promise that resolves with an object containing the success status and the BearerToken token.\n */\nexport async function activatePushNotifications(\n  params: ActivatePushNotificationsParams,\n): Promise<string | null> {\n  const { bearerToken, triggers, env, createRegToken, platform } = params;\n\n  const notificationLinks = await getPushNotificationLinks(bearerToken);\n\n  if (!notificationLinks) {\n    return null;\n  }\n\n  const regToken = await createRegToken(env).catch(() => null);\n  if (!regToken) {\n    return null;\n  }\n\n  const newRegTokens = new Set(notificationLinks.registration_tokens);\n  newRegTokens.add({ token: regToken, platform });\n\n  await updateLinksAPI(bearerToken, triggers, Array.from(newRegTokens));\n  return regToken;\n}\n\ntype DeactivatePushNotificationsParams = {\n  // Push Links\n  regToken: string;\n  bearerToken: string;\n  triggers: string[];\n\n  // Push Un-registration\n  env: PushNotificationEnv;\n  deleteRegToken: DeleteRegToken;\n};\n\n/**\n * Disables push notifications by removing the registration token and unlinking triggers.\n *\n * @param params - Deactivate Push Params\n * @returns A promise that resolves with true if notifications were successfully disabled, false otherwise.\n */\nexport async function deactivatePushNotifications(\n  params: DeactivatePushNotificationsParams,\n): Promise<boolean> {\n  const { regToken, bearerToken, triggers, env, deleteRegToken } = params;\n\n  // if we don't have a reg token, then we can early return\n  if (!regToken) {\n    return true;\n  }\n\n  const notificationLinks = await getPushNotificationLinks(bearerToken);\n  if (!notificationLinks) {\n    return false;\n  }\n\n  const filteredRegTokens = notificationLinks.registration_tokens.filter(\n    (r) => r.token !== regToken,\n  );\n\n  const isTokenRemovedFromAPI = await updateLinksAPI(\n    bearerToken,\n    triggers,\n    filteredRegTokens,\n  );\n  if (!isTokenRemovedFromAPI) {\n    return false;\n  }\n\n  const isTokenRemovedFromFCM = await deleteRegToken(env);\n  if (!isTokenRemovedFromFCM) {\n    return false;\n  }\n\n  return true;\n}\n\ntype UpdateTriggerPushNotificationsParams = {\n  // Push Links\n  regToken: string;\n  bearerToken: string;\n  triggers: string[];\n\n  // Push Registration\n  env: PushNotificationEnv;\n  createRegToken: CreateRegToken;\n  platform: 'extension' | 'mobile' | 'portfolio';\n\n  // Push Un-registration\n  deleteRegToken: DeleteRegToken;\n};\n\n/**\n * Updates the triggers linked to push notifications for a given registration token.\n * If the provided registration token does not exist or is not in the current set of registration tokens,\n * a new registration token is created and used for the update.\n *\n * @param params - Update Push Params\n * @returns A promise that resolves with an object containing:\n * - isTriggersLinkedToPushNotifications: boolean indicating if the triggers were successfully updated.\n * - fcmToken: the new or existing Firebase Cloud Messaging token used for the update, if applicable.\n */\nexport async function updateTriggerPushNotifications(\n  params: UpdateTriggerPushNotificationsParams,\n): Promise<{\n  isTriggersLinkedToPushNotifications: boolean;\n  fcmToken?: string | null;\n}> {\n  const {\n    bearerToken,\n    regToken,\n    triggers,\n    createRegToken,\n    platform,\n    deleteRegToken,\n    env,\n  } = params;\n\n  const notificationLinks = await getPushNotificationLinks(bearerToken);\n  if (!notificationLinks) {\n    return { isTriggersLinkedToPushNotifications: false };\n  }\n  // Create new registration token if doesn't exist\n  const hasRegToken = Boolean(\n    regToken &&\n      notificationLinks.registration_tokens.some((r) => r.token === regToken),\n  );\n\n  let newRegToken: string | null = null;\n  if (!hasRegToken) {\n    await deleteRegToken(env);\n    newRegToken = await createRegToken(env);\n    if (!newRegToken) {\n      throw new Error('Failed to create a new registration token');\n    }\n    notificationLinks.registration_tokens.push({\n      token: newRegToken,\n      platform,\n    });\n  }\n\n  const isTriggersLinkedToPushNotifications = await updateLinksAPI(\n    bearerToken,\n    triggers,\n    notificationLinks.registration_tokens,\n  );\n\n  return {\n    isTriggersLinkedToPushNotifications,\n    fcmToken: newRegToken ?? null,\n  };\n}\n\ntype ListenToPushNotificationsParams = {\n  env: PushNotificationEnv;\n  listenToPushReceived: (\n    notification: Types.INotification,\n  ) => void | Promise<void>;\n  listenToPushClicked: (\n    event: NotificationEvent,\n    notification?: Types.INotification,\n  ) => void;\n};\n\n/**\n * Listens to push notifications and invokes the provided callback function with the received notification data.\n *\n * @param params - listen params\n * @returns A promise that resolves to an unsubscribe function to stop listening to push notifications.\n */\nexport async function listenToPushNotifications(\n  params: ListenToPushNotificationsParams,\n): Promise<() => void> {\n  const { env, listenToPushReceived, listenToPushClicked } = params;\n\n  /*\n  Push notifications require 2 listeners that need tracking (when creating and for tearing down):\n  1. handling receiving a push notification (and the content we want to display)\n  2. handling when a user clicks on a push notification\n  */\n  const unsubscribePushNotifications = await listenToPushNotificationsReceived(\n    env,\n    listenToPushReceived,\n  );\n  const unsubscribeNotificationClicks =\n    listenToPushNotificationsClicked(listenToPushClicked);\n\n  const unsubscribe = () => {\n    unsubscribePushNotifications();\n    unsubscribeNotificationClicks();\n  };\n\n  return unsubscribe;\n}\n"],"mappings":"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","names":[]}