import { AmplitudeEngagement, mkAmplitudeEngagement, } from './AmplitudeEngagement'; import { AmplitudeEngagementPlugin } from './AmplitudeEngagementPlugin'; import type { AmplitudeBootOptions, AmplitudeInitOptions, GuideOrSurvey, } from './types'; import type { BaseEvent } from '@amplitude/analytics-core'; export type { AmplitudeBootOptions, AmplitudeEndUser, AmplitudeInitOptions, AmplitudeIntegration, GuideOrSurvey, } from './types'; let globalEngagement: AmplitudeEngagement = null as any; let toNotify: ((engagement: AmplitudeEngagement) => void)[] = []; async function getGlobalEngagement(): Promise { if (globalEngagement) { return globalEngagement; } else { return await new Promise((resolve, _reject) => { toNotify.push((engagement) => { resolve(engagement); }); }); } } export function init(apiKey: string, options?: AmplitudeInitOptions): void { // Initialize the plugin with the API key if (globalEngagement) { throw new Error('AmplitudeEngagement already initialized'); } globalEngagement = AmplitudeEngagement.create(apiKey, options); toNotify.forEach((callback) => { callback(globalEngagement); }); toNotify = []; } /** * Non-blocking variant of {@link init}. Awaits construction of the native * instance instead of building it synchronously, so callers (e.g. the React * Native plugin's `setup`) don't block the thread on the native `newInstance`, * and resolving guarantees the SDK is ready. SDK methods called before this * resolves are safe: they queue on the engagement's `id` promise and run once * initialization completes. Can be called deferred (e.g. after first paint / * InteractionManager.runAfterInteractions) to keep creation off the launch path. */ export async function initAsync( apiKey: string, options?: AmplitudeInitOptions ): Promise { if (globalEngagement) { throw new Error('AmplitudeEngagement already initialized'); } globalEngagement = await mkAmplitudeEngagement(apiKey, options); toNotify.forEach((callback) => { callback(globalEngagement); }); toNotify = []; } export async function boot(options: AmplitudeBootOptions): Promise; export async function boot( user_id?: string, device_id?: string, user_properties?: Object ): Promise; export async function boot( optionsOrUserId?: AmplitudeBootOptions | string, device_id?: string, user_properties?: Object ): Promise { const e = await getGlobalEngagement(); if (typeof optionsOrUserId === 'object' && optionsOrUserId !== null) { return e.boot(optionsOrUserId); } return e.boot(optionsOrUserId, device_id, user_properties); } export async function enable(): Promise { const e = await getGlobalEngagement(); return e.enable(); } export async function disable(): Promise { const e = await getGlobalEngagement(); return e.disable(); } export async function shutdown(): Promise { const e = await getGlobalEngagement(); return e.shutdown(); } export async function list(): Promise { const e = await getGlobalEngagement(); return e.list(); } export async function show(key: string, stepIndex: number): Promise { const e = await getGlobalEngagement(); return e.show(key, stepIndex); } export async function screen(screenName: string): Promise { const e = await getGlobalEngagement(); return e.screen(screenName); } export async function closeAll(): Promise { const e = await getGlobalEngagement(); return e.closeAll(); } export async function updateLanguage(locale: string): Promise { const e = await getGlobalEngagement(); return e.updateLanguage(locale); } export async function forwardEvent(event: BaseEvent): Promise { const e = await getGlobalEngagement(); return e.forwardEvent(event); } export function addCallback(key: string, func: () => void): () => void { const removePromise = getGlobalEngagement().then((engagement) => { return engagement.addCallback(key, func); }); return () => { removePromise.then((r) => r()); }; } /** * Sets a router function used to handle navigation requests from guides/surveys * (e.g. "Go to screen" CTA button actions). * * @example * ```typescript * import { setRouter } from '@amplitude/plugin-engagement-react-native'; * import { navigate } from './navigation'; * * setRouter((url) => { * navigate(url); * }); * ``` */ export async function setRouter(router: (url: string) => void): Promise { const e = await getGlobalEngagement(); return e.setRouter(router); } /** Removes the currently configured router, if any. */ export async function unsetRouter(): Promise { const e = await getGlobalEngagement(); return e.unsetRouter(); } export async function handleURL(url: string): Promise { const e = await getGlobalEngagement(); return e.handleURL(url); } let plugin: AmplitudeEngagementPlugin | null = null; export function getPlugin( initOptions?: AmplitudeInitOptions ): AmplitudeEngagementPlugin { if (!plugin) { plugin = new AmplitudeEngagementPlugin(initOptions); } return plugin; }