@causalfoundry/js-sdk
Version:
Causal Foundry WEB SDK (JS/TS)
393 lines (314 loc) • 12.4 kB
text/typescript
import {createCheckers} from "ts-interface-checker"
import {EventEmitter} from 'events';
import ECommerce from "../ECommerce";
import Loyalty from "../Loyalty";
import Navigation from '../Navigation';
import PatientMgmt from "../PatientMgmt";
import {
clearLocalStorageUserId,
getDeviceId,
getLocalStorageUserId,
setLocalStorageUserId,
} from '../../drivers/CfSystem';
import ECommercePropertiesTI from "../ECommerce/typings-ti"
import BloodPropertiesTI from '../ECommerce/blood.typings-ti'
import OxygenPropertiesTI from '../ECommerce/oxygen.typings-ti'
import NavigationPropertiesTI, {IdentifyProperties} from '../Navigation/typings-ti'
import CommonTypesTI from '../../core/commonTypes-ti'
import CfSender from "../../core/CfSender";
import CfCore from '../../core/CfCore';
import CfAppStateMonitor from "../../core/CfAppStateMonitor";
import NudgeManager from '../../core/CfNudgeManager';
import CatalogRepository, {ICatalogRepository} from "../../core/repositories/catalog/CatalogRepository";
import {CTA, INudgesRepository} from "../../core/repositories/nudges/typings";
import NudgeRepositoryFactory from "../../core/repositories/nudges/NudgeFactory";
import {CfLogOptions, LogIngestorOptions} from '../../core/typings';
import ImpressionsDetector from "../../core/impressions"
import {
ContentBlock,
IdentityAction,
NavigationTypes,
NudgeAction,
SiteCatalog,
UserCatalog
} from '../Navigation/typings';
import NotificationFactory from "../../drivers/notifications/NotificationFactory";
import {NotificationDispatcher} from "../../drivers/notifications/typings";
import CfLocalStorage from "../../drivers/storage/CfLocalStorage";
import CfNetworkQueue from "../../core/CfNetworkQueue";
import NetworkFactory from "../../drivers/network/CfNetworkFactory";
import {NudgeManagerAction} from "../../core/CfNudgeManager.typings";
import {CfLogEvents, NudgeScreenType} from "../../core/commonTypes";
import CfExceptionHandler from "../../core/CfExceptionHandler";
import isBrowser from "is-in-browser";
import {convertParameterNodes} from "typedoc/dist/lib/converter/factories/signature";
import CallCenter from "../CallCenter";
import EmergencyMgmt from "../EmergencyMgmt";
export default class CfLog extends EventEmitter {
private deviceId
private sender
private cfCore
private cfNetwork
private storageDriver
private networkQueue
private nudgeManager
private notificationsEngine: NotificationDispatcher
private nudgesRepository: INudgesRepository
private catalogRepository: ICatalogRepository
private DEFAULT_BASE_URL = 'https://api.causalfoundry.ai/v1'
private DEFAULT_INGEST_PATH = '/ingest/log'
private DEFAULT_NUDGE_FETCH_PATH = '/nudge/sdk'
private DEFAULT_CATALOG_PATH = '/ingest/catalog'
private DEFAULT_CDN_URL = 'https://cdn.causalfoundry.ai/'
private DEFAULT_FLUSH_INTERVAL = 10000
private DEFAULT_FLUSH_MAX_RETRIES = 10
private DEFAULT_CACHE_EVENTS_KEY = 'cfLog'
private options: CfLogOptions = {
cdnUrl: this.DEFAULT_CDN_URL,
baseUrl: this.DEFAULT_BASE_URL,
allowAnonymousUsers: false,
nudgeFetchPath: this.DEFAULT_NUDGE_FETCH_PATH,
catalogPath: this.DEFAULT_CATALOG_PATH,
activateNudgeMechanism: true,
selfManagedNudges: false,
defaultBlock: ContentBlock.Core,
debug: true,
isUsingAsInternalWrapper : false,
pauseSDK: false
}
public constructor(key: string, options?: Partial<CfLogOptions>) {
super()
this.deviceId = getDeviceId()
if (options) {
this.options = Object.assign(this.options, options)
}
this.cfNetwork = NetworkFactory.getNetworkDriver(key)
this.networkQueue = new CfNetworkQueue(this.cfNetwork)
this.storageDriver = new CfLocalStorage()
const logIngestorDefaultOptions: LogIngestorOptions = {
flushInterval: this.DEFAULT_FLUSH_INTERVAL,
flushMaxRetries: this.DEFAULT_FLUSH_MAX_RETRIES,
ingestPath: this.DEFAULT_INGEST_PATH,
cacheEventsInLocalstorage: true,
cacheEventsKey: this.DEFAULT_CACHE_EVENTS_KEY,
}
const updatedIngestionOptions = {...logIngestorDefaultOptions, ...options}
const logIngestorOptions = {...updatedIngestionOptions, baseUrl: this.options.baseUrl || this.DEFAULT_BASE_URL}
this.sender = new CfSender(this.cfNetwork, logIngestorOptions)
this.cfCore = CfCore.createInstance(
this.sender,
ImpressionsDetector,
this.options.debug,
this.options.defaultBlock,
this.deviceId, this.options.isUsingAsInternalWrapper)
this.nudgesRepository = NudgeRepositoryFactory.getNudgeRepository(
`${this.options.baseUrl}${this.options.nudgeFetchPath}`,
this.cfNetwork,
this.storageDriver
)
this.catalogRepository = new CatalogRepository(
`${this.options.baseUrl}${this.options.catalogPath}`,
this.networkQueue,
{}, this.options.pauseSDK
)
ECommerce.init(this.catalogRepository)
Loyalty.init(this.catalogRepository)
Navigation.init(this.catalogRepository)
PatientMgmt.init(this.catalogRepository)
EmergencyMgmt.init(this.catalogRepository)
CfAppStateMonitor(this)
if(this.options.allowAnonymousUsers && isBrowser && this.deviceId && (getLocalStorageUserId() === '')){
this.fetchNudgesForAnonUsers(this.deviceId)
}
}
/**
* @ignore
*/
private runNudgeManager(userId: string) {
if(this.options.pauseSDK){
return;
}
if (this.nudgeManager && !this.options.allowAnonymousUsers) {
return
}else {
this.nudgeManager = null
}
if (!this.options.activateNudgeMechanism) {
return
}
if (this.options.selfManagedNudges) {
return
}
this.setupNudgeManager(userId, NudgeScreenType.None, false)
}
private fetchNudgesForScreen(userId: string, nudgeScreenType : NudgeScreenType) {
if(this.options.pauseSDK){
return
}
if (this.nudgeManager) {
this.nudgeManager = null
}
if (!this.options.activateNudgeMechanism) {
// console.error("[cfLog-nudge]", "enable activateNudgeMechanism in CfLogOptions")
return
}
if (!this.options.selfManagedNudges) {
// console.error("[cfLog-nudge]", "enable selfManagedNudges in CfLogOptions")
return
}
this.setupNudgeManager(userId, nudgeScreenType, true)
}
private fetchNudgesForAnonUsers(deviceId: string) {
if(this.options.pauseSDK){
return
}
if (this.nudgeManager) {
this.nudgeManager = null
}
this.setupNudgeManager(deviceId, NudgeScreenType.None, true)
}
private setupNudgeManager(userId: string, nudgeScreenType: NudgeScreenType, isOneTimeOnly: boolean){
this.notificationsEngine = NotificationFactory.getNotificationEngine()
this.nudgeManager = new NudgeManager(
userId,
this.notificationsEngine,
this.nudgesRepository,
nudgeScreenType, isOneTimeOnly
)
this.nudgeManager.on(NudgeManagerAction.Action, (callToActionData: CTA) => {
this.emit(CfLogEvents.NudgeAction, callToActionData.type, callToActionData.cta_resource)
})
this.nudgeManager.on(NudgeManagerAction.Open, (id, nudgeTime) => {
Navigation.logPushNotificationEvent({
ref: id,
response: NudgeAction.Open,
time: nudgeTime,
})
})
this.nudgeManager.on(NudgeManagerAction.Discard, (id, nudgeTime) => {
Navigation.logPushNotificationEvent({
ref: id,
response: NudgeAction.Discard,
time: nudgeTime
})
})
this.nudgeManager.on(NudgeManagerAction.Block, (id, nudgeTime) => {
Navigation.logPushNotificationEvent({
ref: id,
response: NudgeAction.Block,
time: nudgeTime
})
})
this.nudgeManager.on(NudgeManagerAction.Shown, (id, nudgeTime) => {
Navigation.logPushNotificationEvent({
ref: id,
response: NudgeAction.Shown,
time: nudgeTime
})
})
}
public flush() {
if(this.options.pauseSDK){
return
}
this.sender.flush()
}
/**
* Call this function whenever the application has information about a session event
* (Register, Login, Logout)
*
* @param {IdentityAction} action
* @param {string} userId
* @param {UserCatalog} userProps
* @param {string} referralCode
*/
public identify(action: IdentityAction, userId: string, userProps? : UserCatalog, referralCode?: string) {
if(this.options.pauseSDK){
return
}
if(userId == ''){
new CfExceptionHandler().throwAndLogError(NavigationTypes.Identify, 'invalid-user-id')
return
}
const { IdentifyProperties: IdentifyPropertiesChecker } = createCheckers(
NavigationPropertiesTI,
BloodPropertiesTI,
ECommercePropertiesTI,
OxygenPropertiesTI,
CommonTypesTI)
const userInfo = {
action: action,
referral_code: referralCode
}
IdentifyPropertiesChecker.check(userInfo)
this.cfCore.login(userId);
if (action === IdentityAction.Logout) {
clearLocalStorageUserId();
} else {
this.runNudgeManager(userId);
setLocalStorageUserId(userId);
if (userProps) {
this.catalogRepository.injectUser(userProps);
}
}
Navigation.logIdentifyEvent({
action: action,
referral_code: referralCode
})
}
public userBlockStatus(isBlocked: boolean, reason: string, remarks?: string,) {
if(this.options.pauseSDK){
return
}
if(isBlocked == undefined){
new CfExceptionHandler().throwAndLogError(NavigationTypes.Identify, 'invalid-block-status')
}else if(reason == ''){
new CfExceptionHandler().throwAndLogError(NavigationTypes.Identify, 'invalid-reason')
}
const userIdentifyObject = {
action: isBlocked? IdentityAction.Blocked : IdentityAction.UnBlocked,
referral_code: "",
blocked: {
reason: reason,
remarks: remarks,
}
}
Navigation.logIdentifyEvent(userIdentifyObject)
}
public updateUserCatalog(userCatalog: UserCatalog) {
if(this.options.pauseSDK){
return
}
this.catalogRepository.injectUser(userCatalog)
}
public updateSiteCatalog(siteCatalog: SiteCatalog) {
if(this.options.pauseSDK){
return
}
console.log("siteHeelo")
this.catalogRepository.injectSite(siteCatalog)
}
/**
* When this SDK is embedded into a web application, which has been already logged
* in another section, there is no need to call `identify` again, because the session
* is already started. Use this function to let the SDK what is the userId, so it is able
* to include in the subsequent events.
*
* An example of a scenario where this is useful is: a native application where
* some section is implemented in HTML/JS with a WebView. In this case, the session
* has already started in the native part, so do not call `identify` within the JS section,
* just call `setUserId`
*
* @param userId the string that represents unambiguously this user
*/
public setUserId(userId: string) {
if(this.options.pauseSDK){
return
}
if(!userId){
new CfExceptionHandler().throwAndLogError(NavigationTypes.Identify, 'invalid-user-id')
return
}
this.cfCore.login(userId)
}
}