1import RudderAnalytics from '@expo/rudder-sdk-node'; 2import os from 'os'; 3import { v4 as uuidv4 } from 'uuid'; 4 5import UserSettings from '../../api/user/UserSettings'; 6import { EXPO_LOCAL, EXPO_STAGING, EXPO_NO_TELEMETRY } from '../env'; 7 8const PLATFORM_TO_ANALYTICS_PLATFORM: { [platform: string]: string } = { 9 darwin: 'Mac', 10 win32: 'Windows', 11 linux: 'Linux', 12}; 13 14let client: RudderAnalytics | null = null; 15let identified = false; 16let identifyData: { 17 userId: string; 18 deviceId: string; 19 traits: Record<string, any>; 20} | null = null; 21 22function getClient(): RudderAnalytics { 23 if (client) { 24 return client; 25 } 26 27 client = new RudderAnalytics( 28 EXPO_STAGING || EXPO_LOCAL ? '24TKICqYKilXM480mA7ktgVDdea' : '24TKR7CQAaGgIrLTgu3Fp4OdOkI', // expo unified 29 'https://cdp.expo.dev/v1/batch', 30 { 31 flushInterval: 300, 32 } 33 ); 34 35 // Install flush on exit... 36 process.on('SIGINT', () => client?.flush?.()); 37 process.on('SIGTERM', () => client?.flush?.()); 38 39 return client; 40} 41 42export async function setUserDataAsync(userId: string, traits: Record<string, any>): Promise<void> { 43 if (EXPO_NO_TELEMETRY) { 44 return; 45 } 46 47 const deviceId = await UserSettings.getAnonymousIdentifierAsync(); 48 49 identifyData = { 50 userId, 51 deviceId, 52 traits, 53 }; 54 55 ensureIdentified(); 56} 57 58export function logEvent( 59 event: // TODO: revise 60 | 'action' 61 | 'Open Url on Device' 62 | 'Start Project' 63 | 'Serve Manifest' 64 | 'dev client start command' 65 | 'Serve Expo Updates Manifest', 66 properties: Record<string, any> = {} 67): void { 68 if (EXPO_NO_TELEMETRY) { 69 return; 70 } 71 ensureIdentified(); 72 73 const { userId, deviceId } = identifyData ?? {}; 74 const commonEventProperties = { source_version: process.env.__EXPO_VERSION, source: 'expo' }; 75 76 const identity = { userId: userId ?? undefined, anonymousId: deviceId ?? uuidv4() }; 77 getClient().track({ 78 event, 79 properties: { ...properties, ...commonEventProperties }, 80 ...identity, 81 context: getContext(), 82 }); 83} 84 85function ensureIdentified(): void { 86 if (EXPO_NO_TELEMETRY || identified || !identifyData) { 87 return; 88 } 89 90 getClient().identify({ 91 userId: identifyData.userId, 92 anonymousId: identifyData.deviceId, 93 traits: identifyData.traits, 94 }); 95 identified = true; 96} 97 98function getContext(): Record<string, any> { 99 const platform = PLATFORM_TO_ANALYTICS_PLATFORM[os.platform()] || os.platform(); 100 return { 101 os: { name: platform, version: os.release() }, 102 device: { type: platform, model: platform }, 103 app: { name: 'expo', version: process.env.__EXPO_VERSION }, 104 }; 105} 106