UNPKG

@segment/analytics-react-native

Version:

The hassle-free way to add Segment analytics to your React-Native app.

243 lines (230 loc) 6.5 kB
import { Timeline } from './timeline'; import { EventType, PluginType } from './types'; export class Plugin { // default to utility to avoid automatic processing type = PluginType.utility; analytics = undefined; configure(analytics) { this.analytics = analytics; } update(_settings, _type) { // do nothing by default, user can override. } execute(event) { // do nothing. return event; } shutdown() { // do nothing by default, user can override. } } export class EventPlugin extends Plugin { execute(event) { if (event === undefined) { return event; } let result = event; switch (result.type) { case EventType.IdentifyEvent: result = this.identify(result); break; case EventType.TrackEvent: result = this.track(result); break; case EventType.ScreenEvent: result = this.screen(result); break; case EventType.AliasEvent: result = this.alias(result); break; case EventType.GroupEvent: result = this.group(result); break; } return result; } // Default implementations that forward the event. This gives plugin // implementors the chance to interject on an event. identify(event) { return event; } track(event) { return event; } screen(event) { return event; } alias(event) { return event; } group(event) { return event; } flush() { return; } reset() { return; } } export class DestinationPlugin extends EventPlugin { // default to destination type = PluginType.destination; key = ''; timeline = new Timeline(); // eslint-disable-next-line @typescript-eslint/no-explicit-any hasSettings() { return this.analytics?.settings.get()?.[this.key] !== undefined; } isEnabled(event) { let customerDisabled = false; if (event.integrations?.[this.key] === false) { customerDisabled = true; } return this.hasSettings() && !customerDisabled; } /** Adds a new plugin to the currently loaded set. - Parameter plugin: The plugin to be added. - Returns: Returns the name of the supplied plugin. */ add(plugin) { const analytics = this.analytics; if (analytics) { plugin.configure(analytics); } if (analytics && plugin instanceof WaitingPlugin) { analytics.pauseEventProcessingForPlugin(plugin); } this.timeline.add(plugin); return plugin; } /** Applies the supplied closure to the currently loaded set of plugins. - Parameter closure: A closure that takes an plugin to be operated on as a parameter. */ apply(closure) { this.timeline.apply(closure); } configure(analytics) { this.analytics = analytics; this.apply(plugin => { plugin.configure(analytics); }); } /** Removes and unloads plugins with a matching name from the system. - Parameter pluginName: An plugin name. */ remove(plugin) { this.timeline.remove(plugin); } async execute(event) { if (!this.isEnabled(event)) { return; } // Apply before and enrichment plugins const beforeResult = await this.timeline.applyPlugins({ type: PluginType.before, event }); if (beforeResult === undefined) { return; } const enrichmentResult = await this.timeline.applyPlugins({ type: PluginType.enrichment, event: beforeResult }); if (enrichmentResult === undefined) { return; } // Now send the event to the destination by executing the normal flow of an EventPlugin await super.execute(enrichmentResult); // apply .after plugins const afterResult = await this.timeline.applyPlugins({ type: PluginType.after, event: enrichmentResult }); return afterResult; } } export class UtilityPlugin extends EventPlugin {} // For internal platform-specific bits export class PlatformPlugin extends Plugin {} export { PluginType }; /** * WaitingPlugin - A base class for plugins that need to pause event processing * until an asynchronous operation completes. * * When a WaitingPlugin is added to the Analytics client, it automatically pauses * event processing. Events are buffered in memory until the plugin calls resume(). * If resume() is not called within 30 seconds, event processing automatically resumes. * * @example * ```typescript * class IDFAPlugin extends WaitingPlugin { * type = PluginType.enrichment; * * configure(analytics: SegmentClient) { * super.configure(analytics); * // Request IDFA permission * requestTrackingPermission().then((status) => { * if (status === 'authorized') { * // Add IDFA to context * } * this.resume(); // Resume event processing * }); * } * * track(event: SegmentEvent) { * // Enrich event with IDFA if available * return event; * } * } * ``` * * Common use cases: * - Waiting for user permissions (IDFA, location, notifications) * - Initializing native SDKs that provide enrichment data * - Loading remote configuration required for event processing * - Waiting for authentication state before sending events * * @remarks * Multiple WaitingPlugins can be active simultaneously. Event processing * only resumes when ALL waiting plugins have called resume() or timed out. * * WaitingPlugins can be added at any plugin type (before, enrichment, destination). * They can also be added to DestinationPlugins to pause only that destination's * event processing. */ export class WaitingPlugin extends Plugin { constructor() { super(); } /** * Configure the plugin with the Analytics client. * Automatically pauses event processing when called. * Override this method to perform async initialization, then call resume(). * * @param analytics - The Analytics client instance */ configure(analytics) { super.configure(analytics); } /** * Manually pause event processing. * Generally not needed as adding a WaitingPlugin automatically pauses processing. */ pause() { this.analytics?.pauseEventProcessingForPlugin(this); } /** * Resume event processing for this plugin. * Call this method when your async operation completes. * If all WaitingPlugins have resumed, buffered events will be processed. */ async resume() { await this.analytics?.resumeEventProcessingForPlugin(this); } } //# sourceMappingURL=plugin.js.map