1import { getExpoHomeDirectory, getUserStatePath } from '@expo/config/build/getUserState';
2import JsonFile from '@expo/json-file';
3import crypto from 'crypto';
4
5type SessionData = {
6  sessionSecret: string;
7  // These fields are potentially used by Expo CLI.
8  userId: string;
9  username: string;
10  currentConnection: 'Username-Password-Authentication';
11};
12
13export type UserSettingsData = {
14  auth?: SessionData | null;
15  ignoreBundledBinaries?: string[];
16  PATH?: string;
17  /** Last development code signing ID used for `expo run:ios`. */
18  developmentCodeSigningId?: string;
19  /** Unique user ID which is generated anonymously and can be cleared locally. */
20  uuid?: string;
21};
22
23/** Return the user cache directory. */
24function getDirectory() {
25  return getExpoHomeDirectory();
26}
27
28function getFilePath(): string {
29  return getUserStatePath();
30}
31
32function userSettingsJsonFile(): JsonFile<UserSettingsData> {
33  return new JsonFile<UserSettingsData>(getFilePath(), {
34    ensureDir: true,
35    jsonParseErrorDefault: {},
36    cantReadFileDefault: {},
37  });
38}
39
40async function setSessionAsync(sessionData?: SessionData): Promise<void> {
41  await UserSettings.setAsync('auth', sessionData, {
42    default: {},
43    ensureDir: true,
44  });
45}
46
47function getSession(): SessionData | null {
48  try {
49    return JsonFile.read<UserSettingsData>(getUserStatePath())?.auth ?? null;
50  } catch (error: any) {
51    if (error.code === 'ENOENT') {
52      return null;
53    }
54    throw error;
55  }
56}
57
58function getAccessToken(): string | null {
59  return process.env.EXPO_TOKEN ?? null;
60}
61
62// returns an anonymous, unique identifier for a user on the current computer
63async function getAnonymousIdentifierAsync(): Promise<string> {
64  const settings = await userSettingsJsonFile();
65  let id = await settings.getAsync('uuid', null);
66
67  if (!id) {
68    id = crypto.randomUUID();
69    await settings.setAsync('uuid', id);
70  }
71
72  return id;
73}
74
75const UserSettings = Object.assign(userSettingsJsonFile(), {
76  getSession,
77  setSessionAsync,
78  getAccessToken,
79  getDirectory,
80  getFilePath,
81  userSettingsJsonFile,
82  getAnonymousIdentifierAsync,
83});
84
85export default UserSettings;
86