import AsyncStorage from '@react-native-async-storage/async-storage'; import type { DeJsvHelper, MapLike, MpDeviceInfo, QcInfoItem, SdkInitOptions, UrlInfo, VisitInfo, VisitorInfo, } from './app-types'; import type { GeoResponse } from '../models/geo-api-response'; import { Logger } from './logger'; import type { ClientSdkDeItem, ClientSdkPrItem, ClientSdkQcItem, ClientSdkTagItem, MpClientSdk, } from '../models/mp-client-sdk'; import { Platform } from 'react-native'; import { Utils } from './utils'; import { version as SDK_VERSION } from '../../package.json'; export class DataStore { private static isDataStoreInitialized = false; private static dataElements: MapLike = {}; private static validQcList: string[]; private static validQcInfoList: Array = []; private static transFunctions: MapLike = {}; private static prStatus = true; private static clientSdk: MpClientSdk; private static urls: UrlInfo; private static debugId: string; private static visitorInfo: VisitorInfo | null; private static visitInfo: VisitInfo; private static pageLang = 'en'; private static mpEnvShort: 'stg' | 'prd'; private static devicePlatform = 'unknown'; private static deviceType = 'mobile'; private static sdkInitOptions: SdkInitOptions; private static deviceInfo: MpDeviceInfo; private static geoInfo: GeoResponse; private static interestedClientSideEvents: string[] = []; private static interestedServerSideEvents: string[] = []; private static interestedAllEvents: string[] = []; private static commonCookies: Record = {}; static async init(clientSdk: MpClientSdk): Promise { this.clientSdk = clientSdk; this.setMpEnv(clientSdk?.s?.ev === 'staging' ? 'stg' : 'prd'); if (typeof Platform !== 'undefined' && typeof Platform.OS !== 'undefined') { this.devicePlatform = Platform.OS.toLowerCase(); } if (Utils.isTablet()) { this.deviceType = 'tablet'; } else { this.deviceType = 'mobile'; } this.interestedClientSideEvents = Utils._makeUniqueStringArray([ ...(clientSdk.dtmE ?? []), ...(clientSdk.ctmE ?? []), ...(clientSdk.mpDlE ?? []), ]); this.interestedServerSideEvents = Utils._makeUniqueStringArray([ ...(clientSdk.sseDtmE ?? []), ...(clientSdk.sseCtmE ?? []), ...(clientSdk.sseMpDlE ?? []), ]); this.interestedAllEvents = Utils._makeUniqueStringArray([ ...this.interestedClientSideEvents, ...this.interestedServerSideEvents, ]); this.resetCollectorUrl( clientSdk.s.c_url, clientSdk.s.ev, clientSdk.s.v_id, clientSdk.s.p_id ); this.isDataStoreInitialized = true; } static resetCollectorUrl( baseCollectorUrl: string, sdkEnv: string, vendorId: string, projectId: string ): boolean { const tagsBaseUrl = `${baseCollectorUrl}/${ sdkEnv === 'staging' ? 's' : 'p' }/${vendorId}/${projectId}`; this.urls = { tfUrl: tagsBaseUrl + '/sst', errUrl: tagsBaseUrl + '/err', rptUrl: tagsBaseUrl + '/report', infoUrl: tagsBaseUrl + '/info', baseUrl: baseCollectorUrl, attrInfoUrl: baseCollectorUrl + `/idl/${vendorId}/attrInfo`, idlUrl: baseCollectorUrl + `/idl/${vendorId}/idl${sdkEnv === 'staging' ? '-staging' : ''}`, geoUrl: '/geo', baseUrlV4: baseCollectorUrl, baseUrlV6: baseCollectorUrl, // For React Native, we'll use the same URL for both IPv4 and IPv6 }; return true; } static isDataStoreReady(): boolean { return this.isDataStoreInitialized; } static shouldExecuteTMForEvent(eventName: string): boolean { return this.interestedAllEvents.indexOf(eventName) > -1; } static shouldExecuteSST(eventName: string): boolean { return this.interestedServerSideEvents.indexOf(eventName) > -1; } static shouldExecuteClientSideTm(eventName: string): boolean { return this.interestedClientSideEvents.indexOf(eventName) > -1; } static getSdkPcKey(): string { return this.clientSdk.pcKey; } static getSdkInitOptions(): SdkInitOptions { return this.sdkInitOptions; } static setDeviceInfo(info: MpDeviceInfo): void { this.deviceInfo = info; } static getDeviceInfo(): MpDeviceInfo { return this.deviceInfo; } static setSdkInitOptions(options: SdkInitOptions): void { this.sdkInitOptions = options; } static getSdkDataElements(): MapLike { return this.clientSdk?.d || {}; } static getSdkQC(): ClientSdkQcItem[] { return this.clientSdk?.qc || []; } static hasOneSSTTag(): boolean { return this.clientSdk.s.sst; } static getSSTDownStream(): 'j' | 'n' { return this.clientSdk.s.dws_s_t; } static getClientDownStream(): 'j' | 'n' { return this.clientSdk.s.dws_c_t; } static getClientSdk(): MpClientSdk { return this.clientSdk; } static getSSTUrl(): string { return this.urls.tfUrl; } static getAttrInfoUrl(): string { return this.urls.attrInfoUrl; } static setVisitInfo(visitInfo: VisitInfo): void { this.visitInfo = visitInfo; } static visitInfoToString(): string { return this.visitInfo ? `${this.visitInfo.visitVer}|${this.visitInfo.visitId}|${this.visitInfo.visitTs}|${this.visitInfo.visitCt}|${this.visitInfo.visitDepth}` : undefined; } static setVisitorInfo(visitorInfo: VisitorInfo | null): void { this.visitorInfo = visitorInfo; } static getVisitorInfo(): VisitorInfo | null { return this.visitorInfo; } static getDebugId(): string { return this.debugId; } static getErrorReportUrl(): string { return this.urls.errUrl; } static getIdlUrl(): string { return this.urls?.idlUrl; } static getSdkVersion(): string { return this.clientSdk.s.v; } static setDebugId(dbgId: string): void { this.debugId = dbgId; } static shouldFireSstForEvent(eventName: string): boolean { return this.clientSdk?.sseMpDlE?.indexOf(eventName) > -1; } static addCommonCookie(key: string, value: string): void { this.commonCookies[key] = value; } static getCommonCookies(): Record { return this.commonCookies; } static getUrlInfo(): UrlInfo { return this.urls; } static getSdkTags(): MapLike { return this?.clientSdk?.t ?? {}; } static getSdkProviders(): MapLike { return this?.clientSdk?.p ?? {}; } static getPrivacyCompliance(): boolean { return this.prStatus; } static setPrivacyCompliance(status: boolean): void { this.prStatus = status; } static async storeData(key: string, value: any): Promise { await AsyncStorage.setItem(key, JSON.stringify(value)); } static async getDataFromStorage(key: string): Promise { const value = await AsyncStorage.getItem(key); return value ? JSON.parse(value) : value; } static getDataElements(): MapLike { return this.dataElements; } static setDataElements(de: MapLike): void { this.dataElements = de; } static getPageLang(): string { return this.pageLang; } static getDeviceOs(): string { return this.devicePlatform; } static getDataElementHelpers(): DeJsvHelper { return { log: Logger.logDbg, err: Logger.logError, }; } static getPageName(): string { return (this.getDataElementValue('page_name') as string) || 'none'; } static getDataElementValue(param: string): string | boolean | number { return this.dataElements[param]; } static setPageLang(lang: string): void { this.pageLang = lang || 'en'; } static getSdkPageLangKey(): string { return this.clientSdk.langKey; } static setDataElement(key: string, value: any): void { this.dataElements[key] = value; } static setValidQc(qcList: string[], qcInfo: QcInfoItem[]): void { this.validQcList = qcList; this.validQcInfoList = qcInfo; } static getValidQcList(): string[] { return this.validQcList || []; } static getValidQcInfo(): QcInfoItem[] { return this.validQcInfoList || []; } static setTransFunctions(elements: MapLike): MapLike { this.transFunctions = elements; return this.transFunctions; } static getTransFunctions(): MapLike { return this.transFunctions; } static getOperatingSystem(): string { return this.devicePlatform; } static getVisitId(): string { return this.visitInfo?.visitId; } static overrideDeviceType(deviceType: string): void { this.deviceType = deviceType?.trim()?.toLowerCase(); } static getDeviceType(): string { return this.deviceType; } static getDeviceId(): string { return this.visitorInfo?.dId; } static getMpId(): string { return this.visitorInfo?.mId; } static getVisitorInfoAsString(): string | undefined { return this.visitorInfo ? JSON.stringify(this.visitorInfo) : undefined; } static getOrgId(): string { return this?.clientSdk?.s?.v_id; } static getCoreVersion(): string { return SDK_VERSION; } static getMpEnv(): 'stg' | 'prd' { return this.mpEnvShort; } static setMpEnv(shortEnv: 'stg' | 'prd'): void { this.mpEnvShort = shortEnv; } static setGeoInfo(geoInfo: GeoResponse): void { this.geoInfo = geoInfo; } static getGeoInfo(): GeoResponse | undefined { return this.geoInfo; } static isGeoLocationEnabledInSdk(): boolean { // TODO: Add geo location configuration to SDK settings // For now, return true to enable geo location by default return false; } static getVisitInfo(): VisitInfo | undefined { return this.visitInfo; } static getBrowser(): string { // In React Native, we return the platform as browser equivalent return this.devicePlatform; } static getMpUserStatus(): number { // Return user status based on visit count // 1 = new user (first visit), 0 = returning user const visitInfo = this.getVisitInfo(); if (!visitInfo) { return 1; // Default to new user if no visit info } return visitInfo.visitCt === 1 ? 1 : 0; } }