1import NativeModulesProxy from './NativeModulesProxy';
2
3type ExpoObject = {
4  modules:
5    | undefined
6    | {
7        [key: string]: any;
8      };
9};
10
11declare global {
12  // eslint-disable-next-line no-var
13  var expo: ExpoObject | undefined;
14
15  /**
16   * @deprecated `global.ExpoModules` is deprecated, use `global.expo.modules` instead.
17   */
18  // eslint-disable-next-line no-var
19  var ExpoModules:
20    | undefined
21    | {
22        [key: string]: any;
23      };
24}
25
26/**
27 * Imports the native module registered with given name. In the first place it tries to load
28 * the module installed through the JSI host object and then falls back to the bridge proxy module.
29 * Notice that the modules loaded from the proxy may not support some features like synchronous functions.
30 *
31 * @param moduleName Name of the requested native module.
32 * @returns Object representing the native module.
33 * @throws Error when there is no native module with given name.
34 */
35export function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType {
36  const nativeModule = requireOptionalNativeModule<ModuleType>(moduleName);
37
38  if (!nativeModule) {
39    throw new Error(`Cannot find native module '${moduleName}'`);
40  }
41  return nativeModule;
42}
43
44/**
45 * Imports the native module registered with the given name. The same as `requireNativeModule`,
46 * but returns `null` when the module cannot be found instead of throwing an error.
47 *
48 * @param moduleName Name of the requested native module.
49 * @returns Object representing the native module or `null` when it cannot be found.
50 */
51export function requireOptionalNativeModule<ModuleType = any>(
52  moduleName: string
53): ModuleType | null {
54  return (
55    globalThis.expo?.modules?.[moduleName] ??
56    globalThis.ExpoModules?.[moduleName] ??
57    NativeModulesProxy[moduleName] ??
58    null
59  );
60}
61