@convivainc/conviva-react-native-appanalytics
Version:
Conviva React Native Application Analytics Library
1,476 lines (1,466 loc) • 54.3 kB
TypeScript
import * as React$1 from 'react';
/** Which JS capture path produced a given error event. */
type ErrorSource = 'globalHandler' | 'unhandledRejection' | 'errorBoundary' | 'manual';
/**
* Severity of the error — the primary bucketing dimension for dashboards and
* backend queries. Mirrors Sentry's `level` and Bugsnag's `severity`.
*/
type ErrorSeverity = 'fatal' | 'error' | 'warning' | 'info';
/** Active JS engine at runtime. Determines which symbolication pipeline applies. */
type JsEngine = 'hermes' | 'jsc' | 'unknown';
/** The complete payload sent across the native bridge for every JS error event. */
interface JsErrorPayload {
/** Epoch milliseconds captured at the moment _dispatch() is called. */
timestamp: number;
/** Human-readable error message. Truncated to MAX_MESSAGE_LENGTH in _dispatch(). */
message: string;
/** error.name — e.g. "TypeError", "ReferenceError", "UnhandledRejection". */
errorType: string;
/** JS stack trace string. Truncated to MAX_STACK_TRACE_LENGTH in _dispatch(). */
stackTrace: string;
/** true only when the error is fatal / app-terminating. */
isFatal: boolean;
/**
* true → caught intentionally (ErrorBoundary, try/catch + trackError).
* false → uncaught (global handler, unhandled promise rejection).
*/
isHandled: boolean;
/** Which JS capture path produced this event. */
errorSource: ErrorSource;
/** Severity of the error — primary dashboard bucketing dimension. */
severity: ErrorSeverity;
/** React component tree to the failing component. Only for errorBoundary. */
componentStack?: string;
/** Line number extracted from the first frame of the stack trace. */
lineNumber?: number;
/** Column number extracted from the first frame of the stack trace. */
lineColumn?: number;
/** Source file name extracted from the first frame of the stack trace. */
fileName?: string;
/**
* SHA-256 hash of the compiled JS bundle, injected at build time.
* Required when backend symbolication is enabled AND the app uses OTA updates.
*/
bundleId?: string;
/** Active JS engine at capture time. */
jsEngine: JsEngine;
/** System-injected + consumer-defined attributes attached at capture time. */
attributes?: Record<string, string | number | boolean>;
}
/** Bridge adapter interface — swap for a mock in tests. */
interface BridgeAdapter {
isAvailable(): boolean;
reportJsError(payload: JsErrorPayload): void;
}
/**
* Internal configuration for the error tracking module.
* NOT directly exposed to consumers — the existing ConvivaTracker.init() config
* schema is extended with error tracking fields, and the existing init flow
* constructs this internal config.
*/
interface ErrorTrackingInternalConfig {
enabled: boolean;
captureGlobalErrors: boolean;
captureUnhandledRejections: boolean;
suppressInDev: boolean;
enableRateLimiting: boolean;
maxEventsPerWindow: number;
rateLimitWindowMs: number;
/** Circuit-breaker cooldown duration in ms after rate limit is exceeded. */
disconnectDurationMs: number;
/**
* When true, unhandled promise rejections are reported with isHandled:true
* and severity:'warning' instead of isHandled:false + severity:'error'.
* Mirrors Bugsnag's reportUnhandledPromiseRejectionsAsHandled option.
*/
promiseRejectionsAsHandled: boolean;
/**
* Consumer-supplied hook. Return false to suppress. Mutate payload to enrich.
* If this throws, the error is captured anyway (fail-open per D8).
* Filtered events (returning false) do NOT consume a rate-limit token.
*/
beforeCapture?: (payload: JsErrorPayload) => boolean | void;
/**
* Optional JS bundle hash override for OTA apps not using the Metro plugin.
*/
bundleId?: string;
/** Injected bridge adapter. Production default: NativeBridgeAdapter. */
bridgeAdapter?: BridgeAdapter;
}
/**
* Consumer-facing configuration exposed through TrackerControllerConfiguration.
* Every field is optional — defaults are applied by _initFromTracker in the
* error tracker singleton.
*/
interface ErrorTrackingConfiguration {
enabled?: boolean;
captureGlobalErrors?: boolean;
captureUnhandledRejections?: boolean;
suppressInDev?: boolean;
enableRateLimiting?: boolean;
/** Default: 20 (matching Conviva JS horizontal tracker). */
maxEventsPerWindow?: number;
/** Default: 1 000 ms (1-second window). */
rateLimitWindowMs?: number;
/** Circuit-breaker cooldown after limit hit. Default: 2 000 ms. */
disconnectDurationMs?: number;
/** Default: false. See Bugsnag reportUnhandledPromiseRejectionsAsHandled. */
promiseRejectionsAsHandled?: boolean;
/** JS bundle hash for source map lookup in Conviva's symbolication service. */
bundleId?: string;
beforeCapture?: (payload: JsErrorPayload) => boolean | void;
/** @internal — test injection point */
bridgeAdapter?: BridgeAdapter;
}
/**
* HttpMethod type
*/
type HttpMethod = 'post' | 'get';
/**
* DevicePlatform type
*/
type DevicePlatform = 'web' | 'mob' | 'pc' | 'srv' | 'app' | 'tv' | 'cnsl' | 'iot';
/**
* LogLevel type
*/
type LogLevel = 'off' | 'error' | 'debug' | 'verbose';
/**
* BasisForProsessing
*/
type Basis = 'consent' | 'contract' | 'legal_obligation' | 'legitimate_interests' | 'public_task' | 'vital_interests';
/**
* BufferOption
*/
type BufferOption = 'single' | 'default' | 'large';
/**
* Trigger for MessageNotification event
*/
type Trigger = 'push' | 'location' | 'calendar' | 'timeInterval' | 'other';
/**
* ScreenSize
*/
type ScreenSize = [number, number];
/**
* SelfDescribing type
*/
type SelfDescribing<T extends Record<keyof T, unknown> = Record<string, unknown>> = {
/**
* Schema
*/
schema: string;
/**
* Data
*/
data: T;
};
/**
* EventContext type
*/
type EventContext = SelfDescribing;
/**
* NetworkConfiguration
*/
interface NetworkConfiguration {
/**
* The collector endpoint
* - if the protocol is not included it defaults to https
*/
endpoint: string;
/**
* The Http Method to use when sending events to the collector
* @defaultValue 'post'
*/
method?: HttpMethod;
/**
* A custom path which will be added to the endpoint URL to specify the
* complete URL of the collector when paired with the POST method.
*
* @defaultValue `com.snowplowanalytics.snowplow/tp2`.
*/
customPostPath?: string;
/**
* Custom headers for HTTP requests to the Collector.
*/
requestHeaders?: Record<string, string>;
}
interface TraceparentConfiguration {
force: Boolean;
enabled: Boolean;
targetUrl: string[];
}
/**
* ClidSyncConfiguration
*
* Mirrors the remote-config clid_sync JSON structure.
* App-supplied domains under webViewCookie.domains are used immediately as fallback;
* remote config replaces them once received.
* Note: webViewCookie.en and webViewBridge.en are controlled by remote config only and
* are ignored when supplied here.
*/
interface ClidSyncConfiguration {
webViewCookie?: {
enabled?: boolean;
/**
* List of cookie domains to receive the Conviva_sdkConfig cookie.
* Use leading-dot form (e.g. ".example.com") for subdomain coverage.
*/
domains?: string[];
};
webViewBridge?: {
enabled?: boolean;
};
}
/**
* TrackerConfiguration
*/
interface TrackerConfiguration {
/**
* The device platform the tracker runs on.
* @defaultValue 'mob'
*/
devicePlatform?: DevicePlatform;
/**
* Whether payload JSON data should be base64 encoded.
* @defaultValue true
*/
base64Encoding?: boolean;
/**
* The log level of tracker logs.
* @defaultValue 'off'
*/
logLevel?: LogLevel;
/**
* Whether application context is attached to tracked events.
* @defaultValue true
*/
applicationContext?: boolean;
/**
* Whether platform context is attached to tracked events.
* @defaultValue true
*/
platformContext?: boolean;
/**
* Whether geo-location context is attached to tracked events.
* @defaultValue false
*/
geoLocationContext?: boolean;
/**
* Whether session context is attached to tracked events.
* @defaultValue true
*/
sessionContext?: boolean;
/**
* Whether to attach a Deep Link entity to the first ScreenView tracked in the tracker after DeepLinkReceived event.
* @defaultValue true
*/
deepLinkContext?: boolean;
/**
* Whether screen context is attached to tracked events.
* @defaultValue true
*/
screenContext?: boolean;
/**
* Whether enable automatic tracking of ScreenView events.
* @defaultValue true
*/
screenViewAutotracking?: boolean;
/**
* Whether enable automatic tracking of background and foreground transitions.
* @defaultValue false
*/
lifecycleAutotracking?: boolean;
/**
* Whether enable automatic tracking of install event.
* @defaultValue true
*/
installAutotracking?: boolean;
/**
* Whether enable crash reporting.
* @defaultValue true
*/
exceptionAutotracking?: boolean;
/**
* Whether enable diagnostic reporting.
* @defaultValue false
*/
diagnosticAutotracking?: boolean;
/**
* Whether to anonymise client-side user identifiers in session and platform context entities
* @defaultValue false
*/
userAnonymisation?: boolean;
}
/**
* SessionConfiguration
*/
interface SessionConfiguration {
/**
* The amount of time in seconds before the session id is updated while the app is in the foreground
* @defaultValue 1800
*/
foregroundTimeout: number;
/**
* The amount of time in seconds before the session id is updated while the app is in the background
* @defaultValue 1800
*/
backgroundTimeout: number;
}
/**
* EmitterConfiguration
*/
interface EmitterConfiguration {
/**
* The buffer option for post requests.
* @defaultValue 'single'
*/
bufferOption?: BufferOption;
/**
* Maximum number of events collected from the EventStore to be sent in a request.
* @defaultValue 150
*/
emitRange?: number;
/**
*Maximum number of threads working in parallel in the tracker to send requests.
* @defaultValue 15
*/
threadPoolSize?: number;
/**
* Maximum amount of bytes allowed to be sent in a payload in a POST request.
* @defaultValue 40000
*/
byteLimitPost?: number;
/**
* Maximum amount of bytes allowed to be sent in a payload in a GET request.
* @defaultValue 40000
*/
byteLimitGet?: number;
/**
* Whether to anonymise server-side user identifiers including the `network_userid` and `user_ipaddress`
* @defaultValue false
*/
serverAnonymisation?: boolean;
}
/**
* SubjectConfiguration
*/
interface SubjectConfiguration {
[index: string]: unknown;
/**
* user id
*/
userId?: string | null;
/**
* network user id (UUIDv4)
*/
networkUserId?: string | null;
/**
* domain user id
*/
domainUserId?: string | null;
/**
* The custom user-agent. It overrides the user-agent used by default.
*/
useragent?: string | null;
/**
* IP address
*/
ipAddress?: string | null;
/**
* The timezone label
*/
timezone?: string | null;
/**
* The language set in the device
*/
language?: string | null;
/**
* The screen resolution
*/
screenResolution?: ScreenSize | null;
/**
* The screen viewport size
*/
screenViewport?: ScreenSize | null;
/**
* color depth (integer)
*/
colorDepth?: number | null;
}
/**
* GdprConfiguration
*/
interface GdprConfiguration {
/**
* Basis for processing
*/
basisForProcessing: Basis;
/**
* ID of a GDPR basis document.
*/
documentId: string;
/**
* Version of the document.
*/
documentVersion: string;
/**
* Description of the document.
*/
documentDescription: string;
}
/**
* Global Context
*/
interface GlobalContext {
/**
* tag
*/
tag: string;
/**
* contexts
*/
globalContexts: SelfDescribing[];
}
/**
* Global Contexts configuration
*/
type GCConfiguration = GlobalContext[];
/**
* Remote Configuration
*/
interface RemoteConfiguration {
/**
* The remote config endpoint
*/
endpoint: string;
/**
* The Http Method to use for fetching the remote config
* @defaultValue 'post'
*/
method?: HttpMethod;
}
/**
* SessionReplayConfiguration
*
* Nested structure that mirrors the native replay SDK JSON schema exactly.
* Passed as `sessionReplayConfig` to createTracker. The bridge passes this
* through to the native SDK without key translation - same pattern as all
* other tracker configs.
*
* In production, enabled/sampling are driven by remote config.
* Set them here for local validation only.
*/
interface SessionReplayConfiguration {
/** Enable replay. Remote config overrides in production. @defaultValue false */
enabled?: boolean;
/** Enable verbose replay SDK logs (snapshot queue, flush counts). @defaultValue false */
logging?: boolean;
/** Sampling configuration. Remote config overrides in production. */
sampling?: {
/** Sampling percentage 0-100. @defaultValue 0 */
pct?: number;
};
/** Replay ingest network configuration (separate from analytics collector). */
networkConfiguration?: {
/** Replay ingest endpoint URL. e.g. 'https://rcg.conviva.com' */
endpoint?: string;
};
/** Replay emitter configuration. */
emitterConfiguration?: {
/** Network data mode: 'wifi' (wifi-only) or 'any'. @defaultValue 'wifi' */
dataMode?: 'wifi' | 'any';
/** Upload interval in seconds. @defaultValue 60 */
uploadInterval?: number;
/** Policy expiry time in seconds. @defaultValue 3600 */
policyExpiryTime?: number;
/** Flush threshold (number of events before an upload). @defaultValue 20 */
flushAt?: number;
/** Max events per upload batch. @defaultValue 120 */
maxBatchSize?: number;
/** Max events held in queue. @defaultValue 1000 */
maxQueueSize?: number;
};
/** Mobile recorder / masking configuration. */
mobRecorderConfiguration?: {
/** Mask all text inputs. @defaultValue true */
maskAllInputs?: boolean;
/** Mask all images. @defaultValue true */
maskAllImages?: boolean;
/**
* Mask system views.
* Read as maskAllSystemViews on Android, maskSandboxedSystemViews on iOS.
* Include both keys to cover both platforms.
* @defaultValue true
*/
maskAllSystemViews?: boolean;
/** iOS-specific key for masking sandboxed/system views. @defaultValue true */
maskSandboxedSystemViews?: boolean;
/** Input categories to mask. e.g. ['emailAddress','password','telephoneNumber'] */
maskInputOptions?: string[];
/** Capture throttle delay in ms. @defaultValue 1000 */
throttleDelayMs?: number;
/** Screenshot JPEG compression quality 0-100. @defaultValue 10 */
compressionQuality?: number;
};
}
/**
* The TrackerControllerConfiguration
*/
interface TrackerControllerConfiguration {
networkConfig?: NetworkConfiguration;
traceparentConfig?: TraceparentConfiguration;
trackerConfig?: TrackerConfiguration;
sessionConfig?: SessionConfiguration;
emitterConfig?: EmitterConfiguration;
subjectConfig?: SubjectConfiguration;
gdprConfig?: GdprConfiguration;
gcConfig?: GCConfiguration;
remoteConfig?: RemoteConfiguration;
/**
* Error tracking configuration. Pass `false` to fully disable JS error
* capture; omit or pass an object to opt in with defaults.
*
* When enabled, the SDK installs a chained ErrorUtils handler plus an
* engine-appropriate unhandled-promise-rejection hook, and exposes the
* `ConvivaErrorBoundary` React component + `tracker.trackError` API.
*/
errorTracking?: false | ErrorTrackingConfiguration;
clidSyncConfig?: ClidSyncConfiguration;
sessionReplayConfig?: SessionReplayConfiguration;
}
/**
* ScreenView event properties
* schema: iglu:com.snowplowanalytics.mobile/screen_view/jsonschema/1-0-0
*/
type ScreenViewProps = {
/**
* The name of the screen viewed
*/
name: string;
/**
* The id(UUID) of screen that was viewed
*/
id?: string;
/**
* The type of screen that was viewed
*/
type?: string;
/**
* The name of the previous screen that was viewed
*/
previousName?: string;
/**
* The id(UUID) of the previous screen that was viewed
*/
previousId?: string;
/**
* The type of the previous screen that was viewed
*/
previousType?: string;
/**
* The type of transition that led to the screen being viewed
*/
transitionType?: string;
};
/**
* Structured event properties
*/
type StructuredProps = {
/**
* The category of the event
*/
category: string;
/**
* The action the event represents
*/
action: string;
/**
* The label the action refers to
*/
label?: string;
/**
* The property associated with the user action
*/
property?: string;
/**
* The value associated with the user action
*/
value?: number;
};
/**
* PageView event properties
*/
type PageViewProps = {
/**
* The page URL
*/
pageUrl: string;
/**
* The page title
*/
pageTitle?: string;
/**
* The referrer URL
*/
referrer?: string;
};
/**
* Timing event properties
*/
type TimingProps = {
/**
* The timing category
*/
category: string;
/**
* The timing variable
*/
variable: string;
/**
* The time
*/
timing: number;
/**
* The timing label
*/
label?: string;
};
/**
* ConsentDocument properties
*/
interface ConsentDocument {
/**
* The consent document id
*/
documentId: string;
/**
* The consent document version
*/
version: string;
/**
* The consent document name
*/
name?: string;
/**
* The consent document description
*/
documentDescription?: string;
}
/**
* ConsentGranted event properties
*/
interface ConsentGrantedProps extends ConsentDocument {
/**
* The expiry (date-time string, e.g.: '2022-01-01T00:00:00Z')
*/
expiry: string;
}
/**
* ConsentWithdrawn event properties
*/
interface ConsentWithdrawnProps extends ConsentDocument {
/**
* Whether user opts out of all data collection
*/
all: boolean;
}
/**
* EcommerceItem
*/
type EcommerceItem = {
sku: string;
price: number;
quantity: number;
name?: string;
category?: string;
currency?: string;
};
/**
* EcommerceTransaction event properties
*/
type EcommerceTransactionProps = {
orderId: string;
totalValue: number;
items: EcommerceItem[];
affiliation?: string;
taxValue?: number;
shipping?: number;
city?: string;
state?: string;
country?: string;
currency?: string;
};
/**
* DeepLinkReceived event properties
* schema: iglu:com.snowplowanalytics.mobile/deep_link_received/jsonschema/1-0-0
*/
type DeepLinkReceivedProps = {
/**
* URL in the received deep-link.
*/
url: string;
/**
* Referrer URL, source of this deep-link.
*/
referrer?: string;
};
/**
* Attachment object that identify an attachment in the MessageNotification.
*/
type MessageNotificationAttachmentProps = {
identifier: string;
type: string;
url: string;
};
/**
* MessageNotification event properties
* schema: iglu:com.snowplowanalytics.mobile/message_notification/jsonschema/1-0-0
*/
type MessageNotificationProps = {
/**
* The action associated with the notification.
*/
action?: string;
attachments?: MessageNotificationAttachmentProps[];
/**
* The notification's body.
*/
body: string;
bodyLocArgs?: string[];
/**
* The key to the body string in the app's string resources to use to localize the body text to the user's current localization.
*/
bodyLocKey?: string;
/**
* The category associated to the notification.
*/
category?: string;
/**
* The application is notified of the delivery of the notification if it's in the foreground or background, the app will be woken up (iOS only).
*/
contentAvailable?: boolean;
/**
* The group which this notification is part of.
*/
group?: string;
/**
* The icon associated to the notification (Android only).
*/
icon?: string;
/**
* The number of items this notification represent.
*/
notificationCount?: number;
/**
* The time when the event of the notification occurred.
*/
notificationTimestamp?: string;
/**
* The sound played when the device receives the notification.
*/
sound?: string;
/**
* The notification's subtitle. (iOS only)
*/
subtitle?: string;
/**
* An identifier similar to 'group' but usable for different purposes (Android only).
*/
tag?: string;
/**
* An identifier similar to 'group' but usable for different purposes (iOS only).
*/
threadIdentifier?: string;
/**
* The notification's title.
*/
title: string;
/**
* Variable string values to be used in place of the format specifiers in titleLocArgs to use to localize the title text to the user's current localization.
*/
titleLocArgs?: string[];
/**
* The key to the title string in the app's string resources to use to localize the title text to the user's current localization.
*/
titleLocKey?: string;
/**
* The trigger that raised the notification message. Must be one of: push, location, calendar, timeInterval, other
*/
trigger: Trigger;
};
/**
* RevenueEventItem properties.
* All fields are optional.
*/
type RevenueEventItemProps = {
productId?: string;
name?: string;
sku?: string;
category?: string[];
unitPrice?: number;
quantity?: number;
discount?: number;
brand?: string;
variant?: string;
extraMetadata?: Record<string, unknown>;
};
/**
* Properties accepted by `tracker.trackError` for manual error reporting.
*
* - `message` is required.
* - `errorType` and `stackTrace` are optional — most consumers will pass an
* `Error` instance through the higher-level `ConvivaErrorBoundary` component
* or rely on automatic capture via the global handler / promise-rejection
* hook. This shape is designed for hand-rolled try/catch blocks where the
* consumer has already stringified an error.
*/
type ErrorEventProps = {
message: string;
errorType?: string;
stackTrace?: string;
isFatal?: boolean;
isHandled?: boolean;
componentStack?: string;
attributes?: Record<string, string | number | boolean>;
};
/**
* RevenueEvent properties.
* Required: totalOrderAmount, transactionId, currency.
*/
type RevenueEventProps = {
totalOrderAmount: number;
transactionId: string;
currency: string;
taxAmount?: number;
shippingCost?: number;
discount?: number;
cartSize?: number;
paymentMethod?: string;
paymentProvider?: string;
items?: RevenueEventItemProps[];
extraMetadata?: Record<string, unknown>;
};
/**
* The ReactNativeTracker type
*/
type ReactNativeTracker = {
/**
* Tracks a self-descibing event
*
* @param argmap - The self-describing event properties
* @param contexts - The array of event contexts
* @typeParam TData - The type of the data object within the SelfDescribing object
*/
readonly trackSelfDescribingEvent: <TData extends Record<keyof TData, unknown> = Record<string, unknown>>(argmap: SelfDescribing<TData>, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a screen-view event
*
* @param argmap - The screen-view event's properties
* @param contexts - The array of event contexts
*/
readonly trackScreenViewEvent: (argmap: ScreenViewProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a structured event
*
* @param argmap - The structured event properties
* @param contexts - The array of event contexts
*/
readonly trackStructuredEvent: (argmap: StructuredProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a page-view event
*
* @param argmap - The page-view event properties
* @param contexts - The array of event contexts
*/
readonly trackPageView: (argmap: PageViewProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a timing event
*
* @param argmap - The timing event properties
* @param contexts - The array of event contexts
*/
readonly trackTimingEvent: (argmap: TimingProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a consent-granted event
*
* @param argmap - The consent-granted event properties
* @param contexts - The array of event contexts
*/
readonly trackConsentGrantedEvent: (argmap: ConsentGrantedProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a consent-withdrawn event
*
* @param argmap - The consent-withdrawn event properties
* @param contexts - The array of event contexts
*/
readonly trackConsentWithdrawnEvent: (argmap: ConsentWithdrawnProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks an ecommerce-transaction event
*
* @param argmap - The ecommerce-transaction event properties
* @param contexts - The array of event contexts
*/
readonly trackEcommerceTransactionEvent: (argmap: EcommerceTransactionProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a deep link received event
*
* @param argmap - The deep link received event properties
* @param contexts - The array of event contexts
*/
readonly trackDeepLinkReceivedEvent: (argmap: DeepLinkReceivedProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a message notification event
*
* @param argmap - The message notification event properties
* @param contexts - The array of event contexts
*/
readonly trackMessageNotificationEvent: (argmap: MessageNotificationProps, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a Custom Event
*
* @param eventName {string} - the custom event name
* @param eventData {any} - the event data
* @param contexts {Array}- the event contexts
* @returns {Promise}
*/
readonly trackCustomEvent: (eventName: string, eventData: any, contexts?: EventContext[]) => Promise<void>;
/**
* Tracks a revenue event
*
* @param argmap - The revenue event properties
* @param contexts - The array of event contexts
*/
readonly trackRevenueEvent: (argmap: RevenueEventProps, contexts?: EventContext[]) => Promise<void>;
/**
* Sets custom tags
*
* @param tags {any} - the custom tags
* @param contexts {Array}- the event contexts
* @returns {Promise}
*/
readonly setCustomTags: (tags: any, contexts?: EventContext[]) => Promise<void>;
/**
* Sets custom tags with category
*
* @param category {string} - category
* @param tags {any} - the custom tags
* @param contexts {Array}- the event contexts
* @returns {Promise}
*/
readonly setCustomTagsWithCategory: (category: string, tags: any, contexts?: EventContext[]) => Promise<void>;
/**
* Clears few of the Custom Tags which are set previously
*
* @param tagKeys {string []} - the custom tag keys to be deleted
* @param contexts {Array}- the event contexts
* @returns {Promise}
*/
readonly clearCustomTags: (tagKeys: string[], contexts?: EventContext[]) => Promise<void>;
/**
* Clears all the previously set Custom Tags
*
* @param contexts {Array}- the event contexts
* @returns {Promise}
*/
readonly clearAllCustomTags: (contexts?: EventContext[]) => Promise<void>;
/**
* Removes global contexts
*
* @param tag - The tag of the global contexts to remove
*/
readonly removeGlobalContexts: (tag: string) => Promise<void>;
/**
* Adds global contexts
*
* @param gc - The global context to add
*/
readonly addGlobalContexts: (gc: GlobalContext) => Promise<void>;
/**
* Sets the userId of the tracker subject
*
* @param newUid - The new userId
*/
readonly setUserId: (newUid: string | null) => Promise<void>;
/**
* Sets the networkUserId of the tracker subject
*
* @param newNuid - The new networkUserId
*/
readonly setNetworkUserId: (newNuid: string | null) => Promise<void>;
/**
* Sets the domainUserId of the tracker subject
*
* @param newDuid - The new domainUserId
*/
readonly setDomainUserId: (newDuid: string | null) => Promise<void>;
/**
* Sets the ipAddress of the tracker subject
*
* @param newIp - The new ipAddress
*/
readonly setIpAddress: (newIp: string | null) => Promise<void>;
/**
* Sets the useragent of the tracker subject
*
* @param newUagent - The new useragent
*/
readonly setUseragent: (newUagent: string | null) => Promise<void>;
/**
* Sets the timezone of the tracker subject
*
* @param newTz - The new timezone
*/
readonly setTimezone: (newTz: string | null) => Promise<void>;
/**
* Sets the language of the tracker subject
*
* @param newLang - The new language
*/
readonly setLanguage: (newLang: string | null) => Promise<void>;
/**
* Sets the screenResolution of the tracker subject
*
* @param newRes - The new screenResolution
*/
readonly setScreenResolution: (newRes: ScreenSize | null) => Promise<void>;
/**
* Sets the screenViewport of the tracker subject
*
* @param newView - The new screenViewport
*/
readonly setScreenViewport: (newView: ScreenSize | null) => Promise<void>;
/**
* Sets the colorDepth of the tracker subject
*
* @param newColorD - The new colorDepth
*/
readonly setColorDepth: (newLang: number | null) => Promise<void>;
/**
* Sets subject data
*
* @param config - The new subject data
*/
readonly setSubjectData: (config: SubjectConfiguration) => Promise<void>;
/**
* Gets the dentifier for the user of the session
*
* @returns {Promise<string | undefined>}
*/
readonly getSessionUserId: () => Promise<string | undefined>;
/**
* Gets the identifier for the session
*
* @returns {Promise<string | undefined>}
*/
readonly getSessionId: () => Promise<string | undefined>;
/**
* Gets the index of the current session for this user
*
* @returns {Promise<number | undefined>}
*/
readonly getSessionIndex: () => Promise<number | undefined>;
/**
* Gets whether the app is currently in background state
*
* @returns {Promise<boolean | undefined>}
*/
readonly getIsInBackground: () => Promise<boolean | undefined>;
/**
* Gets the number of background transitions in the current session
*
* @returns {Promise<number | undefined>}
*/
readonly getBackgroundIndex: () => Promise<number | undefined>;
/**
* Gets the number of foreground transitions in the current session.
*
* @returns {Promise<number | undefined>}
*/
readonly getForegroundIndex: () => Promise<number | undefined>;
/**
* Tracks a click event
*
* @param eventData - The user click event properties
*/
readonly trackClickEvent: (eventData: any) => Promise<void>;
/**
* Passes JS bundle identity fields to the native SDK so they are attached
* to the Conviva app-context entity on every subsequent event.
*
* Recognised keys: `jsBundleSource`, `jsBundleId`, `jsBundleChannel`,
* `jsBundleLabel`, `jsEngine`. Unknown keys and empty string values are
* silently ignored by the native SDK.
*
* @param info - Map of JS bundle fields
*/
readonly setJsBundleInfo: (info: Record<string, string>) => Promise<void>;
/**
* Manually report a JS error. For try/catch blocks and other sites where
* the consumer wants to capture an error with richer context than what the
* automatic global handler / promise-rejection / ErrorBoundary hooks
* provide. Fail-silent — never throws.
*
* Defaults: `isFatal=false`, `isHandled=true`.
*
* @param argmap - The error event properties. `message` is required.
* @param contexts - Optional event contexts forwarded to the native tracker.
*/
readonly trackError: (argmap: ErrorEventProps, contexts?: EventContext[]) => Promise<void>;
};
/**
* Enables tracking events from apps rendered in react-native-webview components.
* The apps need to use the Conviva WebView tracker to track the events.
*
* To subscribe for the events, set the `onMessage` attribute:
* <WebView onMessage={getWebViewCallback()} ... />
*
* @returns Callback to subscribe for events from Web views tracked using the Conviva WebView tracker.
*/
declare function getWebViewCallback(): (message: {
nativeEvent: {
data: string;
};
}) => void;
declare function withReactNavigationAutotrack(track: any): (AppContainer: any) => React.ForwardRefExoticComponent<React.RefAttributes<any>>;
interface ConvivaErrorBoundaryProps {
/**
* Children tree to protect. If any descendant throws during render, commit,
* or lifecycle, this boundary captures the error and renders `fallback`.
*/
children?: React$1.ReactNode;
/**
* What to render when an error is active. Either a ReactNode or a function
* that receives the captured error + a `reset()` callback, matching
* Sentry and react-error-boundary conventions.
*/
fallback?: React$1.ReactNode | ((args: {
error: Error;
reset: () => void;
}) => React$1.ReactNode);
/**
* When any value in this array changes between renders, the boundary
* resets and re-renders children. Useful to recover on route changes.
*/
resetKeys?: ReadonlyArray<unknown>;
/** Consumer callback invoked just before dispatch. Must not throw. */
onError?: (error: Error, componentStack: string) => void;
/**
* Tag this boundary with a human-readable name, forwarded as an attribute
* on the captured payload.
*/
name?: string;
}
interface State {
error: Error | null;
/**
* Mirror of `errorTracker.isEnabled()`, kept in state so the boundary
* re-renders when remote config toggles error tracking at runtime. Optional
* because some state updates (e.g. getDerivedStateFromError) only set `error`;
* an unset value is treated as enabled (the boundary keeps protecting).
*/
enabled?: boolean;
}
/**
* React error boundary that forwards caught render/commit errors to the
* Conviva error tracker with `errorSource: 'errorBoundary'`.
*
* Design notes:
* - Marks the error object in the tracker's DedupGuard BEFORE dispatch so
* the global handler (if the error re-throws up the tree) does not send
* the same error twice.
* - Reset keys mirror the well-known react-error-boundary prop contract.
*/
declare class ConvivaErrorBoundary extends React$1.Component<ConvivaErrorBoundaryProps, State> {
state: State;
/** Cleanup for the enable-state subscription; set in componentDidMount. */
private unsubscribeEnabled;
/** Reads the tracker enable flag defensively (never throws). */
private static readEnabled;
static getDerivedStateFromError(error: Error): Partial<State>;
componentDidMount(): void;
componentWillUnmount(): void;
componentDidCatch(error: Error, info: {
componentStack: string;
}): void;
componentDidUpdate(prevProps: ConvivaErrorBoundaryProps): void;
reset: () => void;
render(): React$1.ReactNode;
}
/**
* Prevents the same Error object from being reported twice when captured by
* multiple hooks (e.g. ErrorUtils.setGlobalHandler runs, then a parent
* ErrorBoundary's componentDidCatch runs for the same throw).
*
* Strategy:
* - Error instances tracked via WeakSet so GC is automatic (no leak).
* - Non-Error thrown primitives delegated to PrimitiveDedupStore, since
* primitives cannot be WeakSet keys.
*/
declare class DedupGuard {
private seenObjects;
private readonly primitives;
constructor(primitiveTtlMs?: number, maxPrimitives?: number);
/** true if this thrown value was already seen within the TTL window. */
isDuplicate(err: unknown): boolean;
/** Call after dispatching so subsequent captures of the same throw are suppressed. */
markSeen(err: unknown): void;
/** Test hook — clears all seen state. Not part of the public API. */
_reset(): void;
}
/**
* Per-session sliding-window + circuit-breaker rate limiter.
*
* Two-phase design (mirrors the Conviva JS horizontal tracker):
* - CLOSED : up to `maxEvents` events allowed in any rolling `windowMs` window.
* - OPEN : once the window limit is exceeded, the circuit opens for
* `disconnectMs` and all subsequent events are dropped — even if
* the sliding window would otherwise allow them. This prevents
* a storm of duplicates from resuming immediately after the
* window slides.
*/
declare class RateLimiter {
private ringBuffer;
private windowStart;
private maxEvents;
private windowMs;
private disconnectMs;
private circuitOpenUntil;
constructor(maxEvents: number, windowMs: number, disconnectMs: number);
/**
* Returns true when an event is allowed to proceed. Consumes a slot on
* allow. Caller must NOT consume a slot if the event is filtered out by a
* beforeCapture hook.
*/
tryAcquire(now?: number): boolean;
/**
* Live update from remote config. Preserves in-flight state sensibly:
* - Resets the window start only when maxEvents changes (buffer is resized).
* - Does NOT close an already-open circuit early: new disconnectMs applies
* from the next time the circuit opens.
*/
updateConfig(maxEvents: number, windowMs: number, disconnectMs: number): void;
/** true when the circuit is currently OPEN (i.e. all events dropped). */
isOpen(now?: number): boolean;
/** Test hook — clears all state. Not part of the public API. */
_reset(): void;
private sanitizeMaxEvents;
private sanitizePositive;
}
/**
* Singleton error tracker. Owns all capture plugins, rate limiting,
* deduplication, user-id propagation, and bridge dispatch.
*
* Lifetime:
* - Constructed as an ES module singleton (`export const errorTracker = ...`)
* so it can be imported by plugins and the ErrorBoundary without having a
* reference threaded through props.
* - `_initFromTracker()` is called by the SDK init code path. Subsequent
* re-calls apply the new config and reinstall hooks via `_applyHookState`,
* so capture-flag changes (captureGlobalErrors, captureUnhandledRejections)
* and enable/disable transitions take effect immediately.
* - `setEnabled()` and `_updateFromRemoteConfig()` route through the same
* `_applyHookState` helper so runtime toggles match init semantics.
* - `teardown()` uninstalls hooks and is called on SDK cleanup/removeAll.
*/
declare class ConvivaErrorTracker {
private config;
private bridge;
private rateLimiter;
private dedup;
private pluginCleanups;
private installed;
private attributes;
private enabledListeners;
constructor();
/**
* Called from src/api.ts on createTracker(). Wires the consumer config and
* installs all capture hooks. Safe to call multiple times — config always
* reflects the latest call, and capture-hook flags (captureGlobalErrors,
* captureUnhandledRejections, enabled) are applied on every call by
* tearing down the existing hooks and reinstalling them with the updated
* flags via `_applyHookState`.
*/
_initFromTracker(cfg: ErrorTrackingConfiguration | undefined): void;
/**
* Aligns plugin install state with the current `config.enabled` /
* captureGlobalErrors / captureUnhandledRejections flags. Always tears
* down existing hooks first so flag changes take effect immediately:
* - enabled:false → uninstall all plugins, clear INSTALL_FLAG.
* - enabled:true → uninstall + reinstall per current capture flags.
*
* HMR / hot-reload safety: cleanup handles are read from
* `globalThis[INSTALL_FLAG]` rather than only from `this.pluginCleanups`,
* so a new tracker instance constructed by a re-evaluated module (Fast
* Refresh, dev-server reload) still tears down the previous instance's
* handlers instead of chaining a new one on top of the old one.
*
* Plugin installation is deferred until initialisation via
* `installPlugins()`, but the plugin modules themselves are imported when
* this tracker module is loaded.
*/
private _applyHookState;
/**
* Runs every plugin cleanup (preferring the global-slot copy over
* `this.pluginCleanups` so an HMR-swapped instance can still tear down the
* previous incarnation's handlers), then clears local state and the global
* install slot. Used by both `_applyHookState` (before reinstall) and
* `teardown` (final shutdown).
*/
private _drainPluginCleanups;
/**
* Current master enable state. Read by ConvivaErrorBoundary to decide whether
* to intercept (enabled) or pass the error through (disabled).
*/
isEnabled(): boolean;
/**
* Subscribe to master enable-state changes. The listener is invoked with the
* current `enabled` value whenever it may have changed. Returns an
* unsubscribe function. Never throws.
*/
onEnabledChange(listener: (enabled: boolean) => void): () => void;
/** Notifies enable-state listeners with the current value. Fail-silent. */
private _notifyEnabledChange;
/**
* Uninstalls every capture hook and clears internal state. Idempotent.
* Called from src/api.ts on removeAllTrackers() / cleanup().
*
* Drains cleanups from BOTH `this.pluginCleanups` and the global install
* slot so an HMR-swapped instance can still tear down handlers that were
* registered by a previous incarnation of this module.
*/
teardown(): void;
/**
* Public toggle used by consumer API + remote config. Routes through
* `_applyHookState` so transitions in either direction are observable:
* enabled:false uninstalls plugins and clears INSTALL_FLAG, while
* enabled:true installs them per current capture flags.
*/
setEnabled(enabled: boolean): void;
setRateLimitingEnabled(enabled: boolean): void;
addAttribute(key: string, value: string | number | boolean): void;
removeAttribute(key: string): void;
/** Called from src/subject.ts when setUserId runs. Kept internal. */
_setUserId(id: string | null): void;
/**
* Remote-config update point. Not yet wired to a backend, but in place for
* future milestones. All fields optional; only provided ones override.
*
* If any of `enabled`, `captureGlobalErrors`, or `captureUnhandledRejections`
* actually change, `_applyHookState` is invoked so plugin install state
* matches the new config. This keeps remote-driven enable/disable and
* capture toggles observable at the hook layer (not just at dispatch).
*/
_updateFromRemoteConfig(patch: Partial<ErrorTrackingInternalConfig> | null | undefined): void;
/**
* Applies the three hook-affecting boolean flags from a remote-config patch
* via the `HOOK_BOOLEAN_KEYS` table. Returns true when any flag actually
* changed so the caller can decide whether to reinstall plugin hooks.
*/
private _applyHookBooleanPatch;
/**
* Applies the rate-limit subset of a remote-config patch to the internal
* config and updates the RateLimiter when any value changed.
*/
private _applyRateLimitPatch;
/**
* Internal entry point called from each plugin. Responsibilities:
* 1. Honour dev-suppression and `enabled`.
* 2. Honour per-source capture flags so runtime toggles work even when a
* plugin's teardown is best-effort (e.g. Hermes).
* 3. Build + truncate the payload via private helpers.
* 4. Run beforeCapture hook (fail-open).
* 5. Bridge availability check.
* 6. Rate-limit (after hook & bridge check — filtered / undeliverable
* events don't consume tokens).
* 7. Forward to bridge adapter.
*
* NEVER throws. The pre-payload gates and the post-payload pipeline are
* extracted into `_acquireBridge` and `_passesDispatchPipeline` so this
* method's cyclomatic complexity stays low.
*/
_dispatch(args: {
error: unknown;
errorSource: ErrorSource;
isFatal: boolean;
isHandled: boolean;
componentStack?: string;
severityOverride?: ErrorSeverity;
extraAttributes?: Record<string, string | number | boolean>;
}): void;
/**
* Consolidates the pre-payload gates (enabled / dev-suppression / per-source
* capture flag / bridge presence) into a single check. Returns the captured
* bridge reference when dispatch should proceed, or `null` to short-circuit.
*
* Capturing the bridge here means the dispatch path is stable against
* re-entrant mutation (e.g. a beforeCapture hook calling `_setBridge`) and
* TypeScript can narrow `bridge` to `BridgeAdapter` for the rest of `_dispatch`.
*/
private _acquireBridge;
/**
* Final post-payload gating: runs the beforeCapture hook (fail-open per D8),
* confirms the bridge is still available, and consumes a rate-limit slot.
* Returns `true` when the payload should be forwarded, `false` when dropped.
*
* Filtered / undeliverable events never consume a rate-limit token —
* `tryAcquire` is the LAST gate before forwarding.
*/
private _passesDispatchPipeline;
/**
* Final hop to the native bridge. No session/subject enrichment happens
* here: session linkage is owned by the native Conviva/Snowplow tracker,
* which attaches a `client_session` context entity to every event emitted
* from `trackCustomEvent` / `track(SelfDescribing(...))` when
* `sessionContext: true` (the default). Adding a JS-side session fetch
* would either duplicate that entity or produce a stale value across
* native session rollovers, so the JS pipeline deliberately stays out
* of it. Kept as a separate method purely as a test seam.
*/
private _forwardToBridge;
/** @internal — test/introspection accessor. */
_getConfig(): ErrorTrackingInternalConfig;
/** @internal — test/introspection accessor. */
_getBridge(): BridgeAdapter | null;
/** @internal — test/introspection accessor. */
_getDedupGuard(): DedupGuard;
/** @internal — test/introspection accessor. */
_getRateLimiter(): RateLimiter;
/** @internal — Bridge replacement (tests only). */
_setBridge(bridge: BridgeAdapter | null): void;
/** @internal — hook install seam. See installPlugins. */
get installedState(): boolean;
/**
* Installs global-error-handler + promise-rejection plugins. Lazy-required
* so unit tests do not pull in RN / ErrorUtils side effects at module load.
*
* The ErrorBoundary component is NOT installed here — it is a React
* component the consumer wraps around their tree.
*/
private installPlugins;
/** @internal — resolves once any pending install completes (test helper). */
_waitForInstall(): Promise<void>;
}
/** Module-level singleton shared by api.ts, subject.ts, and plugins. */
declare const errorTracker: ConvivaErrorTracker;
/**
* In-memory bridge adapter used for unit / integration tests and the DemoApp
* manual-test harness. Collects every payload the error tracker would have
* sent to native so tests can assert on structure and ordering.
*/
declare class MockBridgeAdapter implements BridgeAdapter {
payloads: JsErrorPayload[];
isAvailable(): boolean;
reportJsError(payload: JsErrorPayload): void;
/** Clears captured payloads. Useful between tests. */
clear(): void;
}
/**
* Creates a React Native Tracker object
*
* @param customerKey {string} - The Conviva customer key for the application
* @param appName {string} - The application name reported with events
* @param controllerConfig {TrackerControllerConfiguration} - Optional tracker controller configuration
* @returns The tracker object
*/
declare function createTracker(customerKey: string, appName: string, controllerConfig?: TrackerControllerConfiguration): ReactNativeTracker;
/**
* Removes a tracker given its nam