{"version":3,"file":"index.cjs","sources":["../../src/interface.ts","../../src/utils.ts","../../src/api.ts","../../src/preferences.ts","../../src/user.ts","../../src/webpush.ts","../../src/feed.ts","../../src/main.ts"],"sourcesContent":["export type Dictionary = Record<string, unknown>;\n\nexport interface SuprSendOptions {\n  host?: string;\n  vapidKey?: string;\n  swFileName?: string;\n}\n\nexport type RefreshTokenCallback = (\n  oldUserToken: string,\n  tokenPayload: Dictionary\n) => Promise<string>;\n\nexport interface AuthenticateOptions {\n  refreshUserToken?: RefreshTokenCallback;\n}\n\nexport interface ResponseOptions {\n  status: RESPONSE_STATUS.ERROR | RESPONSE_STATUS.SUCCESS;\n  statusCode?: number;\n  // eslint-disable-next-line\n  body?: any;\n  errorMessage?: string;\n  errorType?: string;\n}\n\ninterface IError {\n  type?: string;\n  message?: string;\n}\n\nexport interface ApiResponse {\n  status: RESPONSE_STATUS.ERROR | RESPONSE_STATUS.SUCCESS;\n  statusCode?: number;\n  error?: IError;\n  // eslint-disable-next-line\n  body?: any;\n}\n\nexport enum PreferenceOptions {\n  OPT_IN = 'opt_in',\n  OPT_OUT = 'opt_out',\n}\n\nexport enum ChannelLevelPreferenceOptions {\n  ALL = 'all',\n  REQUIRED = 'required',\n}\n\nexport interface CategoryChannel {\n  channel: string;\n  preference: PreferenceOptions;\n  is_editable: boolean;\n}\n\nexport interface Category {\n  name: string;\n  category: string;\n  description?: string | null;\n  preference: PreferenceOptions;\n  is_editable: boolean;\n  channels?: CategoryChannel[] | null;\n}\n\nexport interface Section {\n  name?: string | null;\n  description?: string | null;\n  subcategories?: Category[] | null;\n}\n\nexport interface ChannelPreference {\n  channel: string;\n  is_restricted: boolean;\n}\n\nexport interface PreferenceData {\n  sections?: Section[] | null;\n  channel_preferences?: ChannelPreference[] | null;\n}\n\nexport interface PreferenceApiResponse extends ApiResponse {\n  body: PreferenceData;\n}\n\n// eslint-disable-next-line\nexport type EmitterEvents = {\n  preferences_updated: PreferenceApiResponse;\n  preferences_error: ApiResponse;\n};\n\n// eslint-disable-next-line\nexport type InboxEmitterEvents = {\n  'feed.new_notification': IRemoteNotification;\n  'feed.store_update': IFeedData;\n  '*': undefined;\n};\n\nexport interface HandleRequest {\n  type: 'get' | 'post' | 'patch';\n  url: string;\n  payload?: Dictionary;\n  signal?: AbortSignal;\n}\n\nexport interface ValidatedDataOptions {\n  allowReservedKeys?: boolean;\n  valueType?: string;\n}\n\nexport enum ERROR_TYPE {\n  VALIDATION_ERROR = 'VALIDATION_ERROR',\n  NETWORK_ERROR = 'NETWORK_ERROR',\n  UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n  PERMISSION_DENIED = 'PERMISSION_DENIED',\n  UNSUPPORTED_ACTION = 'UNSUPPORTED_ACTION',\n  NOT_FOUND = 'NOT_FOUND',\n}\n\nexport enum RESPONSE_STATUS {\n  SUCCESS = 'success',\n  ERROR = 'error',\n}\n\nexport interface IStore {\n  storeId: string;\n  label: string;\n  query?: {\n    tags?: string | string[];\n    categories?: string | string[];\n    read?: boolean;\n    archived?: boolean;\n  };\n}\n\nexport enum ApiResponseStatus {\n  INITIAL = 'INITIAL', //  Before any request is made (or after a reset).\n  LOADING = 'LOADING', // The initial API call is in progress\n  SUCCESS = 'SUCCESS', // The API call was successful, and data has been received\n  ERROR = 'ERROR', // The API call failed (network issue, server issue, etc.)\n  FETCHING_MORE = 'FETCHING_MORE', //  The API call is fetching additional data (for pagination or infinite scroll)\n}\n\nexport interface IActionObject {\n  name: string;\n  url: string;\n  open_in_new_tab?: boolean;\n}\n\nexport interface IAvatarObject {\n  action_url?: string;\n  avatar_url: string;\n}\n\nexport interface ISubTextObject {\n  action_url?: string;\n  text: string;\n}\n\nexport interface IRemoteNotificationMessage {\n  header?: string;\n  schema: string;\n  text: string;\n  url?: string;\n  open_in_new_tab?: boolean;\n  extra_data?: string;\n  actions?: IActionObject[];\n  avatar?: IAvatarObject;\n  subtext?: ISubTextObject;\n}\n\nexport interface IRemoteNotification {\n  n_id: string;\n  n_category: string;\n  created_on: number;\n  seen_on?: number;\n  read_on?: number | null;\n  interacted_on?: number;\n  archived?: boolean;\n  tags?: string[];\n  expiry?: number;\n  is_expiry_visible: boolean;\n  is_pinned: boolean;\n  can_user_unpin?: boolean;\n  message: IRemoteNotificationMessage;\n}\n\nexport interface IFeedOptions {\n  tenantId?: string;\n  pageSize?: number;\n  stores?: IStore[] | null;\n  host?: { socketHost?: string; apiHost?: string };\n}\n\nexport interface INotificationStore {\n  notifications: IRemoteNotification[];\n  store: IStore;\n  pageInfo: {\n    total: number;\n    hasMore: boolean;\n    pageSize: number;\n  };\n  meta: Record<string, number>;\n  apiStatus: ApiResponseStatus;\n  isFirstFetch: boolean;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface IFeedData\n  extends Omit<INotificationStore, '_firstFetchedTimeStamp'> {}\n\nexport interface IInboxFetchOptions {\n  pageSize?: number;\n}\n\nexport interface IPreferenceConfig {\n  tenantId?: string;\n  showOptOutChannels?: boolean;\n  tags?: string | Dictionary;\n  locale?: string;\n}\n","import {\n  ApiResponse,\n  Dictionary,\n  ResponseOptions,\n  RESPONSE_STATUS,\n} from './interface';\n\nexport function uuid() {\n  let dt = new Date().getTime();\n  const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n    /[xy]/g,\n    function (c) {\n      const r = (dt + Math.random() * 16) % 16 | 0;\n      dt = Math.floor(dt / 16);\n      return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);\n    }\n  );\n  return uuid;\n}\n\nexport function epochMs() {\n  return Math.round(Date.now());\n}\n\nexport function isObjectEmpty(objectName: Dictionary) {\n  return Object.keys(objectName).length === 0;\n}\n\nexport function isArrayEmpty(arrayName: unknown[]) {\n  return arrayName?.length <= 0;\n}\n\nexport function urlB64ToUint8Array(base64String: string) {\n  const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n  const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n  const rawData = atob(base64);\n  const outputArray = new Uint8Array(rawData.length);\n  for (let i = 0; i < rawData.length; ++i) {\n    outputArray[i] = rawData.charCodeAt(i);\n  }\n  return outputArray;\n}\n\nexport function debounce<T extends unknown[], U>(\n  callback: (...args: T) => PromiseLike<U> | U,\n  wait: number\n) {\n  let timer: ReturnType<typeof setTimeout>;\n\n  return (...args: T): Promise<U> => {\n    clearTimeout(timer);\n    return new Promise((resolve) => {\n      timer = setTimeout(() => resolve(callback(...args)), wait);\n    });\n  };\n}\n\n// https://gist.github.com/nzvtrk/1a444cdf6a86a5a6e6d6a34f0db19065\nexport function debounceByType(func, wait) {\n  const memory = {};\n\n  return (...args) => {\n    const [searchType] = args;\n    const payload = args.slice(1);\n\n    if (typeof memory[searchType] === 'function') {\n      return memory[searchType](...payload);\n    }\n\n    memory[searchType] = debounce(func, wait);\n    return memory[searchType](...payload);\n  };\n}\n\nexport function getResponsePayload(options: ResponseOptions) {\n  const response: ApiResponse = { status: options.status };\n\n  if (options.statusCode) {\n    response.statusCode = options.statusCode;\n  }\n\n  if (options.body) {\n    response.body = options.body;\n  }\n\n  if (options.status === RESPONSE_STATUS.ERROR) {\n    response.error = {\n      type: options.errorType,\n      message: options.errorMessage,\n    };\n  }\n  return response;\n}\n\nexport function windowSupport() {\n  return typeof window !== 'undefined';\n}\n\nexport function setLocalStorageData(key: string, value: string) {\n  if (!windowSupport()) return;\n\n  if (typeof value === 'object') {\n    value = JSON.stringify(value);\n  }\n  localStorage.setItem(key, value);\n}\n\nexport function getLocalStorageData(key: string) {\n  if (!windowSupport()) return;\n\n  const value = localStorage.getItem(key);\n  if (!value) return;\n  try {\n    return JSON.parse(value);\n  } catch (e) {\n    return value;\n  }\n}\n\nexport function removeLocalStorageData(key: string) {\n  if (!windowSupport()) return;\n\n  localStorage.removeItem(key);\n}\n\nexport async function sha256Hash(input: string): Promise<string> {\n  const encoder = new TextEncoder();\n  const data = encoder.encode(input);\n  const hashBuffer = await crypto.subtle.digest('SHA-256', data);\n  const hashArray = Array.from(new Uint8Array(hashBuffer));\n  const hashHex = hashArray\n    .map((b) => b.toString(16).padStart(2, '0'))\n    .join('');\n  return hashHex;\n}\n","import jwt_decode from 'jwt-decode';\nimport SuprSend from './main';\nimport {\n  Dictionary,\n  HandleRequest,\n  ERROR_TYPE,\n  RESPONSE_STATUS,\n} from './interface';\nimport { getResponsePayload } from './utils';\n\nexport default class ApiClient {\n  private config: SuprSend;\n\n  constructor(config: SuprSend) {\n    this.config = config;\n  }\n\n  private getHeaders() {\n    const headers = {\n      'Content-Type': 'application/json',\n      Authorization: this.config.publicApiKey,\n    };\n\n    if (this.config.userToken) {\n      headers['x-ss-signature'] = this.config.userToken;\n    }\n\n    return headers;\n  }\n\n  private requestApiInstance(reqData: HandleRequest) {\n    switch (reqData.type) {\n      case 'get':\n        return this.get(reqData.url, reqData.signal);\n      case 'post':\n        return this.post(reqData.url, reqData?.payload || {}, reqData.signal);\n      case 'patch':\n        return this.patch(reqData.url, reqData?.payload || {}, reqData.signal);\n      default:\n        return this.get(reqData.url, reqData.signal);\n    }\n  }\n\n  private get(url: string, signal?: AbortSignal) {\n    return fetch(url, {\n      method: 'GET',\n      headers: this.getHeaders(),\n      signal,\n    });\n  }\n\n  private post(url: string, payload: Dictionary, signal?: AbortSignal) {\n    return fetch(url, {\n      method: 'POST',\n      body: JSON.stringify(payload),\n      headers: this.getHeaders(),\n      signal,\n    });\n  }\n\n  private patch(url: string, payload: Dictionary, signal?: AbortSignal) {\n    return fetch(url, {\n      method: 'PATCH',\n      body: JSON.stringify(payload),\n      headers: this.getHeaders(),\n      signal,\n    });\n  }\n\n  async request(reqData: HandleRequest) {\n    if (!this.config.distinctId) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          \"User isn't authenticated. Call identify method before performing any action\",\n      });\n    }\n\n    if (\n      this.config.authenticateOptions?.refreshUserToken &&\n      this.config.userToken\n    ) {\n      const jwtPayload = jwt_decode(this.config.userToken) as Dictionary;\n      const expiresOn = ((jwtPayload.exp as number) || 0) * 1000; // in ms\n      const now = Date.now(); // in ms\n      const hasExpired = expiresOn <= now;\n      if (hasExpired) {\n        try {\n          const newUserToken =\n            await this.config.authenticateOptions.refreshUserToken(\n              this.config.userToken,\n              jwtPayload\n            );\n\n          if (newUserToken && typeof newUserToken === 'string') {\n            this.config.identify(\n              this.config.distinctId,\n              newUserToken,\n              this.config.authenticateOptions\n            );\n          }\n        } catch (e) {\n          // error while getting token go ahead with calling api\n        }\n      }\n    }\n\n    try {\n      const resp = await this.requestApiInstance(reqData);\n      const respData = await resp.json();\n\n      const respStatus =\n        respData?.status ||\n        (resp.ok ? RESPONSE_STATUS.SUCCESS : RESPONSE_STATUS.ERROR);\n\n      return getResponsePayload({\n        status: respStatus,\n        body: respData,\n        statusCode: resp.status,\n        errorMessage: respData?.error?.message,\n        errorType: respData?.error?.type,\n      });\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (e: any) {\n      console.error(e);\n\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        statusCode: 500,\n        errorMessage: e?.message || 'network error',\n        errorType: ERROR_TYPE.NETWORK_ERROR,\n      });\n    }\n  }\n}\n","import SuprSend from './main';\nimport {\n  Dictionary,\n  PreferenceData,\n  Category,\n  PreferenceOptions,\n  CategoryChannel,\n  ChannelLevelPreferenceOptions,\n  ChannelPreference,\n  ERROR_TYPE,\n  RESPONSE_STATUS,\n  IPreferenceConfig,\n} from './interface';\nimport { debounceByType, getResponsePayload } from './utils';\n\nexport default class Preferences {\n  private config: SuprSend;\n  private preferenceData: PreferenceData;\n  private preferenceArgs?: IPreferenceConfig;\n  private debouncedUpdateCategoryPreferences;\n  private debouncedUpdateChannelPreferences;\n  private debounceTime = 1000;\n\n  constructor(config: SuprSend) {\n    this.config = config;\n\n    this.debouncedUpdateCategoryPreferences = debounceByType(\n      this._updateCategoryPreferences.bind(this),\n      this.debounceTime\n    );\n    this.debouncedUpdateChannelPreferences = debounceByType(\n      this._updateChannelPreferences.bind(this),\n      this.debounceTime\n    );\n  }\n\n  private validateQueryParams(queryParams: Dictionary = {}) {\n    const validatedParams: Record<string, string> = {};\n    for (const key in queryParams) {\n      if (queryParams[key]) {\n        if (typeof queryParams[key] === 'object') {\n          validatedParams[key] = JSON.stringify(queryParams[key]);\n        } else {\n          validatedParams[key] = String(queryParams[key]);\n        }\n      }\n    }\n    return validatedParams;\n  }\n\n  set data(value) {\n    this.preferenceData = value;\n  }\n\n  get data() {\n    return this.preferenceData;\n  }\n\n  getUrl(path: string, qp?: Dictionary) {\n    const urlPath = `${this.config.host}/v2/subscriber/${this.config.distinctId}/${path}`;\n\n    const validatedQueryParams = this.validateQueryParams(qp);\n    const queryParamsString = new URLSearchParams(\n      validatedQueryParams\n    ).toString();\n\n    return queryParamsString ? `${urlPath}/?${queryParamsString}` : urlPath;\n  }\n\n  /**\n   * Used to get user's whole preferences data.\n   */\n  async getPreferences(args?: IPreferenceConfig) {\n    const queryParams = {\n      tenant_id: args?.tenantId,\n      show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n      tags: args?.tags,\n      locale: args?.locale,\n    };\n\n    this.preferenceArgs = {\n      tenantId: queryParams?.tenant_id,\n      showOptOutChannels: queryParams?.show_opt_out_channels,\n      tags: queryParams?.tags,\n      locale: queryParams?.locale,\n    };\n    const url = this.getUrl('full_preference', queryParams);\n\n    const response = await this.config.client().request({ type: 'get', url });\n\n    if (!response.error) {\n      this.data = response.body;\n    }\n    return response;\n  }\n\n  /**\n   * Used to get user's preference of all categories.\n   */\n  async getCategories(args?: {\n    tenantId?: string;\n    showOptOutChannels?: boolean;\n    tags?: string | Dictionary;\n    locale?: string;\n    limit?: number;\n    offset?: number;\n  }) {\n    const queryParams = {\n      tenant_id: args?.tenantId,\n      show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n      limit: args?.limit,\n      offset: args?.offset,\n      tags: args?.tags,\n      locale: args?.locale,\n    };\n    const url = this.getUrl('category', queryParams);\n\n    const response = await this.config.client().request({ type: 'get', url });\n    return response;\n  }\n\n  /**\n   * Used to get user's preference of specific category.\n   */\n  async getCategory(\n    category: string,\n    args?: { tenantId?: string; showOptOutChannels?: boolean; locale?: string }\n  ) {\n    if (!category) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Category parameter is missing',\n      });\n    }\n\n    const queryParams = {\n      tenant_id: args?.tenantId,\n      show_opt_out_channels: args?.showOptOutChannels === false ? false : true,\n      locale: args?.locale,\n    };\n    const url = this.getUrl(`category/${category}`, queryParams);\n\n    const response = await this.config.client().request({ type: 'get', url });\n    return response;\n  }\n\n  /**\n   * Used to get user's all channel level preference.\n   */\n  async getOverallChannelPreferences(args?: { tenantId?: string }) {\n    const queryParams = { tenant_id: args?.tenantId };\n    const url = this.getUrl('channel_preference', queryParams);\n\n    const response = await this.config.client().request({ type: 'get', url });\n    return response;\n  }\n\n  private async _updateCategoryPreferences(\n    category: string,\n    body: Dictionary,\n    subcategory: Category,\n    args: Dictionary\n  ) {\n    const url = this.getUrl(`category/${category}`, args);\n\n    const response = await this.config.client().request({\n      type: 'patch',\n      url,\n      payload: body,\n    });\n\n    if (response?.error) {\n      this.config.emitter.emit('preferences_error', response);\n    } else {\n      Object.assign(subcategory, response.body);\n      this.config.emitter.emit('preferences_updated', {\n        status: RESPONSE_STATUS.SUCCESS,\n        statusCode: 200,\n        body: this.data as PreferenceData,\n      });\n    }\n    return response;\n  }\n\n  private async _updateChannelPreferences(body: Dictionary, args?: Dictionary) {\n    const url = this.getUrl('channel_preference', args);\n\n    const response = await this.config.client().request({\n      type: 'patch',\n      url,\n      payload: body,\n    });\n\n    if (response?.error) {\n      this.config.emitter.emit('preferences_error', response);\n    } else {\n      await this.getPreferences(this.preferenceArgs);\n      this.config.emitter.emit('preferences_updated', {\n        status: RESPONSE_STATUS.SUCCESS,\n        statusCode: 200,\n        body: this.data as PreferenceData,\n      });\n    }\n    return response;\n  }\n\n  /**\n   * Used to update user's category level preference.\n   */\n  async updateCategoryPreference(\n    category: string,\n    preference: PreferenceOptions,\n    args?: IPreferenceConfig\n  ) {\n    if (\n      !category ||\n      ![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(\n        preference\n      )\n    ) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: !category\n          ? 'Category parameter is missing'\n          : 'Preference parameter is invalid',\n      });\n    }\n\n    if (!this.data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Call getPreferences method before performing action',\n      });\n    }\n\n    if (!this.data.sections) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: \"Sections doesn't exist\",\n      });\n    }\n\n    let categoryData: Category | null = null;\n    let dataUpdated = false;\n\n    // optimistic update in local store\n    for (const section of this.data.sections) {\n      let abort = false;\n      if (!section.subcategories) continue;\n\n      for (const subcategory of section.subcategories) {\n        if (subcategory.category === category) {\n          categoryData = subcategory;\n          if (subcategory.is_editable) {\n            if (subcategory.preference !== preference) {\n              subcategory.preference = preference;\n              dataUpdated = true;\n              abort = true;\n              break;\n            } else {\n              // console.log(`category is already ${status}ed`);\n            }\n          } else {\n            return getResponsePayload({\n              status: RESPONSE_STATUS.ERROR,\n              errorType: ERROR_TYPE.VALIDATION_ERROR,\n              errorMessage: 'Category preference is not editable',\n            });\n          }\n        }\n      }\n      if (abort) break;\n    }\n\n    if (!categoryData) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Category not found',\n      });\n    }\n\n    if (!dataUpdated) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.SUCCESS,\n        body: this.data,\n      });\n    }\n\n    const optOutChannels: string[] = [];\n    categoryData?.channels?.forEach((channel) => {\n      if (channel.preference === PreferenceOptions.OPT_OUT) {\n        optOutChannels.push(channel.channel);\n      }\n    });\n\n    let showOptOutChannels = true;\n    if (typeof args?.showOptOutChannels === 'boolean') {\n      showOptOutChannels = args?.showOptOutChannels;\n    } else if (typeof this.preferenceArgs?.showOptOutChannels === 'boolean') {\n      showOptOutChannels = this.preferenceArgs.showOptOutChannels;\n    }\n\n    const requestPayload = {\n      preference: categoryData.preference,\n      opt_out_channels:\n        showOptOutChannels && preference === PreferenceOptions.OPT_IN\n          ? null\n          : optOutChannels,\n    };\n\n    this.debouncedUpdateCategoryPreferences(\n      category,\n      category,\n      requestPayload,\n      categoryData,\n      {\n        tenant_id: args?.tenantId || this.preferenceArgs?.tenantId,\n        show_opt_out_channels: showOptOutChannels,\n        tags: args?.tags || this.preferenceArgs?.tags,\n        locale: args?.locale || this.preferenceArgs?.locale,\n      }\n    );\n\n    return getResponsePayload({\n      status: RESPONSE_STATUS.SUCCESS,\n      body: this.data,\n    });\n  }\n\n  /**\n   * Used to update user's category level channel preference.\n   */\n  async updateChannelPreferenceInCategory(\n    channel: string,\n    preference: PreferenceOptions,\n    category: string,\n    args?: IPreferenceConfig\n  ) {\n    if (!channel || !category) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: !channel\n          ? 'Channel parameter is missing'\n          : 'Category parameter is missing',\n      });\n    }\n\n    if (\n      ![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(\n        preference\n      )\n    ) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Preference parameter is invalid',\n      });\n    }\n\n    if (!this.data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Call getPreferences method before performing action',\n      });\n    }\n\n    if (!this.data.sections) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: \"Sections doesn't exist\",\n      });\n    }\n\n    let categoryData: Category | null = null;\n    let selectedChannelData: CategoryChannel | null = null;\n    let dataUpdated = false;\n\n    // optimistic update in local store\n    for (const section of this.data.sections) {\n      let abort = false;\n      if (!section.subcategories) continue;\n\n      for (const subcategory of section.subcategories) {\n        if (subcategory.category === category) {\n          categoryData = subcategory;\n          if (!subcategory.channels) continue;\n\n          for (const channelData of subcategory.channels) {\n            if (channelData.channel === channel) {\n              selectedChannelData = channelData;\n              if (channelData.is_editable) {\n                if (channelData.preference !== preference) {\n                  channelData.preference = preference;\n                  if (preference === PreferenceOptions.OPT_IN) {\n                    subcategory.preference = PreferenceOptions.OPT_IN;\n                  }\n                  dataUpdated = true;\n                  abort = true;\n                  break;\n                } else {\n                  //  console.log(`channel is already ${preference}`);\n                }\n              } else {\n                return getResponsePayload({\n                  status: RESPONSE_STATUS.ERROR,\n                  errorType: ERROR_TYPE.VALIDATION_ERROR,\n                  errorMessage: 'Channel preference is not editable',\n                });\n              }\n            }\n          }\n        }\n        if (abort) break;\n      }\n      if (abort) break;\n    }\n\n    if (!categoryData) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Category not found',\n      });\n    }\n\n    if (!selectedChannelData) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: \"Category's channel not found\",\n      });\n    }\n\n    if (!dataUpdated) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.SUCCESS,\n        body: this.data,\n      });\n    }\n\n    const optOutChannels: string[] = [];\n    categoryData?.channels?.forEach((channel) => {\n      if (channel.preference === PreferenceOptions.OPT_OUT) {\n        optOutChannels.push(channel.channel);\n      }\n    });\n\n    let showOptOutChannels = true;\n    if (typeof args?.showOptOutChannels === 'boolean') {\n      showOptOutChannels = args?.showOptOutChannels;\n    } else if (typeof this.preferenceArgs?.showOptOutChannels === 'boolean') {\n      showOptOutChannels = this.preferenceArgs.showOptOutChannels;\n    }\n\n    const categoryPreference =\n      showOptOutChannels &&\n      categoryData.preference === PreferenceOptions.OPT_OUT &&\n      preference === PreferenceOptions.OPT_IN\n        ? PreferenceOptions.OPT_IN\n        : categoryData.preference;\n\n    const requestPayload = {\n      preference: categoryPreference,\n      opt_out_channels: optOutChannels,\n    };\n\n    this.debouncedUpdateCategoryPreferences(\n      category,\n      category,\n      requestPayload,\n      categoryData,\n      {\n        tenant_id: args?.tenantId || this.preferenceArgs?.tenantId,\n        show_opt_out_channels: showOptOutChannels,\n        tags: args?.tags || this.preferenceArgs?.tags,\n        locale: args?.locale || this.preferenceArgs?.locale,\n      }\n    );\n\n    return getResponsePayload({\n      status: RESPONSE_STATUS.SUCCESS,\n      body: this.data,\n    });\n  }\n\n  /**\n   * Used to update user's channel level preference.\n   */\n  async updateOverallChannelPreference(\n    channel: string,\n    preference: ChannelLevelPreferenceOptions,\n    args?: { tenantId?: string }\n  ) {\n    if (\n      !channel ||\n      ![\n        ChannelLevelPreferenceOptions.ALL,\n        ChannelLevelPreferenceOptions.REQUIRED,\n      ].includes(preference)\n    ) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: !channel\n          ? 'Channel parameter is missing'\n          : 'Preference parameter is invalid',\n      });\n    }\n\n    if (!this.data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Call getPreferences method before performing action',\n      });\n    }\n\n    if (!this.data.channel_preferences) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: \"Channel preferences doesn't exist\",\n      });\n    }\n\n    let channelData: ChannelPreference | null = null;\n    let dataUpdated = false;\n    const preferenceRestricted =\n      preference === ChannelLevelPreferenceOptions.REQUIRED;\n\n    for (const channelItem of this.data.channel_preferences) {\n      if (channelItem.channel === channel) {\n        channelData = channelItem;\n        if (channelItem.is_restricted !== preferenceRestricted) {\n          channelItem.is_restricted = preferenceRestricted;\n          dataUpdated = true;\n          break;\n        }\n      }\n    }\n\n    if (!channelData) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'Channel data not found',\n      });\n    }\n\n    if (!dataUpdated) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.SUCCESS,\n        body: this.data,\n      });\n    }\n\n    this.debouncedUpdateChannelPreferences(\n      channelData.channel,\n      { channel_preferences: [channelData] },\n      { tenant_id: args?.tenantId || this.preferenceArgs?.tenantId }\n    );\n\n    return getResponsePayload({\n      status: RESPONSE_STATUS.SUCCESS,\n      body: this.data,\n    });\n  }\n}\n","import { SuprSend } from './index';\nimport {\n  Dictionary,\n  ERROR_TYPE,\n  RESPONSE_STATUS,\n  ValidatedDataOptions,\n} from './interface';\nimport {\n  epochMs,\n  getLocalStorageData,\n  getResponsePayload,\n  isArrayEmpty,\n  isObjectEmpty,\n  setLocalStorageData,\n  uuid,\n} from './utils';\nimport Preferences from './preferences';\n\nconst DEVICE_ID_KEY = 'ss_device_id';\n\nexport default class User {\n  private config: SuprSend;\n  public preferences: Preferences;\n\n  constructor(config: SuprSend) {\n    this.config = config;\n    this.preferences = new Preferences(config);\n  }\n\n  private isReservedKey(key: string) {\n    return key.startsWith('$') || key?.toLowerCase()?.startsWith('ss_');\n  }\n\n  private formatParamsToObj(arg1: string | Dictionary, arg2?: unknown) {\n    let data: Dictionary | null = null;\n\n    if (typeof arg1 === 'object' && arg2 === undefined) {\n      data = arg1;\n    } else if (typeof arg1 === 'string' && arg2 !== undefined) {\n      data = { [arg1]: arg2 };\n    } else {\n      console.warn('[SuprSend]: Invalid input parameters');\n    }\n\n    return data;\n  }\n\n  private formatParamsToArray(arg1: string | string[]) {\n    if (!arg1) return;\n\n    return Array.isArray(arg1) ? arg1 : [arg1];\n  }\n\n  private validateObjData(data: Dictionary, options?: ValidatedDataOptions) {\n    const validatedData = {};\n    const allowReservedKeys = options?.allowReservedKeys || false;\n    const valueType = options?.valueType || '';\n\n    for (const key in data) {\n      let value = data[key];\n\n      if (key && value === undefined) continue;\n\n      if (!allowReservedKeys && this.isReservedKey(key)) {\n        console.warn('[SuprSend]: key cannot start with $ or ss_');\n        continue;\n      }\n\n      if (valueType === 'number') {\n        value = Number(value);\n      } else if (valueType === 'boolean') {\n        value = !!value;\n      }\n\n      validatedData[key] = value;\n    }\n\n    return validatedData;\n  }\n\n  private validateArrayData(data: string[]) {\n    const validatedData: string[] = [];\n\n    for (const item of data) {\n      if (item === undefined || item === null) continue;\n\n      if (this.isReservedKey(item)) {\n        console.warn('[SuprSend]: key cannot start with $ or ss_');\n        continue;\n      }\n\n      validatedData.push(String(item));\n    }\n\n    return validatedData;\n  }\n\n  private async triggerUserEvent(data: Dictionary) {\n    return this.config.eventApi({\n      distinct_id: this.config.distinctId,\n      $insert_id: uuid(),\n      $time: epochMs(),\n      ...data,\n    });\n  }\n\n  /**\n   * Used to set user properties. Keys with $ and ss_ will be removed.\n   */\n  async set(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data);\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $set: validatedData });\n  }\n\n  /**\n   * Used to set user properties only once. Properties once set cannot be changed later.\n   * Keys with $ and ss_ will be removed.\n   */\n  async setOnce(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data);\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $set_once: validatedData });\n  }\n\n  /**\n   * Used to increment/decrement user properties whose values are numbers. To decrement use -ve values.\n   * Keys with $ and ss_ will be removed.\n   */\n  async increment(arg1: string | Dictionary, arg2?: number) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data, { valueType: 'number' });\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $add: validatedData });\n  }\n\n  /**\n   * Used to add items to list if user property is list (example: wishlist: [iphone, macbook]).\n   * Keys with $ and ss_ will be removed.\n   */\n  async append(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data);\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $append: validatedData });\n  }\n\n  /**\n   * Used to remove items from list if user property is list.\n   * Keys with $ and ss_ will be removed.\n   */\n  async remove(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data);\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $remove: validatedData });\n  }\n\n  /**\n   * Used to remove user property. Keys with $ and ss_ will be removed.\n   */\n  async unset(arg: string | string[]) {\n    const data = this.formatParamsToArray(arg);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateArrayData(data);\n    if (isArrayEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $unset: validatedData });\n  }\n\n  // this append is only used internally since it allows internal events\n  private appendInternal(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data, {\n      allowReservedKeys: true,\n    });\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $append: validatedData });\n  }\n\n  // this remove is only used internally since it allows internal events\n  private removeInternal(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data, {\n      allowReservedKeys: true,\n    });\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $remove: validatedData });\n  }\n\n  private setInternal(arg1: string | Dictionary, arg2?: unknown) {\n    const data = this.formatParamsToObj(arg1, arg2);\n    if (!data) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    const validatedData = this.validateObjData(data, {\n      allowReservedKeys: true,\n    });\n    if (isObjectEmpty(validatedData)) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'data provided is empty',\n      });\n    }\n\n    return this.triggerUserEvent({ $set: validatedData });\n  }\n\n  private validateEmail(email: string) {\n    const emailRegex = /\\S+@\\S+\\.\\S+/;\n\n    return emailRegex.test(email);\n  }\n\n  private validateMobile(mobile: string) {\n    const mobileRegex = /^\\+[1-9]\\d{1,14}$/;\n\n    return mobileRegex.test(mobile);\n  }\n\n  async addEmail(email: string) {\n    const isValid = this.validateEmail(email);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided email is invalid',\n      });\n    }\n\n    return this.appendInternal({ $email: email });\n  }\n\n  async removeEmail(email: string) {\n    const isValid = this.validateEmail(email);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided email is invalid',\n      });\n    }\n\n    return this.removeInternal({ $email: email });\n  }\n\n  /**\n   * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n   */\n  async addSms(mobile: string) {\n    const isValid = this.validateMobile(mobile);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided mobile number is invalid, must be as per E.164 standard',\n      });\n    }\n\n    return this.appendInternal({ $sms: mobile });\n  }\n\n  /**\n   * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n   */\n  async removeSms(mobile: string) {\n    const isValid = this.validateMobile(mobile);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided mobile number is invalid, must be as per E.164 standard',\n      });\n    }\n\n    return this.removeInternal({ $sms: mobile });\n  }\n\n  /**\n   * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n   */\n  async addWhatsapp(mobile: string) {\n    const isValid = this.validateMobile(mobile);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided mobile number is invalid, must be as per E.164 standard',\n      });\n    }\n\n    return this.appendInternal({ $whatsapp: mobile });\n  }\n\n  /**\n   * Mobile number must be as per {@link https://www.twilio.com/docs/glossary/what-e164 E.164 standard}.\n   */\n  async removeWhatsapp(mobile: string) {\n    const isValid = this.validateMobile(mobile);\n\n    if (!isValid) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided mobile number is invalid, must be as per E.164 standard',\n      });\n    }\n\n    return this.removeInternal({ $whatsapp: mobile });\n  }\n\n  private getDeviceId(): string {\n    let deviceId = getLocalStorageData(DEVICE_ID_KEY);\n\n    if (!deviceId) {\n      deviceId = uuid();\n      setLocalStorageData(DEVICE_ID_KEY, deviceId);\n    }\n\n    return deviceId;\n  }\n\n  async addWebPush(push: PushSubscription) {\n    if (typeof push !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided push subscription is invalid, must be an object',\n      });\n    }\n\n    const deviceId: string = this.getDeviceId();\n\n    return this.appendInternal({\n      $webpush: push,\n      $id_provider: 'vapid',\n      $device_id: deviceId,\n    });\n  }\n\n  async removeWebPush(push: PushSubscription) {\n    if (typeof push !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'provided push subscription is invalid, must be an object',\n      });\n    }\n\n    const deviceId: string = this.getDeviceId();\n\n    return this.removeInternal({\n      $webpush: push,\n      $id_provider: 'vapid',\n      $device_id: deviceId,\n    });\n  }\n\n  async addSlack(data: Dictionary) {\n    if (typeof data !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided slack data is invalid, must be an object',\n      });\n    }\n\n    return this.appendInternal({ $slack: data });\n  }\n\n  async removeSlack(data: Dictionary) {\n    if (typeof data !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided slack data is invalid, must be an object',\n      });\n    }\n\n    return this.removeInternal({ $slack: data });\n  }\n\n  async addMSTeams(data: Dictionary) {\n    if (typeof data !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided ms_teams data is invalid, must be object',\n      });\n    }\n\n    return this.appendInternal({ $ms_teams: data });\n  }\n\n  async removeMSTeams(data: Dictionary) {\n    if (typeof data !== 'object') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided ms_teams data is invalid, must be object',\n      });\n    }\n\n    return this.removeInternal({ $ms_teams: data });\n  }\n\n  /**\n   * language passed should be 2-letter language code in {@link https://gist.github.com/jrnk/8eb57b065ea0b098d571 ISO 639-1 Alpha-2 format}.\n   * e.g. en (for English), es (for Spanish), fr (for French) etc.\n   */\n  async setPreferredLanguage(language: string) {\n    if (typeof language !== 'string') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided language is invalid, must be string',\n      });\n    }\n\n    return this.setInternal({ $preferred_language: language });\n  }\n\n  /**\n   * Timezone passed should be in {@link https://timeapi.io/documentation/iana-timezones IANA timezone format}.\n   */\n  async setTimezone(timezone: string) {\n    if (typeof timezone !== 'string') {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'provided timezone is invalid, must be string',\n      });\n    }\n\n    return this.setInternal({ $timezone: timezone });\n  }\n}\n","import { SuprSend } from './index';\nimport {\n  urlB64ToUint8Array,\n  getResponsePayload,\n  windowSupport,\n  sha256Hash,\n  getLocalStorageData,\n  setLocalStorageData,\n} from './utils';\nimport { ERROR_TYPE, RESPONSE_STATUS } from './interface';\n\nexport const SUPRSEND_ENDPOINT_KEY = 'ss_wp_hash';\n\nexport default class WebPush {\n  private config: SuprSend;\n\n  constructor(config: SuprSend) {\n    this.config = config;\n  }\n\n  private async getPushSubscription() {\n    if (!windowSupport()) return;\n\n    const registration = await navigator.serviceWorker.getRegistration();\n    if (!registration) return;\n\n    const subscription = registration.pushManager.getSubscription();\n    if (!subscription) return;\n    return subscription;\n  }\n\n  private async checkAndUpdateOnServer(subscription: PushSubscription) {\n    const endpoint = subscription.endpoint;\n    let hash: string | null = null;\n    try {\n      hash = await sha256Hash(endpoint);\n    } catch (e) {\n      // pass\n    }\n    if (hash) {\n      if (hash === getLocalStorageData(SUPRSEND_ENDPOINT_KEY)) {\n        return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n      }\n      setLocalStorageData(SUPRSEND_ENDPOINT_KEY, hash);\n    }\n    return await this.config.user.addWebPush(subscription);\n  }\n\n  private async handleRegisterPush() {\n    try {\n      // register the service worker\n      await navigator.serviceWorker.register(`/${this.config.swFileName}`);\n\n      // request notification permission\n      const permission = await Notification.requestPermission();\n      if (permission !== 'granted') {\n        console.warn('[SuprSend]: Notification permission isnt granted');\n        return getResponsePayload({\n          status: RESPONSE_STATUS.ERROR,\n          errorType: ERROR_TYPE.PERMISSION_DENIED,\n          errorMessage: \"Notification permission isn't granted\",\n        });\n      }\n\n      // wait until the service worker is ready\n      const readyRegistration = await navigator.serviceWorker.ready;\n\n      // if push subscribed present then do nothing\n      const pushSubscriptionObj =\n        await readyRegistration.pushManager.getSubscription();\n      if (pushSubscriptionObj) {\n        return this.checkAndUpdateOnServer(pushSubscriptionObj);\n      }\n\n      if (!this.config.vapidKey) {\n        console.warn(\n          '[SuprSend]: Vapid key is missing. Add it while creating SuprSend instance'\n        );\n        return getResponsePayload({\n          status: RESPONSE_STATUS.ERROR,\n          errorType: ERROR_TYPE.VALIDATION_ERROR,\n          errorMessage:\n            'Vapid key is missing. Add it while creating SuprSend instance',\n        });\n      }\n\n      // get the push token object\n      const subscription = await readyRegistration.pushManager.subscribe({\n        userVisibleOnly: true,\n        applicationServerKey: urlB64ToUint8Array(this.config.vapidKey),\n      });\n\n      // send push token object to suprsend\n      return this.checkAndUpdateOnServer(subscription);\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (e: any) {\n      console.warn('SuprSend: Error getting push subscription', e);\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.UNKNOWN_ERROR,\n        errorMessage:\n          e?.message || 'Unknown error occured while registering for push',\n      });\n    }\n  }\n\n  /**\n   * Used to register push service. This method will\n   * 1. Ask for notification permission.\n   * 2. Register push service and generate webpush token.\n   * 3. Send webpush token to SuprSend.\n   */\n  async registerPush() {\n    const pushSupported =\n      windowSupport() &&\n      'serviceWorker' in navigator &&\n      'PushManager' in window;\n\n    if (pushSupported) {\n      return this.handleRegisterPush();\n    } else {\n      console.warn(\"[SuprSend]: Webpush isn't supported\");\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.UNSUPPORTED_ACTION,\n        errorMessage: \"Webpush isn't supported\",\n      });\n    }\n  }\n\n  async updatePushSubscription() {\n    const subscription = await this.getPushSubscription();\n    if (subscription) {\n      return this.checkAndUpdateOnServer(subscription);\n    }\n  }\n\n  async removePushSubscription() {\n    const subscription = await this.getPushSubscription();\n    if (subscription) {\n      return this.config.user.removeWebPush(subscription);\n    }\n  }\n\n  /**\n   * Used to get browser level permission to show notifications.\n   */\n  notificationPermission() {\n    return Notification.permission;\n  }\n\n  /**\n   * Used to check if push service is already active in browser.\n   */\n  async pushSubscribed() {\n    const subscription = await this.getPushSubscription();\n    return !!subscription;\n  }\n}\n","import { createStore, StoreApi } from 'zustand/vanilla';\nimport { io, Socket } from 'socket.io-client';\nimport jwt_decode from 'jwt-decode';\nimport mitt, { Emitter } from 'mitt';\nimport SuprSend from './main';\nimport {\n  IStore,\n  ApiResponseStatus,\n  IFeedOptions,\n  INotificationStore,\n  Dictionary,\n  IInboxFetchOptions,\n  RESPONSE_STATUS,\n  IRemoteNotification,\n  InboxEmitterEvents,\n  ERROR_TYPE,\n  ApiResponse,\n  IFeedData,\n} from './interface';\n\nconst DEFAULT_PAGE_SIZE = 20;\nconst DEFAULT_TENANT_ID = 'default';\nconst MAX_PAGE_SIZE = 100;\nconst DEFAULT_STORE = {\n  storeId: '$suprsend_default_store',\n  label: '',\n};\n\nconst feedOptionsDefaults = {\n  tenantId: DEFAULT_TENANT_ID,\n  pageSize: DEFAULT_PAGE_SIZE,\n  stores: null,\n  host: {\n    apiHost: 'https://inboxs.live',\n    socketHost: 'https://betainbox.suprsend.com',\n  },\n};\n\nconst initialFeedStore: INotificationStore = {\n  notifications: [],\n  store: DEFAULT_STORE,\n  pageInfo: {\n    total: 0,\n    pageSize: DEFAULT_PAGE_SIZE,\n    hasMore: false,\n  },\n  meta: { badge: 0 },\n  apiStatus: ApiResponseStatus.INITIAL,\n  isFirstFetch: true,\n};\n\nexport default class FeedsFactory {\n  private config: SuprSend;\n  feedInstances: Feed[] = [];\n\n  constructor(config: SuprSend) {\n    this.config = config;\n  }\n\n  initialize(options: IFeedOptions = {}) {\n    const feedClient = new Feed(this.config, options);\n    this.feedInstances.push(feedClient);\n    return feedClient;\n  }\n\n  removeInstance(feedClient: Feed) {\n    this.feedInstances = this.feedInstances.filter(\n      (instance) => instance !== feedClient\n    );\n  }\n\n  removeAll() {\n    for (const feedInstance of this.feedInstances) {\n      feedInstance.remove();\n    }\n    this.feedInstances = [];\n  }\n}\n\nexport class Feed {\n  feedOptions: IFeedOptions;\n  private config: SuprSend;\n  private store: StoreApi<INotificationStore>;\n  private socket: Socket;\n  private expiryTimerId?: ReturnType<typeof setInterval>;\n  private fetchAbortController?: AbortController;\n  readonly emitter: Emitter<InboxEmitterEvents> = mitt();\n\n  constructor(config: SuprSend, options: IFeedOptions) {\n    this.config = config;\n    this.setOptions(options);\n    this.store = this.createFeedStore();\n  }\n\n  private setOptions(options: IFeedOptions) {\n    this.feedOptions = { ...feedOptionsDefaults };\n\n    if (options?.tenantId) {\n      this.feedOptions.tenantId = options.tenantId;\n    }\n\n    if (options?.host) {\n      this.feedOptions.host = options.host;\n    }\n\n    if (typeof options?.pageSize === 'number' && options.pageSize > 0) {\n      this.feedOptions.pageSize = Math.min(options.pageSize, MAX_PAGE_SIZE);\n    }\n\n    if (options?.stores) {\n      this.feedOptions.stores = options.stores;\n    }\n    this.validateStore();\n  }\n\n  private validateStore() {\n    const stores = this.feedOptions.stores;\n\n    if (!stores) return;\n\n    if (!Array.isArray(stores) || stores?.length <= 0) {\n      console.warn('SuprSend: stores should be an array of objects');\n      return;\n    }\n\n    const validatedStores: IStore[] = [];\n\n    stores.forEach((store) => {\n      if (!store.storeId) {\n        console.warn(\n          'SuprSend: storeId is mandatory for each store. Ignoring store without storeId'\n        );\n        return;\n      }\n      const query = store?.query;\n      let read: boolean | undefined;\n      let archived: boolean | undefined;\n      let tags: string[] | undefined = [];\n      let categories: string[] | undefined = [];\n\n      if (typeof query?.read === 'boolean') {\n        read = query.read;\n      }\n\n      if (typeof query?.archived === 'boolean') {\n        archived = query.archived;\n      }\n\n      if (typeof query?.tags === 'string') {\n        tags = [query.tags];\n      } else if (Array.isArray(query?.tags)) {\n        tags = query?.tags.filter((tag) => {\n          return typeof tag === 'string';\n        });\n      }\n\n      if (typeof query?.categories === 'string') {\n        categories = [query.categories];\n      } else if (Array.isArray(query?.categories)) {\n        categories = query?.categories.filter((category) => {\n          return typeof category === 'string';\n        });\n      }\n\n      validatedStores.push({\n        storeId: store.storeId,\n        label: store.label || store.storeId,\n        query: {\n          archived,\n          read,\n          tags,\n          categories,\n        },\n      });\n    });\n    this.feedOptions.stores = validatedStores;\n  }\n\n  private createFeedStore() {\n    return createStore<INotificationStore>()(() => {\n      return {\n        ...initialFeedStore,\n        store: this.feedOptions.stores?.[0] || DEFAULT_STORE,\n      };\n    });\n  }\n\n  private initializeSocketEvents() {\n    this.socket.on('connect_error', async (error) => {\n      if (\n        error.message === 'Authentication Error: wrong auth token' &&\n        this.config.authenticateOptions?.refreshUserToken &&\n        this.config.userToken\n      ) {\n        const userToken = this.socket.auth['x-ss-signature'];\n        const jwtPayload = jwt_decode(userToken) as Dictionary;\n        const expiresOn = ((jwtPayload.exp as number) || 0) * 1000; // in ms\n        const now = Date.now(); // in ms\n        const hasExpired = expiresOn <= now;\n        if (hasExpired) {\n          try {\n            const newUserToken =\n              await this.config.authenticateOptions.refreshUserToken(\n                this.config.userToken,\n                jwtPayload\n              );\n            if (newUserToken && typeof newUserToken === 'string') {\n              await this.config.identify(\n                this.config.distinctId,\n                newUserToken,\n                this.config.authenticateOptions\n              );\n              this.socket.auth['x-ss-signature'] = newUserToken;\n              setTimeout(() => {\n                this.socket.connect();\n              }, 1000);\n            }\n          } catch (e) {\n            // error while getting token go ahead with calling api\n          }\n        }\n      }\n    });\n\n    this.socket.on(\n      'new_notification',\n      this.handleNewNotificationSocketEvent.bind(this)\n    );\n\n    this.socket.on(\n      'notification_update',\n      this.handleNoticationUpdateSocketEvent.bind(this)\n    );\n\n    this.socket.on(\n      'bulk_notification_update',\n      this.handleBulkNotificationUpdateSocketEvent.bind(this)\n    );\n\n    this.socket.on('reset_badge', async () => {\n      const storeData = this.store.getState();\n      this.store.setState({\n        meta: { ...storeData.meta, badge: 0 },\n      });\n      this.emitter.emit('feed.store_update', this.data);\n    });\n  }\n\n  private async handleNewNotificationSocketEvent(data: { n_id: string }) {\n    if (!data.n_id) return;\n\n    const response = await this.fetchDetails(data.n_id);\n    if (response.status === RESPONSE_STATUS.ERROR) {\n      return;\n    }\n\n    const newNotificationData = response.body;\n    const storeData = this.store.getState();\n    let emitNewNotificationEvent = false;\n\n    const newMetaData = { ...storeData.meta };\n\n    if (this.notificationBelongToStore(newNotificationData, storeData.store)) {\n      emitNewNotificationEvent = true;\n      this.store.setState({\n        notifications: this.orderNotificationsBasedOnPinFlag(\n          newNotificationData,\n          storeData.notifications\n        ),\n      });\n    }\n\n    this.feedOptions.stores?.map?.((store) => {\n      if (this.notificationBelongToStore(newNotificationData, store)) {\n        emitNewNotificationEvent = true;\n        newMetaData[store.storeId] = (storeData.meta[store.storeId] || 0) + 1;\n      }\n    });\n\n    // update overall badge count as well if it belongs any of store current store\n    this.store.setState({\n      meta: {\n        ...newMetaData,\n        badge: emitNewNotificationEvent\n          ? newMetaData.badge + 1\n          : newMetaData.badge,\n      },\n    });\n\n    if (emitNewNotificationEvent) {\n      this.emitter.emit('feed.new_notification', newNotificationData);\n    }\n\n    this.emitter.emit('feed.store_update', this.data);\n  }\n\n  private async handleNoticationUpdateSocketEvent(data: {\n    n_id: string;\n    action?: string;\n  }) {\n    if (!data.n_id) return;\n\n    const apiResponses = await Promise.allSettled([\n      this.fetchDetails(data.n_id),\n      this.fetchCount(),\n    ]);\n\n    const storeData = this.store.getState();\n\n    if (apiResponses[0].status !== 'fulfilled') return;\n\n    const response = apiResponses[0].value;\n\n    if (response.status === RESPONSE_STATUS.ERROR) return;\n\n    const newNotificationData: IRemoteNotification = response.body;\n\n    const notificationPresent = storeData.notifications?.some(\n      (notif) => notif.n_id === newNotificationData.n_id\n    );\n    const notificationBelongsToStore = this.notificationBelongToStore(\n      newNotificationData,\n      storeData.store\n    );\n\n    if (notificationBelongsToStore) {\n      if (!notificationPresent) {\n        this.store.setState({\n          notifications: this.orderNotificationsBasedOnPinFlag(\n            newNotificationData,\n            storeData.notifications\n          ),\n        });\n      } else {\n        this.store.setState({\n          notifications: storeData.notifications.map((notification) => {\n            return notification.n_id === newNotificationData.n_id\n              ? newNotificationData\n              : notification;\n          }),\n        });\n      }\n    } else {\n      this.store.setState({\n        notifications: storeData.notifications.filter(\n          (notification) => notification.n_id !== newNotificationData.n_id\n        ),\n      });\n    }\n\n    this.emitter.emit('feed.store_update', this.data);\n  }\n\n  private async handleBulkNotificationUpdateSocketEvent(data: {\n    notification_ids: string | string[];\n    action: string;\n  }) {\n    const storeData = this.store.getState();\n\n    if (data.action === 'read' && data.notification_ids === 'all') {\n      for (const key in storeData.meta) {\n        storeData.meta[key] = 0;\n      }\n\n      this.store.setState({\n        notifications: storeData.notifications.map((notification) => {\n          if (!notification.read_on) {\n            notification.read_on = Date.now();\n          }\n          return notification;\n        }),\n        meta: storeData.meta,\n      });\n    }\n\n    if (data.action === 'seen' && Array.isArray(data.notification_ids)) {\n      this.store.setState({\n        notifications: storeData.notifications.map((notification) => {\n          if (data.notification_ids.includes(notification.n_id)) {\n            notification.seen_on = Date.now();\n          }\n          return notification;\n        }),\n      });\n    }\n\n    this.emitter.emit('feed.store_update', this.data);\n  }\n\n  private notificationBelongToStore(\n    notification: IRemoteNotification,\n    store?: IStore\n  ) {\n    const notifRead = !!notification.read_on;\n    const notifArchived = notification.archived;\n    const notifTags: string[] | undefined = notification.tags;\n    const notifCategory: string = notification.n_category;\n\n    const storeRead = store?.query?.read;\n    const storeArchived = store?.query?.archived;\n    const storeTags = store?.query?.tags;\n    const storeCategories = store?.query?.categories;\n\n    const sameRead =\n      storeRead === undefined || storeRead === null || notifRead === storeRead;\n    const sameArchived = !!notifArchived === !!storeArchived;\n    let sameTags = false;\n    let sameCategory = false;\n\n    if (Array.isArray(storeTags) && storeTags.length > 0) {\n      storeTags.forEach((tag) => {\n        if (notifTags?.includes(tag)) {\n          sameTags = true;\n        }\n      });\n    } else {\n      sameTags = true;\n    }\n\n    if (Array.isArray(storeCategories) && storeCategories.length > 0) {\n      if (storeCategories.includes(notifCategory)) {\n        sameCategory = true;\n      }\n    } else {\n      sameCategory = true;\n    }\n\n    return sameRead && sameTags && sameCategory && sameArchived;\n  }\n\n  private orderNotificationsBasedOnPinFlag(\n    newNotification: IRemoteNotification,\n    existingNotifications: IRemoteNotification[]\n  ) {\n    // if pinned notification add new notification append at start else at end of pinned notifications\n    if (newNotification.is_pinned) {\n      return [newNotification, ...existingNotifications];\n    } else {\n      let addedNotification = false;\n      const notifications: IRemoteNotification[] = [];\n\n      existingNotifications.forEach((notification) => {\n        if (notification.is_pinned) {\n          notifications.push(notification);\n        } else {\n          if (addedNotification) {\n            notifications.push(notification);\n          } else {\n            notifications.push(newNotification);\n            notifications.push(notification);\n            addedNotification = true;\n          }\n        }\n      });\n\n      if (!addedNotification) {\n        return [...existingNotifications, newNotification];\n      }\n\n      return notifications;\n    }\n  }\n\n  private startExpiryTimer() {\n    if (this.expiryTimerId) return;\n    this.expiryTimerId = setInterval(this.removeExpiredFeed.bind(this), 30000);\n  }\n\n  private async removeExpiredFeed() {\n    const storeData = this.store.getState();\n    let hasExpired = false;\n\n    const notifications = storeData.notifications.filter(\n      (notification: IRemoteNotification) => {\n        const expired = notification.expiry\n          ? Date.now() > notification.expiry\n          : false;\n        if (expired) {\n          hasExpired = true;\n          return false;\n        } else {\n          return true;\n        }\n      }\n    );\n\n    if (hasExpired) {\n      this.store.setState({ notifications });\n      await this.fetchCount();\n      this.emitter.emit('feed.store_update', this.data);\n    }\n  }\n\n  private getUrl(path: string, qp?: Dictionary) {\n    const urlPath = `${this.feedOptions.host?.apiHost}/v1/feed/${path}`;\n    const validatedQueryParams = this.validateQueryParams(qp);\n    const queryParamsString = new URLSearchParams(\n      validatedQueryParams\n    ).toString();\n    return queryParamsString ? `${urlPath}?${queryParamsString}` : urlPath;\n  }\n\n  private validateQueryParams(queryParams: Dictionary = {}) {\n    const validatedParams: Record<string, string> = {};\n    for (const key in queryParams) {\n      const paramValue = queryParams[key];\n      if (\n        paramValue === undefined ||\n        paramValue === null ||\n        paramValue === ''\n      ) {\n        continue;\n      } else if (typeof paramValue === 'object') {\n        validatedParams[key] = JSON.stringify(paramValue);\n      } else {\n        validatedParams[key] = String(paramValue);\n      }\n    }\n    return validatedParams;\n  }\n\n  private requestInprogress() {\n    const storeData = this.store.getState();\n\n    return [\n      ApiResponseStatus.LOADING,\n      ApiResponseStatus.FETCHING_MORE,\n    ].includes(storeData.apiStatus);\n  }\n\n  private storesQueryParamObj(stores: IStore[]) {\n    const apiStores = stores?.map((store) => {\n      return this.storeQueryParamObj(store);\n    });\n\n    return apiStores;\n  }\n\n  private storeQueryParamObj(store: IStore) {\n    const query = store?.query;\n\n    const tags = query?.tags || [];\n    const categories = query?.categories || [];\n    const read = query?.read;\n    const archived = query?.archived;\n\n    return {\n      store_id: store.storeId,\n      query: {\n        read,\n        archived,\n        tags: { or: tags },\n        categories: { or: categories },\n      },\n    };\n  }\n\n  async changeActiveStore(storeId: string) {\n    const storeData = this.store.getState();\n\n    if (storeData.store.storeId === storeId) return;\n\n    const selectedStore = this.feedOptions.stores?.find(\n      (store) => store.storeId === storeId\n    );\n\n    if (!selectedStore) {\n      return {\n        status: RESPONSE_STATUS.ERROR,\n        error: {\n          type: ERROR_TYPE.NOT_FOUND,\n          message: `store with storeId ${storeId} doesnt exist`,\n        },\n      };\n    }\n\n    // Cancel any in-progress fetch request to prevent stale data from previous store\n    if (this.fetchAbortController) {\n      this.fetchAbortController.abort();\n      this.fetchAbortController = undefined;\n    }\n\n    this.store.setState({\n      ...initialFeedStore,\n      store: selectedStore,\n      meta: storeData.meta,\n    });\n\n    return await this.fetch();\n  }\n\n  get data() {\n    const storeData = this.store.getState();\n\n    return {\n      notifications: storeData.notifications,\n      pageInfo: storeData.pageInfo,\n      meta: storeData.meta,\n      apiStatus: storeData.apiStatus,\n      store: storeData.store,\n    } as IFeedData;\n  }\n\n  initializeSocketConnection() {\n    if (this.socket) return;\n\n    this.socket = io(this.feedOptions.host?.socketHost, {\n      transports: ['websocket'],\n      auth: {\n        authorization: this.config.publicApiKey,\n        'x-ss-signature': this.config.userToken,\n        distinct_id: this.config.distinctId,\n        tenant_id: this.feedOptions.tenantId,\n        schema: '1',\n      },\n      reconnectionDelay: 1000,\n      reconnectionDelayMax: 10000,\n    });\n\n    this.initializeSocketEvents();\n  }\n\n  // TODO: support other stores and pages\n  async fetch(options: IInboxFetchOptions = {}) {\n    const storeData = this.store.getState();\n\n    if (this.requestInprogress()) return;\n\n    const pageSize = options?.pageSize || this.feedOptions.pageSize;\n\n    if (!storeData.isFirstFetch) {\n      this.store.setState({\n        apiStatus: ApiResponseStatus.FETCHING_MORE,\n      });\n    } else {\n      this.store.setState({\n        apiStatus: ApiResponseStatus.LOADING,\n      });\n      this.fetchCount();\n    }\n    this.emitter.emit('feed.store_update', this.data);\n\n    const queryParams: Dictionary = {\n      distinct_id: this.config.distinctId,\n      tenant_id: this.feedOptions.tenantId,\n      page_size: pageSize,\n      store:\n        storeData.store.storeId !== DEFAULT_STORE.storeId\n          ? this.storeQueryParamObj(storeData.store)\n          : null,\n    };\n\n    if (storeData.notifications.length > 0) {\n      const lastNotification =\n        storeData.notifications[storeData.notifications.length - 1];\n      queryParams.search_after = [\n        lastNotification.is_pinned,\n        lastNotification.created_on,\n      ];\n    } else {\n      queryParams.search_after = [];\n    }\n\n    const url = this.getUrl('notifications', queryParams);\n\n    // Create an AbortController for this fetch so it can be cancelled on store switch\n    const abortController = new AbortController();\n    this.fetchAbortController = abortController;\n\n    const response = await this.config\n      .client()\n      .request({ type: 'get', url, signal: abortController.signal });\n\n    // If this fetch was aborted (e.g. user switched stores), discard the response\n    if (abortController.signal.aborted) {\n      return;\n    }\n\n    if (response.status === RESPONSE_STATUS.ERROR) {\n      this.store.setState({ apiStatus: ApiResponseStatus.ERROR });\n      this.emitter.emit('feed.store_update', this.data);\n      return response;\n    }\n\n    this.store.setState({\n      apiStatus: ApiResponseStatus.SUCCESS,\n      notifications: storeData.isFirstFetch\n        ? response.body.results\n        : [...storeData.notifications, ...response.body.results],\n      pageInfo: {\n        ...storeData.pageInfo,\n        total: response.body.meta.total_count,\n        hasMore: response.body.meta.has_more,\n      },\n      isFirstFetch: false,\n    });\n    this.emitter.emit('feed.store_update', this.data);\n\n    this.startExpiryTimer();\n\n    return response;\n  }\n\n  // TODO: support other stores\n  async fetchNextPage() {\n    const storeData = this.store.getState();\n\n    if (storeData.pageInfo.hasMore === false) {\n      return {\n        status: RESPONSE_STATUS.ERROR,\n        error: {\n          type: ERROR_TYPE.VALIDATION_ERROR,\n          message: 'No more pages to fetch',\n        },\n      } as ApiResponse;\n    }\n\n    return this.fetch();\n  }\n\n  async fetchCount() {\n    const queryParams: Dictionary = {\n      distinct_id: this.config.distinctId,\n      tenant_id: this.feedOptions.tenantId,\n      stores: this.feedOptions.stores\n        ? this.storesQueryParamObj(this.feedOptions.stores)\n        : null,\n    };\n\n    const url = this.getUrl('notifications_count', queryParams);\n\n    const response = await this.config.client().request({ type: 'get', url });\n\n    if (response.status === RESPONSE_STATUS.SUCCESS) {\n      this.store.setState({ meta: response.body });\n    }\n\n    this.emitter.emit('feed.store_update', this.data);\n    return response;\n  }\n\n  async fetchDetails(notificationId: string) {\n    const url = this.getUrl(`notifications/${notificationId}`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    return await this.config.client().request({ type: 'get', url });\n  }\n\n  async markAsSeen(notificationId: string) {\n    const storeData = this.store.getState();\n    let alreadyUpdated = false;\n\n    this.store.setState({\n      notifications: storeData.notifications.map((notification) => {\n        if (notification.n_id === notificationId) {\n          if (!notification.seen_on) {\n            notification.seen_on = Date.now();\n          } else {\n            alreadyUpdated = true;\n          }\n        }\n        return notification;\n      }),\n    });\n\n    if (alreadyUpdated) return { status: RESPONSE_STATUS.SUCCESS };\n\n    const url = this.getUrl(`notifications/${notificationId}/seen`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  async markAsRead(notificationId: string) {\n    const storeData = this.store.getState();\n    let alreadyUpdated = false;\n\n    this.store.setState({\n      notifications: storeData.notifications.map((notification) => {\n        if (notification.n_id === notificationId) {\n          if (!notification.read_on) {\n            notification.read_on = Date.now();\n            notification.seen_on = Date.now();\n          } else {\n            alreadyUpdated = true;\n          }\n        }\n        return notification;\n      }),\n    });\n\n    if (alreadyUpdated) return { status: RESPONSE_STATUS.SUCCESS };\n\n    const url = this.getUrl(`notifications/${notificationId}/read`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  async markAsUnread(notificationId: string) {\n    const storeData = this.store.getState();\n    let alreadyUpdated = false;\n\n    this.store.setState({\n      notifications: storeData.notifications.map((notification) => {\n        if (notification.n_id === notificationId) {\n          if (notification.read_on) {\n            notification.read_on = null;\n          } else {\n            alreadyUpdated = true;\n          }\n        }\n        return notification;\n      }),\n    });\n\n    if (alreadyUpdated) return { status: RESPONSE_STATUS.SUCCESS };\n\n    const url = this.getUrl(`notifications/${notificationId}/unread`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  // TODO: improve logic for already interacted cases\n  async markAsInteracted(notificationId: string) {\n    const storeData = this.store.getState();\n\n    this.store.setState({\n      notifications: storeData.notifications.map((notification) => {\n        if (notification.n_id === notificationId) {\n          if (!notification.interacted_on) {\n            notification.interacted_on = Date.now();\n          }\n          if (!notification.read_on) {\n            notification.read_on = Date.now();\n          }\n        }\n        return notification;\n      }),\n    });\n\n    const url = this.getUrl(`notifications/${notificationId}/interacted`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  async markAsArchived(notificationId: string) {\n    const storeData = this.store.getState();\n    let alreadyUpdated = false;\n\n    this.store.setState({\n      notifications: storeData.notifications.filter((notification) => {\n        if (notification.n_id === notificationId) {\n          alreadyUpdated = !!notification.archived;\n          return false;\n        } else {\n          return true;\n        }\n      }),\n    });\n\n    if (alreadyUpdated) return { status: RESPONSE_STATUS.SUCCESS };\n\n    const url = this.getUrl(`notifications/${notificationId}/archive`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  async markBulkAsSeen(notificationIds: string[]) {\n    const storeData = this.store.getState();\n\n    this.store.setState({\n      notifications: storeData.notifications.map((notification) => {\n        if (notificationIds.includes(notification.n_id)) {\n          if (!notification.seen_on) {\n            notification.seen_on = Date.now();\n          }\n        }\n        return notification;\n      }),\n    });\n\n    const url = this.getUrl(`bulk/notifications/seen`, {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({\n      type: 'post',\n      url,\n      payload: { notification_ids: notificationIds },\n    });\n  }\n\n  async resetBadgeCount() {\n    const storeData = this.store.getState();\n\n    // optimistic update\n    this.store.setState({ meta: { ...storeData.meta, badge: 0 } });\n\n    const url = this.getUrl('reset_bell_count', {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  async markAllAsRead() {\n    const storeData = this.store.getState();\n\n    // optimistic update\n    this.store.setState({\n      meta: { ...storeData.meta, badge: 0 },\n      notifications: storeData.notifications.map((notification) => {\n        notification.read_on = Date.now();\n        return notification;\n      }),\n    });\n\n    const url = this.getUrl('mark_all_read', {\n      tenant_id: this.feedOptions.tenantId,\n      distinct_id: this.config.distinctId,\n    });\n\n    this.emitter.emit('feed.store_update', this.data);\n    return await this.config.client().request({ type: 'patch', url });\n  }\n\n  reset() {\n    this.store.setState({\n      ...initialFeedStore,\n      store: this.feedOptions.stores?.[0] || DEFAULT_STORE,\n    });\n    this.emitter.emit('feed.store_update', this.data);\n\n    if (this.expiryTimerId) {\n      clearInterval(this.expiryTimerId);\n      this.expiryTimerId = undefined;\n    }\n  }\n\n  remove() {\n    this.reset();\n    this.emitter.off('*');\n    this.socket?.disconnect();\n    this.config.feeds.removeInstance(this);\n  }\n}\n","import mitt, { Emitter } from 'mitt';\nimport jwt_decode from 'jwt-decode';\nimport {\n  SuprSendOptions,\n  Dictionary,\n  EmitterEvents,\n  AuthenticateOptions,\n  RefreshTokenCallback,\n  ERROR_TYPE,\n  RESPONSE_STATUS,\n} from './interface';\nimport ApiClient from './api';\nimport {\n  uuid,\n  epochMs,\n  windowSupport,\n  getResponsePayload,\n  getLocalStorageData,\n  setLocalStorageData,\n  removeLocalStorageData,\n} from './utils';\nimport User from './user';\nimport WebPush, { SUPRSEND_ENDPOINT_KEY } from './webpush';\nimport FeedsFactory from './feed';\n\nconst DEFAULT_HOST = 'https://hub.suprsend.com';\nconst DEFAULT_SW_FILENAME = 'serviceworker.js';\nconst AUTHENTICATED_DISTINCT_ID = 'ss_distinct_id';\n\nexport default class SuprSend {\n  public host: string;\n  public publicApiKey: string;\n  public distinctId: unknown;\n  public userToken?: string;\n  public vapidKey: string;\n  public swFileName: string;\n  private apiClient: ApiClient | null = null;\n  private userTokenExpirationTimer: ReturnType<typeof setTimeout> | null = null;\n  public authenticateOptions?: AuthenticateOptions;\n\n  readonly user = new User(this);\n  readonly webpush = new WebPush(this);\n  readonly feeds = new FeedsFactory(this);\n  readonly emitter: Emitter<EmitterEvents> = mitt();\n\n  constructor(publicApiKey: string, options?: SuprSendOptions) {\n    if (!publicApiKey) {\n      throw new Error('[SuprSend]: publicApiKey is missing');\n    }\n\n    this.publicApiKey = publicApiKey;\n    this.host = options?.host || DEFAULT_HOST;\n    this.vapidKey = options?.vapidKey || '';\n    this.swFileName = options?.swFileName || DEFAULT_SW_FILENAME;\n  }\n\n  private handleRefreshUserToken(refreshUserToken: RefreshTokenCallback) {\n    if (!this.userToken || !windowSupport()) return;\n\n    const jwtPayload = jwt_decode(this.userToken) as Dictionary;\n    const expiresOn = ((jwtPayload.exp as number) || 0) * 1000; // in ms\n    const now = Date.now(); // in ms\n    const refreshBefore = 1000 * 30; // call refresh api before 30sec of expiry\n\n    if (expiresOn && expiresOn > now) {\n      const timeDiff = expiresOn - now - refreshBefore;\n\n      if (this.userTokenExpirationTimer) {\n        clearTimeout(this.userTokenExpirationTimer);\n      }\n      this.userTokenExpirationTimer = setTimeout(async () => {\n        let newToken = '';\n        try {\n          newToken = await refreshUserToken(\n            this.userToken as string,\n            jwtPayload\n          );\n        } catch (e) {\n          // retry fetching token\n          try {\n            newToken = await refreshUserToken(\n              this.userToken as string,\n              jwtPayload\n            );\n          } catch (e) {\n            console.warn(\"[SuprSend]: Couldn't fetch new userToken\", e);\n          }\n        }\n\n        if (newToken && typeof newToken === 'string') {\n          this.identify(this.distinctId, newToken, this.authenticateOptions);\n        }\n      }, timeDiff);\n    }\n  }\n\n  client() {\n    if (!this.distinctId) {\n      console.warn(\n        '[SuprSend]: distinctId is missing. User should be authenticated'\n      );\n    }\n\n    if (!this.apiClient) {\n      this.apiClient = new ApiClient(this);\n    }\n\n    return this.apiClient;\n  }\n\n  eventApi(payload: Dictionary) {\n    return this.client().request({\n      url: `${this.host}/v2/event`,\n      payload,\n      type: 'post',\n    });\n  }\n\n  /**\n   *  Used to authenticate user. Usually called just after successful login and on reload of loggedin route to re-authenticate loggedin user.\n   *  In production env's userToken is mandatory for security purposes.\n   */\n  async identify(\n    distinctId: unknown,\n    userToken?: string,\n    options?: AuthenticateOptions\n  ) {\n    if (!distinctId) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'distinctId is missing',\n      });\n    }\n\n    // other user already present\n    if (this.apiClient && this.distinctId && this.distinctId !== distinctId) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage:\n          'User already loggedin, reset current user to login new user',\n      });\n    }\n\n    // updating usertoken for existing user\n    if (\n      this.apiClient &&\n      this.distinctId === distinctId &&\n      this.userToken !== userToken\n    ) {\n      this.userToken = userToken;\n      this.apiClient = new ApiClient(this);\n      if (options?.refreshUserToken) {\n        this.handleRefreshUserToken(options.refreshUserToken);\n      }\n      return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n    }\n\n    // ignore more than one identify call\n    if (this.distinctId && this.apiClient) {\n      return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n    }\n\n    this.distinctId = distinctId;\n    this.userToken = userToken;\n    this.apiClient = new ApiClient(this);\n    this.authenticateOptions = options;\n    const authenticatedDistinctId = getLocalStorageData(\n      AUTHENTICATED_DISTINCT_ID\n    );\n\n    if (options?.refreshUserToken) {\n      this.handleRefreshUserToken(options.refreshUserToken);\n    }\n\n    // already loggedin\n    if (authenticatedDistinctId == this.distinctId) {\n      this.webpush.updatePushSubscription();\n      return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n    }\n\n    // first time login\n    const resp = await this.eventApi({\n      event: '$identify',\n      $insert_id: uuid(),\n      $time: epochMs(),\n      properties: {\n        $identified_id: distinctId,\n      },\n    });\n\n    if (resp.status === RESPONSE_STATUS.SUCCESS) {\n      // store user so that other method calls dont need api calls\n      this.webpush.updatePushSubscription();\n      setLocalStorageData(AUTHENTICATED_DISTINCT_ID, this.distinctId as string);\n    } else {\n      // reset user data so that user can retry\n      this.reset({ unsubscribePush: false });\n    }\n    return resp;\n  }\n\n  /**\n   * Check's if SuprSend instance is authenticated. To check if userToken is also present pass true.\n   */\n  isIdentified(checkUserToken?: boolean) {\n    return checkUserToken\n      ? !!(this.userToken && this.distinctId)\n      : !!this.distinctId;\n  }\n\n  /**\n   *  Used to trigger events to suprsend.\n   */\n  async track(event: string, properties?: Dictionary) {\n    let propertiesObj: Dictionary = {};\n\n    if (!event) {\n      return getResponsePayload({\n        status: RESPONSE_STATUS.ERROR,\n        errorType: ERROR_TYPE.VALIDATION_ERROR,\n        errorMessage: 'event name is missing',\n      });\n    }\n    // TODO: add check to validate special keys\n    if (typeof properties === 'object') {\n      propertiesObj = { ...propertiesObj, ...properties };\n    }\n\n    return this.eventApi({\n      event: String(event),\n      $insert_id: uuid(),\n      $time: epochMs(),\n      distinct_id: this.distinctId,\n      properties: propertiesObj,\n    });\n  }\n\n  /**\n   * Clears user related data attached to SuprSend instance. Usually called during logout.\n   */\n  async reset(options?: { unsubscribePush?: boolean }) {\n    const unsubscribePush = !(options?.unsubscribePush === false); // defaults to true\n\n    if (unsubscribePush) {\n      await this.webpush?.removePushSubscription();\n      removeLocalStorageData(SUPRSEND_ENDPOINT_KEY);\n    }\n\n    this.apiClient = null;\n    this.distinctId = null;\n    this.userToken = '';\n    // removeLocalStorageData(AUTHENTICATED_DISTINCT_ID);\n\n    if (this.userTokenExpirationTimer) {\n      clearTimeout(this.userTokenExpirationTimer);\n    }\n\n    if (this.feeds.feedInstances?.length > 0) {\n      this.feeds.removeAll();\n    }\n    return getResponsePayload({ status: RESPONSE_STATUS.SUCCESS });\n  }\n}\n"],"names":["PreferenceOptions","ChannelLevelPreferenceOptions","ERROR_TYPE","RESPONSE_STATUS","ApiResponseStatus","uuid","dt","c","r","epochMs","isObjectEmpty","objectName","isArrayEmpty","arrayName","urlB64ToUint8Array","base64String","padding","base64","rawData","outputArray","debounce","callback","wait","timer","args","resolve","debounceByType","func","memory","searchType","payload","getResponsePayload","options","response","windowSupport","setLocalStorageData","key","value","getLocalStorageData","removeLocalStorageData","sha256Hash","input","data","hashBuffer","b","ApiClient","config","__publicField","headers","reqData","url","signal","_a","jwtPayload","jwt_decode","expiresOn","now","newUserToken","resp","respData","respStatus","_b","_c","e","Preferences","queryParams","validatedParams","path","qp","urlPath","validatedQueryParams","queryParamsString","category","body","subcategory","preference","categoryData","dataUpdated","section","abort","optOutChannels","channel","showOptOutChannels","requestPayload","_d","_e","selectedChannelData","channelData","preferenceRestricted","channelItem","DEVICE_ID_KEY","User","arg1","arg2","validatedData","allowReservedKeys","valueType","item","arg","email","mobile","deviceId","push","language","timezone","SUPRSEND_ENDPOINT_KEY","WebPush","registration","subscription","endpoint","hash","readyRegistration","pushSubscriptionObj","DEFAULT_PAGE_SIZE","DEFAULT_TENANT_ID","MAX_PAGE_SIZE","DEFAULT_STORE","feedOptionsDefaults","initialFeedStore","FeedsFactory","feedClient","Feed","instance","feedInstance","mitt","stores","validatedStores","store","query","read","archived","tags","categories","tag","createStore","error","userToken","storeData","newNotificationData","emitNewNotificationEvent","newMetaData","apiResponses","notificationPresent","notif","notification","notifRead","notifArchived","notifTags","notifCategory","storeRead","storeArchived","storeTags","storeCategories","sameRead","sameArchived","sameTags","sameCategory","newNotification","existingNotifications","addedNotification","notifications","hasExpired","paramValue","storeId","selectedStore","io","pageSize","lastNotification","abortController","notificationId","alreadyUpdated","notificationIds","DEFAULT_HOST","DEFAULT_SW_FILENAME","AUTHENTICATED_DISTINCT_ID","SuprSend","publicApiKey","refreshUserToken","refreshBefore","timeDiff","newToken","distinctId","authenticatedDistinctId","checkUserToken","event","properties","propertiesObj"],"mappings":"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"}