From ed8213375654e1c9d6cd76bf48a1e5e86d697d45 Mon Sep 17 00:00:00 2001 From: Niamh Coleman <92738247+niamh-coleman@users.noreply.github.com> Date: Tue, 10 Nov 2026 15:32:04 +0000 Subject: [PATCH] Don't throw when the module is imported outside the native runtime Importing the package read native module properties at load time: IntercomEvents read its event names from IntercomEventEmitter, and setNeedsStatusBarAppearanceUpdate read its method from IntercomModule while building the Platform.select object. Outside the native runtime those modules are undefined, so the import threw. Expo Router's server export evaluates every route file in Node, which broke the iOS Release build of a default Expo app that imports the package in a route or layout. Both reads now happen safely, and the values in the app are unchanged. Co-Authored-By: Claude Opus 5.5 --- __tests__/importOutsideNativeRuntime.test.ts | 45 ++++++++++++++++++++ src/index.tsx | 14 +++--- 2 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 __tests__/importOutsideNativeRuntime.test.ts diff --git a/__tests__/importOutsideNativeRuntime.test.ts b/__tests__/importOutsideNativeRuntime.test.ts new file mode 100644 index 00000000..780a7b36 --- /dev/null +++ b/__tests__/importOutsideNativeRuntime.test.ts @@ -0,0 +1,45 @@ +describe('importing the module', () => { + test('does not throw without the native modules', () => { + jest.isolateModules(() => { + const { NativeModules } = require('react-native'); + expect(NativeModules.IntercomEventEmitter).toBeUndefined(); + expect(NativeModules.IntercomModule).toBeUndefined(); + + const { IntercomEvents } = require('../src'); + + expect(IntercomEvents.IntercomUnreadCountDidChange).toBeUndefined(); + }); + }); + + test('reads event names and methods from the native modules', () => { + jest.isolateModules(() => { + jest.doMock('../src/nativeModules', () => ({ + IntercomModule: { + setNeedsStatusBarAppearanceUpdate: jest.fn(() => + Promise.resolve(true) + ), + }, + IntercomEventEmitter: { + UNREAD_COUNT_CHANGE_NOTIFICATION: 'unread', + WINDOW_DID_HIDE_NOTIFICATION: 'hide', + WINDOW_DID_SHOW_NOTIFICATION: 'show', + }, + })); + const { IntercomModule } = require('../src/nativeModules'); + const { default: Intercom, IntercomEvents } = require('../src'); + + expect(IntercomEvents).toEqual({ + IntercomUnreadCountDidChange: 'unread', + IntercomWindowDidHide: 'hide', + IntercomWindowDidShow: 'show', + IntercomHelpCenterWindowDidShow: 'show', + IntercomHelpCenterWindowDidHide: 'hide', + }); + + Intercom.setNeedsStatusBarAppearanceUpdate(); + expect( + IntercomModule.setNeedsStatusBarAppearanceUpdate + ).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/index.tsx b/src/index.tsx index 046a2e22..02c45594 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -49,15 +49,17 @@ export enum ThemeMode { type ThemeModeType = keyof typeof ThemeMode; +// Optional so that importing outside the native runtime, such as an Expo Router +// server export, doesn't throw. export const IntercomEvents = { IntercomUnreadCountDidChange: - IntercomEventEmitter.UNREAD_COUNT_CHANGE_NOTIFICATION, - IntercomWindowDidHide: IntercomEventEmitter.WINDOW_DID_HIDE_NOTIFICATION, - IntercomWindowDidShow: IntercomEventEmitter.WINDOW_DID_SHOW_NOTIFICATION, + IntercomEventEmitter?.UNREAD_COUNT_CHANGE_NOTIFICATION, + IntercomWindowDidHide: IntercomEventEmitter?.WINDOW_DID_HIDE_NOTIFICATION, + IntercomWindowDidShow: IntercomEventEmitter?.WINDOW_DID_SHOW_NOTIFICATION, IntercomHelpCenterWindowDidShow: - IntercomEventEmitter.WINDOW_DID_SHOW_NOTIFICATION, + IntercomEventEmitter?.WINDOW_DID_SHOW_NOTIFICATION, IntercomHelpCenterWindowDidHide: - IntercomEventEmitter.WINDOW_DID_HIDE_NOTIFICATION, + IntercomEventEmitter?.WINDOW_DID_HIDE_NOTIFICATION, }; export enum Space { @@ -425,7 +427,7 @@ const Intercom: IntercomType = { IntercomModule.setLauncherVisibility(visibility), setNeedsStatusBarAppearanceUpdate: Platform.select({ - ios: IntercomModule.setNeedsStatusBarAppearanceUpdate, + ios: () => IntercomModule.setNeedsStatusBarAppearanceUpdate(), default: async () => true, }),