1import JsonFile from '@expo/json-file';
2import chalk from 'chalk';
3import resolveFrom from 'resolve-from';
4
5import { getNativeModuleVersionsAsync } from '../../../api/getNativeModuleVersions';
6import { APISettings } from '../../../api/settings';
7import * as Log from '../../../log';
8import { CommandError } from '../../../utils/errors';
9
10export type BundledNativeModules = Record<string, string>;
11
12/**
13 * Gets the bundledNativeModules.json for a given SDK version:
14 * - Tries to fetch the data from the /sdks/:sdkVersion/native-modules API endpoint.
15 * - If the data is missing on the server (it can happen for SDKs that are yet fully released)
16 *    or there's a downtime, reads the local .json file from the "expo" package.
17 * - For UNVERSIONED, returns the local .json file contents.
18 */
19export async function getVersionedNativeModulesAsync(
20  projectRoot: string,
21  sdkVersion: string
22): Promise<BundledNativeModules> {
23  if (sdkVersion !== 'UNVERSIONED' && !APISettings.isOffline) {
24    try {
25      Log.debug('Fetching bundled native modules from the server...');
26      return await getNativeModuleVersionsAsync(sdkVersion);
27    } catch {
28      Log.warn(
29        chalk`Unable to reach Expo servers. Falling back to using the cached dependency map ({bold bundledNativeModules.json}) from the package "{bold expo}" installed in your project.`
30      );
31    }
32  }
33
34  Log.debug('Fetching bundled native modules from the local JSON file...');
35  return await getBundledNativeModulesAsync(projectRoot);
36}
37
38/**
39 * Get the legacy static `bundledNativeModules.json` file
40 * that's shipped with the version of `expo` that the project has installed.
41 */
42async function getBundledNativeModulesAsync(projectRoot: string): Promise<BundledNativeModules> {
43  // TODO: Revisit now that this code is in the `expo` package.
44  const bundledNativeModulesPath = resolveFrom.silent(
45    projectRoot,
46    'expo/bundledNativeModules.json'
47  );
48  if (!bundledNativeModulesPath) {
49    Log.log();
50    throw new CommandError(
51      chalk`The dependency map {bold expo/bundledNativeModules.json} cannot be found, please ensure you have the package "{bold expo}" installed in your project.`
52    );
53  }
54  return await JsonFile.readAsync<BundledNativeModules>(bundledNativeModulesPath);
55}
56