@segment/analytics-react-native
Version:
The hassle-free way to add Segment analytics to your React-Native app.
213 lines (176 loc) • 4.98 kB
text/typescript
import type { SegmentClient } from './analytics';
import { Timeline } from './timeline';
import {
AliasEventType,
EventType,
GroupEventType,
IdentifyEventType,
PluginType,
ScreenEventType,
SegmentAPISettings,
SegmentEvent,
TrackEventType,
UpdateType,
} from './types';
export class Plugin {
// default to utility to avoid automatic processing
type: PluginType = PluginType.utility;
analytics?: SegmentClient = undefined;
configure(analytics: SegmentClient) {
this.analytics = analytics;
}
update(_settings: SegmentAPISettings, _type: UpdateType) {
// do nothing by default, user can override.
}
execute(
event: SegmentEvent
): Promise<SegmentEvent | undefined> | SegmentEvent | undefined {
// do nothing.
return event;
}
shutdown() {
// do nothing by default, user can override.
}
}
export class EventPlugin extends Plugin {
execute(
event: SegmentEvent
): Promise<SegmentEvent | undefined> | SegmentEvent | undefined {
if (event === undefined) {
return event;
}
let result: Promise<SegmentEvent | undefined> | SegmentEvent | undefined =
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: IdentifyEventType
): Promise<IdentifyEventType | undefined> | IdentifyEventType | undefined {
return event;
}
track(
event: TrackEventType
): Promise<TrackEventType | undefined> | TrackEventType | undefined {
return event;
}
screen(
event: ScreenEventType
): Promise<ScreenEventType | undefined> | ScreenEventType | undefined {
return event;
}
alias(
event: AliasEventType
): Promise<AliasEventType | undefined> | AliasEventType | undefined {
return event;
}
group(
event: GroupEventType
): Promise<GroupEventType | undefined> | GroupEventType | undefined {
return event;
}
flush(): void | Promise<void> {
return;
}
reset(): void | Promise<void> {
return;
}
}
export class DestinationPlugin extends EventPlugin {
// default to destination
type = PluginType.destination;
key = '';
timeline = new Timeline();
private hasSettings() {
return this.analytics?.settings.get()?.[this.key] !== undefined;
}
private isEnabled(event: SegmentEvent): boolean {
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: Plugin) {
const analytics = this.analytics;
if (analytics) {
plugin.configure(analytics);
}
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: (plugin: Plugin) => void) {
this.timeline.apply(closure);
}
configure(analytics: SegmentClient) {
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: Plugin) {
this.timeline.remove(plugin);
}
async execute(event: SegmentEvent): Promise<SegmentEvent | undefined> {
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 {}