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        `Unable to reach Expo servers. Falling back to using the cached dependency map (${chalk.bold(
31          'bundledNativeModules.json'
32        )}) from the package "${chalk.bold`expo`}" installed in your project.`
33      );
34      return await getBundledNativeModulesFromExpoPackageAsync(projectRoot);
35    }
36  }
37}
38
39/**
40 * Get the legacy static `bundledNativeModules.json` file
41 * that's shipped with the version of `expo` that the project has installed.
42 */
43async function getBundledNativeModulesFromExpoPackageAsync(
44  projectRoot: string
45): Promise<BundledNativeModules> {
46  // TODO: Revisit now that this code is in the `expo` package.
47  const bundledNativeModulesPath = resolveFrom.silent(
48    projectRoot,
49    'expo/bundledNativeModules.json'
50  );
51  if (!bundledNativeModulesPath) {
52    Log.log();
53    throw new CommandError(
54      `The dependency map ${chalk.bold(
55        `expo/bundledNativeModules.json`
56      )} cannot be found, please ensure you have the package "${chalk.bold`expo`}" installed in your project.\n`
57    );
58  }
59  return await JsonFile.readAsync<BundledNativeModules>(bundledNativeModulesPath);
60}
61