1// Similar interface to the one used in expo modules.
2type CodedError = Error & { code?: string };
3
4let isErrorHandlingEnabled = true;
5let wasHit = false; // whether the original error handler was called
6
7const unavailableErrorPossibleSolutions = `Some possible solutions:
8- Make sure that the method is available on the current platform.
9- Make sure you're using the newest available version of this development client.
10- Make sure you're running a compatible version of your JavaScript code.
11- If you've installed a new library recently, you may need to make a new development client build.`;
12
13const moduleIsMissingPossibleSolutions = `Some possible solutions:
14- Make sure you're using the newest available version of this development client.
15- Make sure you're running a compatible version of your JavaScript code.
16- If you've installed a new library recently, you may need to make a new development client build.`;
17
18function customizeUnavailableMessage(error: CodedError) {
19  error.message += '\n\n' + unavailableErrorPossibleSolutions;
20}
21
22function customizeModuleIsMissingMessage(error: Error) {
23  error.message = `Your JavaScript code tried to access a native module that doesn't exist in this development client.
24
25${moduleIsMissingPossibleSolutions}`;
26}
27
28function customizeError(error: Error | CodedError) {
29  if ('code' in error) {
30    // It's a CodedError from expo modules
31    switch (error.code) {
32      case 'ERR_UNAVAILABLE': {
33        customizeUnavailableMessage(error);
34        break;
35      }
36    }
37  } else if (
38    error.message.includes('Native module cannot be null') || // RN 0.64 and below message
39    error.message.includes('`new NativeEventEmitter()` requires a non-null argument.') // RN 0.65+ message
40  ) {
41    customizeModuleIsMissingMessage(error);
42  }
43}
44
45function errorHandler(originalHandler, error, isFatal) {
46  if (error instanceof Error) {
47    // Suppresses `"main" has not been registered` error only if it was caused by a different error.
48    // Otherwise, we want to show it, cause the user may forget to call `AppRegistry.registerComponent`.
49    if (wasHit && error.message?.includes('has not been registered. This can happen if')) {
50      return;
51    }
52    customizeError(error);
53  }
54
55  wasHit = true;
56  originalHandler(error, isFatal);
57}
58
59export function createErrorHandler(originalHandler) {
60  return (error, isFatal) => {
61    if (isErrorHandlingEnabled) {
62      errorHandler(originalHandler, error, isFatal);
63      return;
64    }
65
66    originalHandler(error, isFatal);
67  };
68}
69
70export function disableErrorHandling() {
71  isErrorHandlingEnabled = false;
72}
73