{"version":3,"file":"feature-announcements.cjs","sourceRoot":"","sources":["../../../src/NotificationServicesController/services/feature-announcements.ts"],"names":[],"mappings":"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","sourcesContent":["import { documentToHtmlString } from '@contentful/rich-text-html-renderer';\nimport type { Entry, Asset, EntryCollection } from 'contentful';\n\nimport { TRIGGER_TYPES } from '../constants/notification-schema';\nimport { processFeatureAnnouncement } from '../processors/process-feature-announcement';\nimport type { FeatureAnnouncementRawNotification } from '../types/feature-announcement/feature-announcement';\nimport type {\n  ImageFields,\n  TypeFeatureAnnouncement,\n} from '../types/feature-announcement/type-feature-announcement';\nimport type {\n  TypeExternalLinkFields,\n  TypePortfolioLinkFields,\n  TypeExtensionLinkFields,\n  TypeMobileLinkFields,\n} from '../types/feature-announcement/type-links';\nimport type { INotification } from '../types/notification/notification';\nimport { isVersionInBounds } from '../utils/isVersionInBounds';\n\n// Feature announcements older than this (by sys.updatedAt) are excluded from the feed.\nconst FEATURE_ANNOUNCEMENT_MAX_AGE_MONTHS = 3;\n\nconst DEFAULT_SPACE_ID = ':space_id';\nconst DEFAULT_ACCESS_TOKEN = ':access_token';\nconst DEFAULT_CLIENT_ID = ':client_id';\nconst DEFAULT_DOMAIN = 'cdn.contentful.com';\nconst PREVIEW_DOMAIN = 'preview.contentful.com';\nexport const FEATURE_ANNOUNCEMENT_API = `https://${DEFAULT_DOMAIN}/spaces/${DEFAULT_SPACE_ID}/environments/master/entries`;\nexport const FEATURE_ANNOUNCEMENT_URL = `${FEATURE_ANNOUNCEMENT_API}?access_token=${DEFAULT_ACCESS_TOKEN}&content_type=productAnnouncement&include=10&fields.clients[in]=${DEFAULT_CLIENT_ID}`;\n\ntype Env = {\n  spaceId: string;\n  accessToken: string;\n  platform: 'extension' | 'mobile';\n  platformVersion?: string;\n};\n\n/**\n * Contentful API Response Shape\n */\nexport type ContentfulResult = {\n  includes?: {\n    // Property names match Contentful API response structure\n    // eslint-disable-next-line @typescript-eslint/naming-convention\n    Entry?: Entry[];\n    // eslint-disable-next-line @typescript-eslint/naming-convention\n    Asset?: Asset[];\n  };\n  items?: TypeFeatureAnnouncement[];\n};\n\nexport const getFeatureAnnouncementUrl = (\n  env: Env,\n  previewToken?: string,\n): string => {\n  const domain = previewToken ? PREVIEW_DOMAIN : DEFAULT_DOMAIN;\n  const replacedUrl = FEATURE_ANNOUNCEMENT_URL.replace(\n    DEFAULT_SPACE_ID,\n    env.spaceId,\n  )\n    .replace(DEFAULT_ACCESS_TOKEN, previewToken ?? env.accessToken)\n    .replace(DEFAULT_CLIENT_ID, env.platform)\n    .replace(DEFAULT_DOMAIN, domain);\n  return encodeURI(replacedUrl);\n};\n\nconst fetchFeatureAnnouncementNotifications = async (\n  env: Env,\n  previewToken?: string,\n): Promise<FeatureAnnouncementRawNotification[]> => {\n  const url = getFeatureAnnouncementUrl(env, previewToken);\n\n  const data = await fetch(url)\n    .then((response) => response.json())\n    .catch(() => null);\n\n  if (!data) {\n    return [];\n  }\n\n  const findIncludedItem = (\n    sysId: string,\n  ):\n    | ImageFields['fields']\n    | TypeExtensionLinkFields['fields']\n    | TypePortfolioLinkFields['fields']\n    | TypeMobileLinkFields['fields']\n    | TypeExternalLinkFields['fields']\n    | null => {\n    const typedData: EntryCollection<\n      | ImageFields\n      | TypeExtensionLinkFields\n      | TypePortfolioLinkFields\n      | TypeMobileLinkFields\n      | TypeExternalLinkFields\n    > = data;\n    const item =\n      typedData?.includes?.Entry?.find(\n        (entry: Entry) => entry?.sys?.id === sysId,\n      ) ??\n      typedData?.includes?.Asset?.find(\n        (asset: Asset) => asset?.sys?.id === sysId,\n      );\n    return item ? item?.fields : null;\n  };\n\n  const contentfulNotifications = data?.items ?? [];\n  const rawNotifications: FeatureAnnouncementRawNotification[] =\n    contentfulNotifications\n      .filter((item: TypeFeatureAnnouncement) => {\n        const updatedAt = new Date(item.sys.updatedAt);\n        const limitDate = new Date();\n        limitDate.setMonth(\n          limitDate.getMonth() - FEATURE_ANNOUNCEMENT_MAX_AGE_MONTHS,\n        );\n        return updatedAt > limitDate;\n      })\n      .map((item: TypeFeatureAnnouncement) => {\n        const { fields } = item;\n        const imageFields = fields.image\n          ? (findIncludedItem(fields.image.sys.id) as ImageFields['fields'])\n          : undefined;\n\n        const externalLinkFields = fields.externalLink\n          ? (findIncludedItem(\n              fields.externalLink.sys.id,\n            ) as TypeExternalLinkFields['fields'])\n          : undefined;\n        const portfolioLinkFields = fields.portfolioLink\n          ? (findIncludedItem(\n              fields.portfolioLink.sys.id,\n            ) as TypePortfolioLinkFields['fields'])\n          : undefined;\n        const extensionLinkFields = fields.extensionLink\n          ? (findIncludedItem(\n              fields.extensionLink.sys.id,\n            ) as TypeExtensionLinkFields['fields'])\n          : undefined;\n        const mobileLinkFields = fields.mobileLink\n          ? (findIncludedItem(\n              fields.mobileLink.sys.id,\n            ) as TypeMobileLinkFields['fields'])\n          : undefined;\n\n        const notification: FeatureAnnouncementRawNotification = {\n          type: TRIGGER_TYPES.FEATURES_ANNOUNCEMENT,\n          createdAt: new Date(item.sys.createdAt).toString(),\n          data: {\n            id: fields.id,\n            category: fields.category,\n            title: fields.title,\n            longDescription: documentToHtmlString(fields.longDescription),\n            shortDescription: fields.shortDescription,\n            image: {\n              title: imageFields?.title,\n              description: imageFields?.description,\n              url: imageFields?.file?.url ?? '',\n            },\n            externalLink: externalLinkFields && {\n              externalLinkText: externalLinkFields?.externalLinkText,\n              externalLinkUrl: externalLinkFields?.externalLinkUrl,\n            },\n            portfolioLink: portfolioLinkFields && {\n              portfolioLinkText: portfolioLinkFields?.portfolioLinkText,\n              portfolioLinkUrl: portfolioLinkFields?.portfolioLinkUrl,\n            },\n            extensionLink: extensionLinkFields && {\n              extensionLinkText: extensionLinkFields?.extensionLinkText,\n              extensionLinkRoute: extensionLinkFields?.extensionLinkRoute,\n            },\n            mobileLink: mobileLinkFields && {\n              mobileLinkText: mobileLinkFields?.mobileLinkText,\n              mobileLinkUrl: mobileLinkFields?.mobileLinkUrl,\n            },\n            extensionMinimumVersionNumber: fields.extensionMinimumVersionNumber,\n            mobileMinimumVersionNumber: fields.mobileMinimumVersionNumber,\n            extensionMaximumVersionNumber: fields.extensionMaximumVersionNumber,\n            mobileMaximumVersionNumber: fields.mobileMaximumVersionNumber,\n          },\n        };\n\n        return notification;\n      });\n\n  const versionKeys = {\n    extension: {\n      min: 'extensionMinimumVersionNumber',\n      max: 'extensionMaximumVersionNumber',\n    },\n    mobile: {\n      min: 'mobileMinimumVersionNumber',\n      max: 'mobileMaximumVersionNumber',\n    },\n  } as const;\n\n  const filteredRawNotifications = rawNotifications.filter(\n    (rawNotification) => {\n      const minVersion = rawNotification.data?.[versionKeys[env.platform].min];\n      const maxVersion = rawNotification.data?.[versionKeys[env.platform].max];\n      return isVersionInBounds({\n        currentVersion: env.platformVersion,\n        minVersion,\n        maxVersion,\n      });\n    },\n  );\n\n  return filteredRawNotifications;\n};\n\n/**\n * Gets Feature Announcement from our services\n *\n * @param env - environment for feature announcements\n * @param previewToken - the preview token to use if needed\n * @returns Raw Feature Announcements\n */\nexport async function getFeatureAnnouncementNotifications(\n  env: Env,\n  previewToken?: string,\n): Promise<INotification[]> {\n  if (env?.accessToken && env?.spaceId && env?.platform) {\n    const rawNotifications = await fetchFeatureAnnouncementNotifications(\n      env,\n      previewToken,\n    );\n    const notifications = rawNotifications.map((notification) =>\n      processFeatureAnnouncement(notification),\n    );\n\n    return notifications;\n  }\n\n  return [];\n}\n"]}