18d307f52SEvan Baconimport { getExpoHomeDirectory, getUserStatePath } from '@expo/config/build/getUserState'; 28d307f52SEvan Baconimport JsonFile from '@expo/json-file'; 3b1f66971SLinus Unnebäckimport crypto from 'crypto'; 48d307f52SEvan Bacon 58d307f52SEvan Bacontype SessionData = { 68d307f52SEvan Bacon sessionSecret: string; 78d307f52SEvan Bacon // These fields are potentially used by Expo CLI. 88d307f52SEvan Bacon userId: string; 98d307f52SEvan Bacon username: string; 10*d88ac65dSlzkb currentConnection: 'Username-Password-Authentication' | 'Browser-Flow-Authentication'; 118d307f52SEvan Bacon}; 128d307f52SEvan Bacon 138d307f52SEvan Baconexport type UserSettingsData = { 148d307f52SEvan Bacon auth?: SessionData | null; 158d307f52SEvan Bacon ignoreBundledBinaries?: string[]; 168d307f52SEvan Bacon PATH?: string; 17384598e2SBrent Vatne /** Last development code signing ID used for `npx expo run:ios`. */ 188d307f52SEvan Bacon developmentCodeSigningId?: string; 198d307f52SEvan Bacon /** Unique user ID which is generated anonymously and can be cleared locally. */ 208d307f52SEvan Bacon uuid?: string; 218d307f52SEvan Bacon}; 228d307f52SEvan Bacon 238d307f52SEvan Bacon/** Return the user cache directory. */ 248d307f52SEvan Baconfunction getDirectory() { 258d307f52SEvan Bacon return getExpoHomeDirectory(); 268d307f52SEvan Bacon} 278d307f52SEvan Bacon 288d307f52SEvan Baconfunction getFilePath(): string { 298d307f52SEvan Bacon return getUserStatePath(); 308d307f52SEvan Bacon} 318d307f52SEvan Bacon 328d307f52SEvan Baconfunction userSettingsJsonFile(): JsonFile<UserSettingsData> { 338d307f52SEvan Bacon return new JsonFile<UserSettingsData>(getFilePath(), { 348d307f52SEvan Bacon ensureDir: true, 358d307f52SEvan Bacon jsonParseErrorDefault: {}, 368d307f52SEvan Bacon cantReadFileDefault: {}, 378d307f52SEvan Bacon }); 388d307f52SEvan Bacon} 398d307f52SEvan Bacon 408d307f52SEvan Baconasync function setSessionAsync(sessionData?: SessionData): Promise<void> { 418d307f52SEvan Bacon await UserSettings.setAsync('auth', sessionData, { 428d307f52SEvan Bacon default: {}, 438d307f52SEvan Bacon ensureDir: true, 448d307f52SEvan Bacon }); 458d307f52SEvan Bacon} 468d307f52SEvan Bacon 478d307f52SEvan Baconfunction getSession(): SessionData | null { 488d307f52SEvan Bacon try { 498d307f52SEvan Bacon return JsonFile.read<UserSettingsData>(getUserStatePath())?.auth ?? null; 508d307f52SEvan Bacon } catch (error: any) { 518d307f52SEvan Bacon if (error.code === 'ENOENT') { 528d307f52SEvan Bacon return null; 538d307f52SEvan Bacon } 548d307f52SEvan Bacon throw error; 558d307f52SEvan Bacon } 568d307f52SEvan Bacon} 578d307f52SEvan Bacon 588d307f52SEvan Baconfunction getAccessToken(): string | null { 598d307f52SEvan Bacon return process.env.EXPO_TOKEN ?? null; 608d307f52SEvan Bacon} 618d307f52SEvan Bacon 628d307f52SEvan Bacon// returns an anonymous, unique identifier for a user on the current computer 638d307f52SEvan Baconasync function getAnonymousIdentifierAsync(): Promise<string> { 648d307f52SEvan Bacon const settings = await userSettingsJsonFile(); 658d307f52SEvan Bacon let id = await settings.getAsync('uuid', null); 668d307f52SEvan Bacon 678d307f52SEvan Bacon if (!id) { 68b1f66971SLinus Unnebäck id = crypto.randomUUID(); 698d307f52SEvan Bacon await settings.setAsync('uuid', id); 708d307f52SEvan Bacon } 718d307f52SEvan Bacon 728d307f52SEvan Bacon return id; 738d307f52SEvan Bacon} 748d307f52SEvan Bacon 758d307f52SEvan Baconconst UserSettings = Object.assign(userSettingsJsonFile(), { 768d307f52SEvan Bacon getSession, 778d307f52SEvan Bacon setSessionAsync, 788d307f52SEvan Bacon getAccessToken, 798d307f52SEvan Bacon getDirectory, 808d307f52SEvan Bacon getFilePath, 818d307f52SEvan Bacon userSettingsJsonFile, 828d307f52SEvan Bacon getAnonymousIdentifierAsync, 838d307f52SEvan Bacon}); 848d307f52SEvan Bacon 858d307f52SEvan Baconexport default UserSettings; 86