import { Exponea } from './ExponeaImpl'; import type { InAppMessageCallbackImpl } from './ExponeaListeners'; import { SegmentationDataCallback } from './ExponeaListeners'; import { FlushMode, LogLevel } from './NativeExponea'; import type { OpenedPush, InAppMessage, InAppMessageButton, Segment, Consent, ConsentSources, Recommendation, RecommendationOptions, AppInboxMessage, AppInboxAction, AppInboxStyle, JsonObject, ExponeaProject, PushAction, InAppMessageAction, InAppMessageActionType, InAppContentBlock, InAppContentBlockAction, } from './NativeExponea'; import EventType from './EventType'; import type Configuration from './Configuration'; import type { IntegrationConfig, ProjectConfig } from './Configuration'; import type { CustomerIdentity } from './CustomerIdentity'; import type { SdkAuthError } from './SdkAuthError'; import { SdkAuthErrorCode } from './SdkAuthError'; // Export components export { default as AppInboxButton } from './AppInboxButton'; export { default as InAppContentBlocksPlaceholder } from './InAppContentBlocksPlaceholder'; export { default as ContentBlockCarouselView } from './ContentBlockCarouselView'; export type { AppInboxButtonProps } from './AppInboxButton'; export type { InAppContentBlocksPlaceholderProps } from './InAppContentBlocksPlaceholder'; export type { ContentBlockCarouselViewProps } from './ContentBlockCarouselView'; // Export types export type { OpenedPush, InAppMessage, InAppMessageButton, Segment, Consent, ConsentSources, Recommendation, RecommendationOptions, AppInboxMessage, AppInboxAction, AppInboxStyle, JsonObject, ExponeaProject, PushAction, InAppMessageAction, InAppMessageActionType, InAppContentBlock, InAppContentBlockAction, InAppMessageCallbackImpl as InAppMessageCallback, CustomerIdentity, SdkAuthError, }; export type { ProjectConfig, StreamConfig, IntegrationConfig, } from './Configuration'; export { FlushMode, LogLevel, EventType, SegmentationDataCallback, SdkAuthErrorCode, }; export { PushTokenTrackingFrequency, PushNotificationImportance, HttpLoggingLevel, } from './Configuration'; // Interface C: Combines A (Turbo Module) and B (Listeners) /** * # Exponea React Native SDK - Architectural Design * * ## Two-Interface Architecture * * This SDK implements a sophisticated two-interface pattern to handle the technical * limitations of React Native's code generation while providing a unified public API. * * ### Interface A: TurboModule Methods * * These are methods that communicate with native code using React Native's TurboModule * architecture. They are defined in `NativeExponea.ts` and can be auto-generated by * React Native's codegen because they use only codegen-supported types. * * **Characteristics:** * - Extend `TurboModule` from React Native * - Return `Promise` for async operations or primitive types * - Use only codegen-compatible types: `string`, `number`, `boolean`, `Object` * - Use `Readonly<{ [key: string]: Type }>` for object parameters * - Follow request-response communication pattern (JS → Native → Response) * * **Examples:** * ```typescript * await Exponea.configure(config); // Promise * const cookie = await Exponea.getCustomerCookie(); // Promise * await Exponea.trackEvent('event_name', {}); // Promise * ``` * * **Why these work with codegen:** * - Simple type signatures that can be serialized across the bridge * - No function callbacks (only return values) * - No complex nested optional properties * - No class-based types * * ### Interface B: Listener Methods * * These methods handle event-driven communication from native code to JavaScript. * They are implemented in `ExponeaListeners.ts` and **cannot** be generated by * codegen because they require functionality that codegen doesn't support. * * **Characteristics:** * - Use `NativeEventEmitter` for native → JS communication * - Store callback references in JavaScript-side variables * - Handle event streaming (continuous events, not single responses) * - Use complex callback types with optional methods * - Implement stateful lifecycle management (set/remove) * * **Examples:** * ```typescript * // Set up event listener * Exponea.setPushOpenedListener((openedPush) => { * console.log('Push opened:', openedPush); * }); * * // Native sends events whenever they occur * // Native → NativeEventEmitter → JavaScript callback * * // Clean up when done * Exponea.removePushOpenedListener(); * ``` * * **Why these cannot use codegen:** * - Callbacks are functions stored in JavaScript memory, not serialized data * - Event emitter pattern requires bidirectional communication * - Callback types like `InAppMessageCallbackImpl` have optional nested functions * - Stateful management requires storing references outside the module * - Codegen only supports request-response, not event streaming * * ### Codegen Type Limitations * * React Native's codegen has strict type requirements for cross-platform compatibility: * * **✅ Supported by codegen:** * - Primitive types: `string`, `number`, `boolean` * - Generic `Object` type * - `Promise` for async operations * - Simple arrays: `Array` * - `Readonly<{ [key: string]: Type }>` for read-only objects * * **❌ Not supported by codegen:** * - Function types as parameters: `(param: Type) => void` * - Optional method signatures: `method?: () => void` * - Classes with state * - Complex nested optional properties * - Index signatures on regular interfaces (see NativeExponea.ts:43-44) * - Event emitter patterns * * ### How The Interfaces Combine * * The `ExponeaType` interface (this interface) combines both patterns seamlessly: * * ```typescript * export interface ExponeaType { * // Interface A: TurboModule methods * configure(configMap: Object): Promise; * trackEvent(eventName: string, properties: Object): Promise; * * // Interface B: Listener methods * setPushOpenedListener(listener: (openedPush: OpenedPush) => void): void; * registerSegmentationDataCallback(callback: SegmentationDataCallback): void; * } * ``` * * The implementation (`ExponeaImpl.ts`) delegates to the appropriate subsystem: * - Interface A methods → `NativeExponea` (TurboModule) * - Interface B methods → `ExponeaListeners` (JavaScript event handlers) * * ### Communication Patterns Comparison * * | Aspect | Interface A (TurboModule) | Interface B (Listeners) | * |--------|--------------------------|-------------------------| * | Direction | JavaScript → Native | Native → JavaScript | * | Pattern | Request-response | Event streaming | * | Data Flow | Bridge serialization | NativeEventEmitter | * | Type System | Codegen-compatible | Custom (non-codegen) | * | State | Stateless | Stateful (stores callbacks) | * | Return Type | `Promise` or primitive | `void` | * | Use Case | Method calls, data queries | Event notifications, callbacks | * * ### Developer Guidance * * **Use Interface A (TurboModule methods) when:** * - You need to send data to native code * - You want to query native state * - You're making a one-time request * - You need a return value (Promise) * * **Use Interface B (Listener methods) when:** * - You want to receive events from native code * - Native code needs to notify your app of state changes * - You need continuous event updates (not just one response) * - The event timing is unpredictable (push notifications, user actions) * * @see {@link ./NativeExponea.ts} for Interface A (TurboModule) definitions * @see {@link ./ExponeaListeners.ts} for Interface B (Listener) implementations * @see {@link ./ExponeaImpl.ts} for the delegation pattern implementation * * @remarks * This architectural pattern allows the SDK to leverage React Native's modern * TurboModule performance for request-response operations while maintaining * sophisticated event-driven patterns for asynchronous notifications. * * @public */ export interface ExponeaType { // ============================================================================ // Interface A: TurboModule Methods // ============================================================================ // These methods use React Native's TurboModule architecture for direct // native communication. They are defined in NativeExponea.ts and support // only codegen-compatible types. See architectural documentation above. // Configuration /** Configures Exponea SDK. Should only be called once. You need to configure ExponeaSDK before calling most methods. * Optionally accepts a `CustomerIdentity` so initial customer IDs and Stream JWT can be applied during init. */ configure( configuration: Configuration, customerIdentity?: CustomerIdentity ): Promise; isConfigured(): Promise; // Customer /** Resolves to cookie of the current customer */ getCustomerCookie(): Promise; /** * Identifies current customer with new customer ids and properties. * @deprecated Use `identifyCustomer(customerIdentity, properties?)` instead. */ identifyCustomer( customerIds: Record, properties: JsonObject ): Promise; /** * Identifies current customer using a `CustomerIdentity` (customer IDs + * optional Stream JWT). `properties` is optional and defaults to an empty map. */ identifyCustomer( customerIdentity: CustomerIdentity, properties?: JsonObject ): Promise; /** * Anonymizes current customer and creates a new one. Push token is cleared on Exponea backend. * Optionally changes default Exponea project and event routing. * @deprecated Use `anonymize(integrationConfig?, integrationRouteMap?)` instead. */ anonymize( exponeaProject: ExponeaProject, projectMapping?: { [key in EventType]?: Array } ): Promise; /** * Anonymizes the current customer and creates a new anonymous one. * The push token is cleared on the Exponea backend. * * Optionally switches the default configuration integration to a different * `ProjectConfig` or `StreamConfig`, and overrides the per-event-type * project routing map. * * Calling `anonymize()` with no arguments keeps the existing integration * configuration and simply resets the customer identity. * * @param integrationConfig - Optional new integration to use after anonymization. * Pass a `ProjectConfig` for a standard project or a `StreamConfig` for a * stream-based integration. If omitted, the current integration is retained. * @param integrationRouteMap - Optional per-event-type routing overrides. * Only applicable when `integrationConfig` is a `ProjectConfig`; ignored * for `StreamConfig`. */ anonymize( integrationConfig?: IntegrationConfig, integrationRouteMap?: { [key in EventType]?: Array; } ): Promise; /** Sets a Stream JWT auth token. Only effective with StreamConfig integrations. */ setSdkAuthToken(token: string): Promise; // Properties /** Get default properties tracked with every event */ getDefaultProperties(): Promise; /** Set default properties tracked with every event. * Only use for reconfiguration, preferred way of setting default properties is configuration object. */ setDefaultProperties(properties: JsonObject): Promise; // Tracking /** Tracks custom event to Exponea backend */ trackEvent( eventName: string, properties: JsonObject, timestamp?: number ): Promise; /** Manually tracks session start. Only usable when automaticSessionTracking is disabled in Configuration */ trackSessionStart(timestamp?: number): Promise; /** Manually tracks session end. Only usable when automaticSessionTracking is disabled in Configuration */ trackSessionEnd(timestamp?: number): Promise; // Consents & Recommendations /** Fetches consents for the current customer */ fetchConsents(): Promise>; /** Fetches recommendations based on RecommendationOptions */ fetchRecommendations( options: RecommendationOptions ): Promise>; // Push Authorization /** * Requests authorization and subsequently registers for receiving notifications for both Android and iOS platform */ requestPushAuthorization(): Promise; /** * Requests authorization and subsequently registers for receiving notifications for iOS platform * @deprecated use `requestPushAuthorization` instead */ requestIosPushAuthorization(): Promise; // Configuration Methods /** Sets whether automatic session tracking is enabled */ setAutomaticSessionTracking(enabled: boolean): Promise; /** Sets session timeout in seconds */ setSessionTimeout(timeout: number): Promise; /** Sets whether automatic push notification tracking is enabled */ setAutoPushNotification(enabled: boolean): Promise; /** Sets campaign TTL in seconds */ setCampaignTTL(seconds: number): Promise; // Push Tokens /** Manually tracks push notification token to Exponea */ trackPushToken(token: string): Promise; /** Manually tracks HMS push notification token to Exponea (Huawei Mobile Services) */ trackHmsPushToken(token: string): Promise; // App Inbox (8 methods) /** Sets App Inbox provider with custom styling */ setAppInboxProvider(withStyle: AppInboxStyle): Promise; /** Tracks App Inbox message opened event (respects tracking consent) */ trackAppInboxOpened(message: AppInboxMessage): Promise; /** Tracks App Inbox message opened event (ignores tracking consent) */ trackAppInboxOpenedWithoutTrackingConsent( message: AppInboxMessage ): Promise; /** Tracks App Inbox message click event (respects tracking consent) */ trackAppInboxClick( action: AppInboxAction, message: AppInboxMessage ): Promise; /** Tracks App Inbox message click event (ignores tracking consent) */ trackAppInboxClickWithoutTrackingConsent( action: AppInboxAction, message: AppInboxMessage ): Promise; /** Marks App Inbox message as read */ markAppInboxAsRead(message: AppInboxMessage): Promise; /** Fetches all App Inbox messages for the current customer */ fetchAppInbox(): Promise>; /** Fetches a specific App Inbox message by ID */ fetchAppInboxItem(messageId: string): Promise; // Push Tracking (6 methods) /** Tracks push notification delivery event (respects tracking consent) */ trackDeliveredPush(params: Record): Promise; /** Tracks push notification delivery event (ignores tracking consent) */ trackDeliveredPushWithoutTrackingConsent( params: Record ): Promise; /** Tracks push notification click event (respects tracking consent) */ trackClickedPush(params: Record): Promise; /** Tracks push notification click event (ignores tracking consent) */ trackClickedPushWithoutTrackingConsent( params: Record ): Promise; /** Tracks payment event */ trackPaymentEvent(params: Record): Promise; /** Checks if notification payload belongs to Exponea */ isExponeaPushNotification(params: Record): Promise; // InApp Message Tracking (4 methods) /** Tracks in-app message click event (respects tracking consent) */ trackInAppMessageClick( message: InAppMessage, buttonText: string | null | undefined, buttonUrl: string | null | undefined ): Promise; /** Tracks in-app message click event (ignores tracking consent) */ trackInAppMessageClickWithoutTrackingConsent( message: InAppMessage, buttonText: string | null | undefined, buttonUrl: string | null | undefined ): Promise; /** Tracks in-app message close event (respects tracking consent) */ trackInAppMessageClose( message: InAppMessage, buttonText: string | null | undefined, interaction: boolean ): Promise; /** Tracks in-app message close event (ignores tracking consent) */ trackInAppMessageCloseWithoutTrackingConsent( message: InAppMessage, buttonText: string | null | undefined, interaction: boolean ): Promise; // InApp Content Block Tracking (8 methods) /** Tracks in-app content block click event (respects tracking consent) */ trackInAppContentBlockClick(params: Record): Promise; /** Tracks in-app content block click event (ignores tracking consent) */ trackInAppContentBlockClickWithoutTrackingConsent( params: Record ): Promise; /** Tracks in-app content block close event (respects tracking consent) */ trackInAppContentBlockClose(params: Record): Promise; /** Tracks in-app content block close event (ignores tracking consent) */ trackInAppContentBlockCloseWithoutTrackingConsent( params: Record ): Promise; /** Tracks in-app content block shown event (respects tracking consent) */ trackInAppContentBlockShown(params: Record): Promise; /** Tracks in-app content block shown event (ignores tracking consent) */ trackInAppContentBlockShownWithoutTrackingConsent( params: Record ): Promise; /** Tracks in-app content block error event (respects tracking consent) */ trackInAppContentBlockError(params: Record): Promise; /** Tracks in-app content block error event (ignores tracking consent) */ trackInAppContentBlockErrorWithoutTrackingConsent( params: Record ): Promise; // Segmentation & Integration (3 methods) /** Fetches customer segments for the given category */ getSegments( exposingCategory: string, force?: boolean ): Promise>; /** Stops all SDK tracking and integration */ stopIntegration(): Promise; /** Clears all local customer data from device storage */ clearLocalCustomerData(appGroup?: string): Promise; // Flushing /** Enable automatic push notification diagnostics *before* configuring the SDK to help you with push notification integration */ checkPushSetup(): Promise; /** Resolves to current FlushMode used by the SDK */ getFlushMode(): Promise; /** Sets the Flush mode of the SDK */ setFlushMode(flushMode: FlushMode): Promise; /** Gets the period with which events are tracked to Exponea backend. Only valid in PERIOD FlushMode */ getFlushPeriod(): Promise; /** Sets the period with which events are tracked to Exponea backend. Only valid in PERIOD FlushMode */ setFlushPeriod(period: number): Promise; /** Resolves to current LogLevel native SDK uses. */ getLogLevel(): Promise; /** Sets LogLevel for native SDK. */ setLogLevel(level: LogLevel): Promise; /** Flushes data to Exponea backend. Only usable in MANUAL FlushMode */ flushData(): Promise; // ============================================================================ // Interface B: Listener Methods // ============================================================================ // These methods use NativeEventEmitter for event-driven communication from // native to JavaScript. They are implemented in ExponeaListeners.ts and // support callback functions and stateful management. See architectural // documentation above for why these cannot use codegen. /** * Sets a listener to handle push notification opened events. * @see ExponeaListeners.setPushOpenedListener */ setPushOpenedListener(listener: (openedPush: OpenedPush) => void): void; /** * Removes the push notification opened event listener. * @see ExponeaListeners.removePushOpenedListener */ removePushOpenedListener(): void; /** * Sets a listener to handle push notification received events. * @see ExponeaListeners.setPushReceivedListener */ setPushReceivedListener(listener: (data: JsonObject) => void): void; /** * Removes the push notification received event listener. * @see ExponeaListeners.removePushReceivedListener */ removePushReceivedListener(): void; /** * Sets a callback handler for in-app message lifecycle events. * @see ExponeaListeners.setInAppMessageCallback */ setInAppMessageCallback(callback: InAppMessageCallbackImpl): void; /** * Removes the in-app message callback handler. * @see ExponeaListeners.removeInAppMessageCallback */ removeInAppMessageCallback(): void; /** * Registers a callback to receive customer segmentation data updates. * @see ExponeaListeners.registerSegmentationDataCallback */ registerSegmentationDataCallback(callback: SegmentationDataCallback): void; /** * Unregisters a previously registered segmentation data callback. * @see ExponeaListeners.unregisterSegmentationDataCallback */ unregisterSegmentationDataCallback(callback: SegmentationDataCallback): void; /** * Registers a callback called when the native SDK reports an auth-token error. * @see ExponeaListeners.setSdkAuthErrorCallback */ setSdkAuthErrorCallback(callback: (error: SdkAuthError) => void): void; /** * Removes the previously registered auth callback handler. * @see ExponeaListeners.removeSdkAuthErrorCallback */ removeSdkAuthErrorCallback(): void; } // Default export for backward compatibility export default Exponea; // Named exports for modern usage export const configure = Exponea.configure; export const isConfigured = Exponea.isConfigured; export const getCustomerCookie = Exponea.getCustomerCookie; export const identifyCustomer = Exponea.identifyCustomer; export const anonymize = Exponea.anonymize; export const setSdkAuthToken = Exponea.setSdkAuthToken; export const getDefaultProperties = Exponea.getDefaultProperties; export const setDefaultProperties = Exponea.setDefaultProperties; export const trackEvent = Exponea.trackEvent; export const trackSessionStart = Exponea.trackSessionStart; export const trackSessionEnd = Exponea.trackSessionEnd; export const fetchConsents = Exponea.fetchConsents; export const fetchRecommendations = Exponea.fetchRecommendations; export const requestPushAuthorization = Exponea.requestPushAuthorization; export const requestIosPushAuthorization = Exponea.requestIosPushAuthorization; export const setAutomaticSessionTracking = Exponea.setAutomaticSessionTracking; export const setSessionTimeout = Exponea.setSessionTimeout; export const setAutoPushNotification = Exponea.setAutoPushNotification; export const setCampaignTTL = Exponea.setCampaignTTL; export const trackPushToken = Exponea.trackPushToken; export const trackHmsPushToken = Exponea.trackHmsPushToken; export const setAppInboxProvider = Exponea.setAppInboxProvider; export const trackAppInboxOpened = Exponea.trackAppInboxOpened; export const trackAppInboxOpenedWithoutTrackingConsent = Exponea.trackAppInboxOpenedWithoutTrackingConsent; export const trackAppInboxClick = Exponea.trackAppInboxClick; export const trackAppInboxClickWithoutTrackingConsent = Exponea.trackAppInboxClickWithoutTrackingConsent; export const markAppInboxAsRead = Exponea.markAppInboxAsRead; export const fetchAppInbox = Exponea.fetchAppInbox; export const fetchAppInboxItem = Exponea.fetchAppInboxItem; export const trackDeliveredPush = Exponea.trackDeliveredPush; export const trackDeliveredPushWithoutTrackingConsent = Exponea.trackDeliveredPushWithoutTrackingConsent; export const trackClickedPush = Exponea.trackClickedPush; export const trackClickedPushWithoutTrackingConsent = Exponea.trackClickedPushWithoutTrackingConsent; export const trackPaymentEvent = Exponea.trackPaymentEvent; export const isExponeaPushNotification = Exponea.isExponeaPushNotification; export const trackInAppMessageClick = Exponea.trackInAppMessageClick; export const trackInAppMessageClickWithoutTrackingConsent = Exponea.trackInAppMessageClickWithoutTrackingConsent; export const trackInAppMessageClose = Exponea.trackInAppMessageClose; export const trackInAppMessageCloseWithoutTrackingConsent = Exponea.trackInAppMessageCloseWithoutTrackingConsent; export const trackInAppContentBlockClick = Exponea.trackInAppContentBlockClick; export const trackInAppContentBlockClickWithoutTrackingConsent = Exponea.trackInAppContentBlockClickWithoutTrackingConsent; export const trackInAppContentBlockClose = Exponea.trackInAppContentBlockClose; export const trackInAppContentBlockCloseWithoutTrackingConsent = Exponea.trackInAppContentBlockCloseWithoutTrackingConsent; export const trackInAppContentBlockShown = Exponea.trackInAppContentBlockShown; export const trackInAppContentBlockShownWithoutTrackingConsent = Exponea.trackInAppContentBlockShownWithoutTrackingConsent; export const trackInAppContentBlockError = Exponea.trackInAppContentBlockError; export const trackInAppContentBlockErrorWithoutTrackingConsent = Exponea.trackInAppContentBlockErrorWithoutTrackingConsent; export const getSegments = Exponea.getSegments; export const stopIntegration = Exponea.stopIntegration; export const clearLocalCustomerData = Exponea.clearLocalCustomerData; export const checkPushSetup = Exponea.checkPushSetup; export const getFlushMode = Exponea.getFlushMode; export const setFlushMode = Exponea.setFlushMode; export const getFlushPeriod = Exponea.getFlushPeriod; export const setFlushPeriod = Exponea.setFlushPeriod; export const getLogLevel = Exponea.getLogLevel; export const setLogLevel = Exponea.setLogLevel; export const flushData = Exponea.flushData; export const setPushOpenedListener = Exponea.setPushOpenedListener; export const removePushOpenedListener = Exponea.removePushOpenedListener; export const setPushReceivedListener = Exponea.setPushReceivedListener; export const removePushReceivedListener = Exponea.removePushReceivedListener; export const setInAppMessageCallback = Exponea.setInAppMessageCallback; export const removeInAppMessageCallback = Exponea.removeInAppMessageCallback; export const registerSegmentationDataCallback = Exponea.registerSegmentationDataCallback; export const unregisterSegmentationDataCallback = Exponea.unregisterSegmentationDataCallback; export const setSdkAuthErrorCallback = Exponea.setSdkAuthErrorCallback; export const removeSdkAuthErrorCallback = Exponea.removeSdkAuthErrorCallback;