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 getBundledNativeModulesAsync(
20  projectRoot: string,
21  sdkVersion: string
22): Promise<BundledNativeModules> {
23  if (sdkVersion === 'UNVERSIONED' || APISettings.isOffline) {
24    return await getBundledNativeModulesFromExpoPackageAsync(projectRoot);
25  } else {
26    try {
27      return await getNativeModuleVersionsAsync(sdkVersion);
28    } catch {
29      Log.warn(
30        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.`
31      );
32      return await getBundledNativeModulesFromExpoPackageAsync(projectRoot);
33    }
34  }
35}
36
37/**
38 * Get the legacy static `bundledNativeModules.json` file
39 * that's shipped with the version of `expo` that the project has installed.
40 */
41async function getBundledNativeModulesFromExpoPackageAsync(
42  projectRoot: string
43): Promise<BundledNativeModules> {
44  // TODO: Revisit now that this code is in the `expo` package.
45  const bundledNativeModulesPath = resolveFrom.silent(
46    projectRoot,
47    'expo/bundledNativeModules.json'
48  );
49  if (!bundledNativeModulesPath) {
50    Log.log();
51    throw new CommandError(
52      `The dependency map ${chalk.bold(
53        `expo/bundledNativeModules.json`
54      )} cannot be found, please ensure you have the package "${chalk.bold`expo`}" installed in your project.\n`
55    );
56  }
57  return await JsonFile.readAsync<BundledNativeModules>(bundledNativeModulesPath);
58}
59