UNPKG

@rudderstack/rudder-sdk-react-native

Version:
398 lines (368 loc) 12.2 kB
import { Platform } from 'react-native'; import AsyncLock from 'async-lock'; import { configure } from './RudderConfiguration'; import bridge, { Configuration } from './NativeRudderBridge'; import { logInit, logDebug, logError, logWarn } from './Logger'; import { SDK_VERSION, ENABLE_GZIP } from './Constants'; import IRudderContext from './IRudderContext'; import { filterNaN } from './FilterNaN'; const lock = new AsyncLock(); function validateConfiguration(configuration: Configuration) { if (configuration.controlPlaneUrl && typeof configuration.controlPlaneUrl != 'string') { logWarn("setup : 'controlPlaneUrl' must be a string. Falling back to the default value"); delete configuration.controlPlaneUrl; } if (configuration.flushQueueSize && !Number.isInteger(configuration.flushQueueSize)) { logWarn("setup : 'flushQueueSize' must be an integer. Falling back to the default value"); delete configuration.flushQueueSize; } if (configuration.dbCountThreshold && !Number.isInteger(configuration.dbCountThreshold)) { logWarn("setup : 'dbCountThreshold' must be an integer. Falling back to the default value"); delete configuration.dbCountThreshold; } if (configuration.sleepTimeOut && !Number.isInteger(configuration.sleepTimeOut)) { logWarn("setup : 'sleepTimeOut' must be an integer. Falling back to the default value"); delete configuration.sleepTimeOut; } if (configuration.logLevel && !Number.isInteger(configuration.logLevel)) { logWarn( "setup : 'logLevel' must be an integer. Use RUDDER_LOG_LEVEL to set this value.Falling back to the default value", ); delete configuration.logLevel; } if ( configuration.configRefreshInterval && !Number.isInteger(configuration.configRefreshInterval) ) { logWarn( "setup : 'configRefreshInterval' must be an integer. Falling back to the default value", ); delete configuration.configRefreshInterval; } if ( configuration.trackAppLifecycleEvents && typeof configuration.trackAppLifecycleEvents != 'boolean' ) { logWarn( "setup : 'trackAppLifecycleEvents' must be a boolen. Falling back to the default value", ); delete configuration.trackAppLifecycleEvents; } if (configuration.recordScreenViews && typeof configuration.recordScreenViews != 'boolean') { logWarn("setup : 'recordScreenViews' must be a boolen. Falling back to the default value"); delete configuration.recordScreenViews; } if (configuration.autoCollectAdvertId && typeof configuration.autoCollectAdvertId != 'boolean') { logWarn("setup : 'autoCollectAdvertId' must be a boolen. Falling back to the default value"); delete configuration.autoCollectAdvertId; } if (configuration.autoSessionTracking && typeof configuration.autoSessionTracking != 'boolean') { logWarn("setup : 'autoSessionTracking' must be a boolen. Falling back to the default value"); delete configuration.autoSessionTracking; } if (configuration.sessionTimeout && !Number.isInteger(configuration.sessionTimeout)) { logWarn("setup : 'sessionTimeout' must be an integer. Falling back to the default value"); delete configuration.sessionTimeout; } if ( configuration.enableBackgroundMode && typeof configuration.enableBackgroundMode != 'boolean' ) { logWarn("setup : 'enableBackgroundMode' must be a boolen. Falling back to the default value"); delete configuration.enableBackgroundMode; } if (configuration.collectDeviceId && typeof configuration.collectDeviceId != 'boolean') { logWarn("setup : 'collectDeviceId' must be a boolean. Falling back to the default value"); delete configuration.collectDeviceId; } if ( typeof configuration.enableGzip !== 'undefined' && typeof configuration.enableGzip != 'boolean' ) { logWarn( `setup : 'enableGzip' must be a boolean. Falling back to the default value ${ENABLE_GZIP}`, ); delete configuration.enableGzip; } } // setup the RudderSDK with writeKey and Config. async function setup( writeKey: string, configuration: Configuration = {}, options: Record<string, unknown> | null = null, ) { if (writeKey == undefined || typeof writeKey != 'string' || writeKey == '') { logError('setup: writeKey is incorrect. Aborting'); return; } if ( !configuration.dataPlaneUrl || typeof configuration.dataPlaneUrl != 'string' || configuration.dataPlaneUrl! == '' ) { logError('setup: dataPlaneUrl is incorrect. Aborting'); return; } // init log level if (configuration.logLevel && Number.isInteger(configuration.logLevel)) { logInit(configuration.logLevel); } logDebug(`Initializing Rudder RN SDK version: ${SDK_VERSION}`); validateConfiguration(configuration); // Acquire a lock before calling the setup of Native Modules await lock.acquire('lock', async function (done) { const config = await configure(writeKey, configuration); logDebug('setup: created config'); await bridge.setup(config as Record<string, unknown>, options); logDebug('setup: setup completed'); done(); }); } // wrapper for `track` method async function track( event: string, properties: Record<string, unknown> | null = null, options: Record<string, unknown> | null = null, ) { if (event == undefined) { logWarn("track: Mandatory field 'event' missing"); return; } if (typeof event != 'string') { logWarn("track: 'event' must be a string"); return; } bridge.track(event, filterNaN(properties), filterNaN(options)); } // wrapper for `screen` method async function screen( name: string, properties: Record<string, unknown> | null = null, options: Record<string, unknown> | null = null, ) { if (name == undefined) { logWarn("screen: Mandatory field 'name' missing"); return; } if (typeof name != 'string') { logWarn("screen: 'name' must be a string"); return; } bridge.screen(name, filterNaN(properties), filterNaN(options)); } // wrapper for `identify` method async function identify( userId: string, traits: Record<string, unknown>, options: Record<string, unknown>, ): Promise<void>; async function identify( traits: Record<string, unknown>, options: Record<string, unknown>, ): Promise<void>; async function identify( userIdOrTraits: string | Record<string, unknown>, traitsOrOptions: Record<string, unknown> | null = null, options: Record<string, unknown> | null = null, ) { if (userIdOrTraits == undefined) { logWarn('identify: atleast one of userId or traits is required'); return; } let _userId; let _traits; let _options; if (typeof userIdOrTraits == 'string') { // userIdOrTraits contains userId _userId = userIdOrTraits; _traits = traitsOrOptions; _options = options; } else if (typeof userIdOrTraits == 'object') { // userIdOrTraits contains traits _userId = ''; _traits = userIdOrTraits; _options = traitsOrOptions; } else { logWarn('identify : Unsupported argument type passed to identify'); return; } bridge.identify(_userId, filterNaN(_traits), filterNaN(_options)); } // wrapper for `group` method async function group( groupId: string, traits: Record<string, unknown> | null = null, options: Record<string, unknown> | null = null, ) { if (groupId == undefined) { logWarn("group: Mandatory field 'groupId' missing"); return; } if (typeof groupId != 'string') { logWarn("group: 'groupId' must be a string"); return; } bridge.group(groupId, filterNaN(traits), filterNaN(options)); } // wrapper for `alias` method async function alias(newId: string, options?: Record<string, unknown> | null): Promise<void>; async function alias( newId: string, previousId: string, options?: Record<string, unknown> | null, ): Promise<void>; async function alias( newId: string, previousIdOrOptions: string | Record<string, unknown> | null = null, options: Record<string, unknown> | undefined | null = null, ): Promise<void> { // Validate newId if (!newId) { logWarn("alias: Mandatory field 'newId' is missing"); return Promise.resolve(); } if (typeof newId !== 'string') { logWarn("alias: 'newId' must be a string"); return Promise.resolve(); } // Handle cases based on the type of previousIdOrOptions if (typeof previousIdOrOptions === 'string') { return bridge.alias(newId, previousIdOrOptions, filterNaN(options)); } if ( previousIdOrOptions && typeof previousIdOrOptions === 'object' && !Array.isArray(previousIdOrOptions) ) { return bridge.alias(newId, null, filterNaN(previousIdOrOptions)); } return bridge.alias(newId, null, filterNaN(options)); } async function putDeviceToken(token: string): Promise<void>; /** * @deprecated use putDeviceToken{@link putDeviceToken(token: string)} instead */ async function putDeviceToken(androidToken: string, iOSToken: string): Promise<void>; async function putDeviceToken(token: string, iOSToken: string | null = null): Promise<void> { if (Platform.OS == 'ios' && iOSToken) { bridge.putDeviceToken(iOSToken); } else if (token) { bridge.putDeviceToken(token); } } /** * @deprecated use putAdvertisingId{@link putAdvertisingId(advertisingId: string)} instead */ async function setAdvertisingId(androidId: string, iOSId: string) { switch (Platform.OS) { case 'ios': if (iOSId) { putAdvertisingId(iOSId); } break; case 'android': if (androidId) { putAdvertisingId(androidId); } break; } } async function putAdvertisingId(advertisingId: string) { if (advertisingId) { bridge.putAdvertisingId(advertisingId); } } async function clearAdvertisingId() { bridge.clearAdvertisingId(); } /** * @deprecated use putAnonymousId{@link putAnonymousId(anonymousId: string)} instead */ async function setAnonymousId(anonymousId: string) { if (anonymousId) { putAnonymousId(anonymousId); } } async function putAnonymousId(anonymousId: string) { if (anonymousId) { bridge.putAnonymousId(anonymousId); } } async function reset(clearAnonymousId = false) { const clearAnonymousIdVal = clearAnonymousId === true; if (typeof clearAnonymousId !== 'boolean') { logWarn("reset: 'clearAnonymousId' must be a boolean"); } bridge.reset(clearAnonymousIdVal); } async function flush() { bridge.flush(); } async function optOut(optOut: boolean) { const optOutVal = optOut === true; if (typeof optOut !== 'boolean') { logWarn("optOut: 'optOut' must be a boolean"); } bridge.optOut(optOutVal); } // eslint-disable-next-line @typescript-eslint/ban-types async function registerCallback(name: string, callback: (data: unknown) => void) { if (name) { bridge.registerCallback(name, callback); } } async function getRudderContext(): Promise<IRudderContext | null> { const context: IRudderContext | null = await bridge.getRudderContext(); return context ?? null; } async function startSession(sessionId?: number): Promise<void> { if (sessionId === undefined) { bridge.startSession(''); } else if (!Number.isInteger(sessionId)) { logWarn("startSession: 'sessionId' must be an integer"); } else { if (sessionId.toString().length < 10) { logWarn("startSession: 'sessionId' length should be at least 10, hence ignoring it"); return; } bridge.startSession(sessionId.toString()); } } async function endSession() { bridge.endSession(); } async function getSessionId(): Promise<number | null> { try { const sessionId: number | null = await bridge.getSessionId(); if (sessionId === null || sessionId === undefined) { return null; } return Number(sessionId); } catch (e) { logError('getSessionId: Failed to get sessionId: ' + e); return null; } } const rudderClient = { setup, track, screen, identify, group, alias, reset, flush, optOut, putDeviceToken, putAdvertisingId, setAdvertisingId, clearAdvertisingId, putAnonymousId, setAnonymousId, registerCallback, getRudderContext, startSession, endSession, getSessionId, }; export default rudderClient;