18d307f52SEvan Baconimport { createCachedFetch } from './rest/client';
2*8a424bebSJames Ideimport { CommandError } from '../utils/errors';
38d307f52SEvan Bacon
48d307f52SEvan Baconinterface NativeModule {
58d307f52SEvan Bacon  npmPackage: string;
68d307f52SEvan Bacon  versionRange: string;
78d307f52SEvan Bacon}
88d307f52SEvan Bacontype BundledNativeModuleList = NativeModule[];
98d307f52SEvan Bacon
108d307f52SEvan Baconexport type BundledNativeModules = Record<string, string>;
118d307f52SEvan Bacon
128d307f52SEvan Bacon/**
138d307f52SEvan Bacon * The endpoint returns the list of bundled native modules for a given SDK version.
148d307f52SEvan Bacon * The data is populated by the `et sync-bundled-native-modules` script from expo/expo repo.
158d307f52SEvan Bacon * See the code for more details:
168d307f52SEvan Bacon * https://github.com/expo/expo/blob/main/tools/src/commands/SyncBundledNativeModules.ts
178d307f52SEvan Bacon *
188d307f52SEvan Bacon * Example result:
198d307f52SEvan Bacon * [
208d307f52SEvan Bacon *   {
218d307f52SEvan Bacon *     id: "79285187-e5c4-47f7-b6a9-664f5d16f0db",
228d307f52SEvan Bacon *     sdkVersion: "41.0.0",
23e05af9e1SBrent Vatne *     npmPackage: "expo-camera",
248d307f52SEvan Bacon *     versionRange: "~10.1.0",
258d307f52SEvan Bacon *     createdAt: "2021-04-29T09:34:32.825Z",
268d307f52SEvan Bacon *     updatedAt: "2021-04-29T09:34:32.825Z"
278d307f52SEvan Bacon *   },
288d307f52SEvan Bacon *   ...
298d307f52SEvan Bacon * ]
308d307f52SEvan Bacon */
318d307f52SEvan Baconexport async function getNativeModuleVersionsAsync(
328d307f52SEvan Bacon  sdkVersion: string
338d307f52SEvan Bacon): Promise<BundledNativeModules> {
348d307f52SEvan Bacon  const fetchAsync = createCachedFetch({
358d307f52SEvan Bacon    cacheDirectory: 'native-modules-cache',
368d307f52SEvan Bacon    // 1 minute cache
378d307f52SEvan Bacon    ttl: 1000 * 60 * 1,
388d307f52SEvan Bacon  });
398d307f52SEvan Bacon  const results = await fetchAsync(`sdks/${sdkVersion}/native-modules`);
408d307f52SEvan Bacon  if (!results.ok) {
418d307f52SEvan Bacon    throw new CommandError(
428d307f52SEvan Bacon      'API',
438d307f52SEvan Bacon      `Unexpected response when fetching version info from Expo servers: ${results.statusText}.`
448d307f52SEvan Bacon    );
458d307f52SEvan Bacon  }
468d307f52SEvan Bacon  const { data } = await results.json();
478d307f52SEvan Bacon  if (!data.length) {
488d307f52SEvan Bacon    throw new CommandError('VERSIONS', 'The bundled native module list from the Expo API is empty');
498d307f52SEvan Bacon  }
508d307f52SEvan Bacon  return fromBundledNativeModuleList(data);
518d307f52SEvan Bacon}
528d307f52SEvan Bacon
538d307f52SEvan Baconfunction fromBundledNativeModuleList(list: BundledNativeModuleList): BundledNativeModules {
548d307f52SEvan Bacon  return list.reduce((acc, i) => {
558d307f52SEvan Bacon    acc[i.npmPackage] = i.versionRange;
568d307f52SEvan Bacon    return acc;
578d307f52SEvan Bacon  }, {} as BundledNativeModules);
588d307f52SEvan Bacon}
59