@suprsend/web-sdk 4.1.2 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/es/index.js +479 -416
- package/dist/es/index.js.map +1 -1
- package/dist/types/api.d.ts +0 -1
- package/dist/types/feed.d.ts +0 -1
- package/dist/types/interface.d.ts +20 -0
- package/dist/types/main.d.ts +7 -6
- package/dist/types/preferences.d.ts +0 -1
- package/dist/types/user.d.ts +0 -1
- package/dist/types/utils.d.ts +14 -3
- package/dist/types/webpush.d.ts +0 -1
- package/package.json +6 -6
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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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"}
|
|
1
|
+
{"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 AppInfo {\n name?: string;\n version?: string;\n}\n\nexport interface ClientUserAgentConfig {\n sdk?: string;\n sdk_version?: string;\n lang?: string;\n platform?: string;\n environment?: string;\n os?: string;\n os_version?: string;\n app_info?: AppInfo;\n browser?: string;\n browser_version?: string;\n device_model?: string;\n}\n\nexport interface SuprSendOptions {\n host?: string;\n vapidKey?: string;\n swFileName?: string;\n appInfo?: AppInfo;\n clientUserAgent?: ClientUserAgentConfig;\n}\n\nexport type RefreshTokenCallback = (\n oldUserToken: string,\n tokenPayload: Dictionary\n) => Promise<string>;\n\nexport interface AuthenticateOptions {\n refreshUserToken?: RefreshTokenCallback;\n createUser?: boolean;\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 AppInfo,\n ClientUserAgentConfig,\n Dictionary,\n ResponseOptions,\n RESPONSE_STATUS,\n} from './interface';\nimport { name as SDK_NAME, version as SDK_VERSION } from '../package.json';\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 localStorageSupport() {\n if (!windowSupport() || !window?.localStorage) return false;\n return true;\n}\n\nexport function setLocalStorageData(key: string, value: string) {\n if (!localStorageSupport()) 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 (!localStorageSupport()) return;\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 (!localStorageSupport()) return;\n\n localStorage.removeItem(key);\n}\n\nfunction getUserAgent(): string {\n return typeof navigator !== 'undefined' ? navigator.userAgent || '' : '';\n}\n\nexport function detectOS(ua: string = getUserAgent()): {\n os: string;\n os_version: string;\n} {\n let match: RegExpMatchArray | null;\n\n if ((match = ua.match(/Windows NT (\\d+(?:\\.\\d+)*)/i))) {\n return { os: 'windows', os_version: match[1] };\n }\n if (\n (match = ua.match(\n /(?:iPhone|iPad|iPod)[^;]*;\\s*CPU[^)]*OS (\\d+[_.]\\d+(?:[_.]\\d+)?)/i\n ))\n ) {\n return { os: 'ios', os_version: match[1].replace(/_/g, '.') };\n }\n if ((match = ua.match(/Android (\\d+(?:\\.\\d+)*)/i))) {\n return { os: 'android', os_version: match[1] };\n }\n if ((match = ua.match(/Mac OS X (\\d+[_.]\\d+(?:[_.]\\d+)?)/i))) {\n return { os: 'mac os', os_version: match[1].replace(/_/g, '.') };\n }\n if (/Linux/i.test(ua)) {\n return { os: 'linux', os_version: '' };\n }\n return { os: '', os_version: '' };\n}\n\nexport function detectBrowser(ua: string = getUserAgent()): {\n browser: string;\n browser_version: string;\n} {\n let match: RegExpMatchArray | null;\n\n if ((match = ua.match(/Edg(?:e|A|iOS)?\\/(\\d+(?:\\.\\d+)*)/i))) {\n return { browser: 'edge', browser_version: match[1] };\n }\n if ((match = ua.match(/OPR\\/(\\d+(?:\\.\\d+)*)/i))) {\n return { browser: 'opera', browser_version: match[1] };\n }\n if ((match = ua.match(/Firefox\\/(\\d+(?:\\.\\d+)*)/i))) {\n return { browser: 'firefox', browser_version: match[1] };\n }\n if ((match = ua.match(/Chrome\\/(\\d+(?:\\.\\d+)*)/i))) {\n return { browser: 'chrome', browser_version: match[1] };\n }\n if ((match = ua.match(/Version\\/(\\d+(?:\\.\\d+)*)[^)]*Safari/i))) {\n return { browser: 'safari', browser_version: match[1] };\n }\n if (/Safari/i.test(ua)) {\n return { browser: 'safari', browser_version: '' };\n }\n return { browser: '', browser_version: '' };\n}\n\nexport function detectEnvironment(ua: string = getUserAgent()): string {\n if (!ua) return '';\n if (/iPad|Tablet/i.test(ua) || (/Android/i.test(ua) && !/Mobile/i.test(ua))) {\n return 'tablet';\n }\n if (/Mobi|Android|iPhone|iPod/i.test(ua)) {\n return 'mobile';\n }\n return 'desktop';\n}\n\nexport function buildClientUserAgent(\n appInfo?: AppInfo,\n override?: ClientUserAgentConfig\n): ClientUserAgentConfig {\n const ua = getUserAgent();\n const { os, os_version } = detectOS(ua);\n const { browser, browser_version } = detectBrowser(ua);\n\n const defaults: ClientUserAgentConfig = {\n sdk: (SDK_NAME || '').toLowerCase(),\n sdk_version: (SDK_VERSION || '').toLowerCase(),\n lang: 'javascript',\n platform: 'browser',\n environment: detectEnvironment(ua),\n os,\n os_version,\n browser,\n browser_version,\n };\n\n if (appInfo?.name) {\n defaults.app_info = {\n name: appInfo.name,\n version: appInfo.version || '',\n };\n }\n\n if (!override) return defaults;\n\n const merged: ClientUserAgentConfig = { ...defaults };\n\n // merge override into defaults, with special handling for app_info to merge its properties\n for (const key of Object.keys(override) as (keyof ClientUserAgentConfig)[]) {\n const value = override[key];\n if (value === undefined) continue;\n if (key === 'app_info') {\n merged.app_info = { ...defaults.app_info, ...(value as AppInfo) };\n } else {\n (merged as Dictionary)[key] = value;\n }\n }\n return merged;\n}\n\nfunction formatAppInfo(info?: AppInfo): string {\n if (!info?.name) return '';\n return info.version ? `${info.name}/${info.version}` : info.name;\n}\n\nexport function buildUserAgent(config: ClientUserAgentConfig): string {\n const sdkName = config.sdk || '';\n const sdkVersion = config.sdk_version || '';\n let result = sdkVersion ? `${sdkName}/${sdkVersion}` : sdkName;\n\n const runtime = config.browser\n ? `${config.browser}${config.browser_version ? `/${config.browser_version}` : ''}`\n : config.lang || '';\n const detailParts: string[] = [];\n if (runtime) detailParts.push(runtime);\n if (config.os) detailParts.push(config.os);\n if (detailParts.length) result += ` (${detailParts.join('; ')})`;\n\n const appPart = formatAppInfo(config.app_info);\n if (appPart) result += ` (${appPart})`;\n\n return result;\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 'X-Suprsend-Client-User-Agent': JSON.stringify(\n this.config.clientUserAgent\n ),\n 'X-Suprsend-User-Agent': this.config.userAgent,\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 ApiResponse,\n ClientUserAgentConfig,\n} from './interface';\nimport ApiClient from './api';\nimport {\n uuid,\n epochMs,\n windowSupport,\n getResponsePayload,\n getLocalStorageData,\n setLocalStorageData,\n removeLocalStorageData,\n buildUserAgent,\n buildClientUserAgent,\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 public clientUserAgent: ClientUserAgentConfig;\n public userAgent: 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 this.clientUserAgent = buildClientUserAgent(\n options?.appInfo,\n options?.clientUserAgent\n );\n this.userAgent = buildUserAgent(this.clientUserAgent);\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 let resp: ApiResponse;\n const createUser = options?.createUser !== false;\n // first time login\n if (createUser) {\n resp = await this.eventApi({\n event: '$identify',\n $insert_id: uuid(),\n $time: epochMs(),\n properties: {\n $identified_id: distinctId,\n },\n });\n } else {\n resp = { status: RESPONSE_STATUS.SUCCESS };\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","i","debounce","callback","wait","timer","args","resolve","debounceByType","func","memory","searchType","payload","getResponsePayload","options","response","windowSupport","localStorageSupport","setLocalStorageData","key","value","getLocalStorageData","removeLocalStorageData","getUserAgent","detectOS","ua","match","detectBrowser","detectEnvironment","buildClientUserAgent","appInfo","override","os","os_version","browser","browser_version","defaults","SDK_NAME","SDK_VERSION","merged","formatAppInfo","info","buildUserAgent","config","sdkName","sdkVersion","result","runtime","detailParts","appPart","sha256Hash","input","data","hashBuffer","b","ApiClient","__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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"}
|