From b835b41148896c5c1eb4df82d8bde2304480299d Mon Sep 17 00:00:00 2001 From: Srirang Kalantri Date: Mon, 31 Aug 2026 15:11:45 +0530 Subject: [PATCH 1/4] fix: web build issue --- package.json | 30 ++++++++++++++++++++++- src/file-system/NativeMxFileSystem.ts | 29 +++++++++++++++++----- src/file-system/index.ts | 17 ++++++++++++- src/index.ts | 1 + src/native-modules/index.ts | 8 ++++++ src/navigation-mode/NativeMxNavigation.ts | 26 +++++++++++++++++--- src/navigation-mode/index.ts | 10 ++++++-- 7 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 src/native-modules/index.ts diff --git a/package.json b/package.json index f9d6089..b8274dc 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,40 @@ "description": "Mendix native mobile package", "main": "./lib/module/index.js", "types": "./lib/typescript/src/index.d.ts", + "typesVersions": { + "*": { + "file-system": [ + "lib/typescript/src/file-system/index.d.ts" + ], + "native-modules": [ + "lib/typescript/src/native-modules/index.d.ts" + ], + "navigation-mode": [ + "lib/typescript/src/navigation-mode/index.d.ts" + ] + } + }, "exports": { ".": { "source": "./src/index.ts", "types": "./lib/typescript/src/index.d.ts", "default": "./lib/module/index.js" }, + "./file-system": { + "source": "./src/file-system/index.ts", + "types": "./lib/typescript/src/file-system/index.d.ts", + "default": "./lib/module/file-system/index.js" + }, + "./native-modules": { + "source": "./src/native-modules/index.ts", + "types": "./lib/typescript/src/native-modules/index.d.ts", + "default": "./lib/module/native-modules/index.js" + }, + "./navigation-mode": { + "source": "./src/navigation-mode/index.ts", + "types": "./lib/typescript/src/navigation-mode/index.d.ts", + "default": "./lib/module/navigation-mode/index.js" + }, "./package.json": "./package.json" }, "files": [ @@ -89,7 +117,7 @@ "typescript": "5.9.3" }, "peerDependencies": { - "@op-engineering/op-sqlite": "*", + "@op-engineering/op-sqlite": "15.2.5", "@react-native-async-storage/async-storage": "*", "react": "*", "react-native": "*", diff --git a/src/file-system/NativeMxFileSystem.ts b/src/file-system/NativeMxFileSystem.ts index 6845bc4..f0586f9 100644 --- a/src/file-system/NativeMxFileSystem.ts +++ b/src/file-system/NativeMxFileSystem.ts @@ -1,8 +1,9 @@ -import { - TurboModuleRegistry, - type TurboModule, - type CodegenTypes, -} from 'react-native'; +import type { TurboModule, CodegenTypes } from 'react-native'; + +const TurboModuleRegistry = + require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { + getEnforcing: (name: string) => T; + }; type BlobData = { blobId: string; @@ -34,6 +35,22 @@ export interface Spec extends TurboModule { setEncryptionEnabled(enabled: boolean): void; } -export default TurboModuleRegistry.getEnforcing('MxFileSystem'); +let cachedModule: Spec | undefined; +const getModule = (): Spec => { + if (!cachedModule) { + cachedModule = TurboModuleRegistry.getEnforcing('MxFileSystem'); + } + return cachedModule; +}; + +// Resolves the native module lazily (on first property access) instead of at import time, +// so requiring this file on web, where TurboModuleRegistry is stubbed out, never crashes. +const NativeMxFileSystem = new Proxy({} as Spec, { + get(_target, prop) { + return getModule()[prop as keyof Spec]; + }, +}); + +export default NativeMxFileSystem; export type { BlobData, FsConstants }; diff --git a/src/file-system/index.ts b/src/file-system/index.ts index e9704b9..14c92f1 100644 --- a/src/file-system/index.ts +++ b/src/file-system/index.ts @@ -44,4 +44,19 @@ const cast = (value: unknown): T | undefined => { return value as T; }; -export const NativeFileSystem = initFs(); +type Fs = ReturnType; +let cachedFs: Fs | undefined; +const getFs = (): Fs => { + if (!cachedFs) { + cachedFs = initFs(); + } + return cachedFs; +}; + +// Deferred so importing this module never touches the native file system module +// (e.g. on web, where it doesn't exist) until a consumer actually reads a property. +export const NativeFileSystem = new Proxy({} as Fs, { + get(_target, prop) { + return getFs()[prop as keyof Fs]; + }, +}); diff --git a/src/index.ts b/src/index.ts index c24aba9..aa96ec2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,3 +10,4 @@ export * from './encrypted-storage'; export * from './error'; export * from './file-system'; export * from './navigation-mode'; +export * from './native-modules'; diff --git a/src/native-modules/index.ts b/src/native-modules/index.ts new file mode 100644 index 0000000..c1c2b61 --- /dev/null +++ b/src/native-modules/index.ts @@ -0,0 +1,8 @@ +const TurboModuleRegistry = + require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { + get: >(name: string) => T | null; + }; + +export const getNativeModule = >( + name: string +): T | null => TurboModuleRegistry.get(name); diff --git a/src/navigation-mode/NativeMxNavigation.ts b/src/navigation-mode/NativeMxNavigation.ts index eaa3dc3..bebaa69 100644 --- a/src/navigation-mode/NativeMxNavigation.ts +++ b/src/navigation-mode/NativeMxNavigation.ts @@ -1,9 +1,29 @@ -import { TurboModuleRegistry, type TurboModule } from 'react-native'; -import type { CodegenTypes } from 'react-native'; +import type { TurboModule, CodegenTypes } from 'react-native'; + +const TurboModuleRegistry = + require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { + getEnforcing: (name: string) => T; + }; export interface Spec extends TurboModule { isNavigationBarActive(): boolean; getNavigationBarHeight(): CodegenTypes.Double; } -export default TurboModuleRegistry.getEnforcing('MxNavigation'); +let cachedModule: Spec | undefined; +const getModule = (): Spec => { + if (!cachedModule) { + cachedModule = TurboModuleRegistry.getEnforcing('MxNavigation'); + } + return cachedModule; +}; + +// Resolves the native module lazily (on first property access) instead of at import time, +// so requiring this file on web, where TurboModuleRegistry is stubbed out, never crashes. +const NativeMxNavigation = new Proxy({} as Spec, { + get(_target, prop) { + return getModule()[prop as keyof Spec]; + }, +}); + +export default NativeMxNavigation; diff --git a/src/navigation-mode/index.ts b/src/navigation-mode/index.ts index 04209dd..b138213 100644 --- a/src/navigation-mode/index.ts +++ b/src/navigation-mode/index.ts @@ -1,6 +1,12 @@ import NativeMxNavigation from './NativeMxNavigation'; +// Getters keep this lazy: reading .height/.isActive is what triggers the native call, +// not importing this module. export const AndroidNavigationBar = { - height: NativeMxNavigation.getNavigationBarHeight(), - isActive: NativeMxNavigation.isNavigationBarActive(), + get height() { + return NativeMxNavigation.getNavigationBarHeight(); + }, + get isActive() { + return NativeMxNavigation.isNavigationBarActive(); + }, }; From 2a812d12f7b2b461adea75337911c3dc1fabe04d Mon Sep 17 00:00:00 2001 From: Srirang Kalantri Date: Mon, 31 Aug 2026 15:15:22 +0530 Subject: [PATCH 2/4] chore: yarn.lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 36bfc46..3eeb43b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9264,7 +9264,7 @@ __metadata: turbo: "npm:2.8.21" typescript: "npm:5.9.3" peerDependencies: - "@op-engineering/op-sqlite": "*" + "@op-engineering/op-sqlite": 15.2.5 "@react-native-async-storage/async-storage": "*" react: "*" react-native: "*" From 89fc8e95c19a2d1a7067e4bede3b1183627fd6a2 Mon Sep 17 00:00:00 2001 From: Srirang Kalantri Date: Tue, 1 Sep 2026 16:02:48 +0530 Subject: [PATCH 3/4] fix: scope modules --- package.json | 32 +++++++++++++++++++++++++++++++ src/firebase-messaging/index.ts | 18 +++++++++++++++++ src/image-picker/index.ts | 19 ++++++++++++++++++ src/index.ts | 4 ++++ src/notifee/index.ts | 7 +++++++ src/schedule-exact-alarm/index.ts | 14 ++++++++++++++ 6 files changed, 94 insertions(+) create mode 100644 src/firebase-messaging/index.ts create mode 100644 src/image-picker/index.ts create mode 100644 src/notifee/index.ts create mode 100644 src/schedule-exact-alarm/index.ts diff --git a/package.json b/package.json index b8274dc..43119c5 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,18 @@ ], "navigation-mode": [ "lib/typescript/src/navigation-mode/index.d.ts" + ], + "image-picker": [ + "lib/typescript/src/image-picker/index.d.ts" + ], + "notifee": [ + "lib/typescript/src/notifee/index.d.ts" + ], + "firebase-messaging": [ + "lib/typescript/src/firebase-messaging/index.d.ts" + ], + "schedule-exact-alarm": [ + "lib/typescript/src/schedule-exact-alarm/index.d.ts" ] } }, @@ -38,6 +50,26 @@ "types": "./lib/typescript/src/navigation-mode/index.d.ts", "default": "./lib/module/navigation-mode/index.js" }, + "./image-picker": { + "source": "./src/image-picker/index.ts", + "types": "./lib/typescript/src/image-picker/index.d.ts", + "default": "./lib/module/image-picker/index.js" + }, + "./notifee": { + "source": "./src/notifee/index.ts", + "types": "./lib/typescript/src/notifee/index.d.ts", + "default": "./lib/module/notifee/index.js" + }, + "./firebase-messaging": { + "source": "./src/firebase-messaging/index.ts", + "types": "./lib/typescript/src/firebase-messaging/index.d.ts", + "default": "./lib/module/firebase-messaging/index.js" + }, + "./schedule-exact-alarm": { + "source": "./src/schedule-exact-alarm/index.ts", + "types": "./lib/typescript/src/schedule-exact-alarm/index.d.ts", + "default": "./lib/module/schedule-exact-alarm/index.js" + }, "./package.json": "./package.json" }, "files": [ diff --git a/src/firebase-messaging/index.ts b/src/firebase-messaging/index.ts new file mode 100644 index 0000000..5e350fc --- /dev/null +++ b/src/firebase-messaging/index.ts @@ -0,0 +1,18 @@ +import { getNativeModule } from '../native-modules'; + +interface FirebaseMessagingModuleSpec { + hasPermission(): Promise; +} + +export const RNFBMessagingModule = { + get isAvailable(): boolean { + return !!getNativeModule( + 'RNFBMessagingModule' + ); + }, + hasPermission(): Promise { + return getNativeModule( + 'RNFBMessagingModule' + )!.hasPermission(); + }, +}; diff --git a/src/image-picker/index.ts b/src/image-picker/index.ts new file mode 100644 index 0000000..67c8a56 --- /dev/null +++ b/src/image-picker/index.ts @@ -0,0 +1,19 @@ +import { getNativeModule } from '../native-modules'; + +interface ImagePickerManagerSpec { + showImagePicker?: unknown; +} + +export const ImagePickerManager = { + /** + * `react-native-image-picker` v3 dropped the legacy action-sheet API. Its native module is + * only present pre-v3; use that as a version marker instead of duplicating this check at + * every call site. + */ + get version(): 2 | 4 { + return getNativeModule('ImagePickerManager') + ?.showImagePicker + ? 2 + : 4; + }, +}; diff --git a/src/index.ts b/src/index.ts index aa96ec2..bb4ebcd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,4 +10,8 @@ export * from './encrypted-storage'; export * from './error'; export * from './file-system'; export * from './navigation-mode'; +export * from './image-picker'; +export * from './notifee'; +export * from './firebase-messaging'; +export * from './schedule-exact-alarm'; export * from './native-modules'; diff --git a/src/notifee/index.ts b/src/notifee/index.ts new file mode 100644 index 0000000..acae0d6 --- /dev/null +++ b/src/notifee/index.ts @@ -0,0 +1,7 @@ +import { getNativeModule } from '../native-modules'; + +export const NotifeeApiModule = { + get isAvailable(): boolean { + return !!getNativeModule('NotifeeApiModule'); + }, +}; diff --git a/src/schedule-exact-alarm/index.ts b/src/schedule-exact-alarm/index.ts new file mode 100644 index 0000000..4c8554a --- /dev/null +++ b/src/schedule-exact-alarm/index.ts @@ -0,0 +1,14 @@ +import { getNativeModule } from '../native-modules'; + +interface ScheduleEASpec { + checkPermission(callback: (isEnabled: boolean) => void): void; +} + +export const ScheduleEA = { + get isAvailable(): boolean { + return !!getNativeModule('ScheduleEA'); + }, + checkPermission(callback: (isEnabled: boolean) => void): void { + getNativeModule('ScheduleEA')!.checkPermission(callback); + }, +}; From 0ffadb4e1ed6893afdcdafbd24918018b8b7173f Mon Sep 17 00:00:00 2001 From: Srirang Kalantri Date: Thu, 3 Sep 2026 12:29:43 +0530 Subject: [PATCH 4/4] fix: remove module scope from mendix-native --- package.json | 34 +---------------------- src/file-system/NativeMxFileSystem.ts | 6 +--- src/firebase-messaging/index.ts | 18 ------------ src/image-picker/index.ts | 19 ------------- src/index.ts | 4 --- src/native-modules/index.ts | 7 ++--- src/navigation-mode/NativeMxNavigation.ts | 6 +--- src/notifee/index.ts | 7 ----- src/schedule-exact-alarm/index.ts | 14 ---------- yarn.lock | 2 +- 10 files changed, 6 insertions(+), 111 deletions(-) delete mode 100644 src/firebase-messaging/index.ts delete mode 100644 src/image-picker/index.ts delete mode 100644 src/notifee/index.ts delete mode 100644 src/schedule-exact-alarm/index.ts diff --git a/package.json b/package.json index 43119c5..bd546dd 100644 --- a/package.json +++ b/package.json @@ -14,18 +14,6 @@ ], "navigation-mode": [ "lib/typescript/src/navigation-mode/index.d.ts" - ], - "image-picker": [ - "lib/typescript/src/image-picker/index.d.ts" - ], - "notifee": [ - "lib/typescript/src/notifee/index.d.ts" - ], - "firebase-messaging": [ - "lib/typescript/src/firebase-messaging/index.d.ts" - ], - "schedule-exact-alarm": [ - "lib/typescript/src/schedule-exact-alarm/index.d.ts" ] } }, @@ -50,26 +38,6 @@ "types": "./lib/typescript/src/navigation-mode/index.d.ts", "default": "./lib/module/navigation-mode/index.js" }, - "./image-picker": { - "source": "./src/image-picker/index.ts", - "types": "./lib/typescript/src/image-picker/index.d.ts", - "default": "./lib/module/image-picker/index.js" - }, - "./notifee": { - "source": "./src/notifee/index.ts", - "types": "./lib/typescript/src/notifee/index.d.ts", - "default": "./lib/module/notifee/index.js" - }, - "./firebase-messaging": { - "source": "./src/firebase-messaging/index.ts", - "types": "./lib/typescript/src/firebase-messaging/index.d.ts", - "default": "./lib/module/firebase-messaging/index.js" - }, - "./schedule-exact-alarm": { - "source": "./src/schedule-exact-alarm/index.ts", - "types": "./lib/typescript/src/schedule-exact-alarm/index.d.ts", - "default": "./lib/module/schedule-exact-alarm/index.js" - }, "./package.json": "./package.json" }, "files": [ @@ -149,7 +117,7 @@ "typescript": "5.9.3" }, "peerDependencies": { - "@op-engineering/op-sqlite": "15.2.5", + "@op-engineering/op-sqlite": "*", "@react-native-async-storage/async-storage": "*", "react": "*", "react-native": "*", diff --git a/src/file-system/NativeMxFileSystem.ts b/src/file-system/NativeMxFileSystem.ts index f0586f9..a9920a2 100644 --- a/src/file-system/NativeMxFileSystem.ts +++ b/src/file-system/NativeMxFileSystem.ts @@ -1,10 +1,6 @@ +import { TurboModuleRegistry } from 'react-native'; import type { TurboModule, CodegenTypes } from 'react-native'; -const TurboModuleRegistry = - require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { - getEnforcing: (name: string) => T; - }; - type BlobData = { blobId: string; offset: number; diff --git a/src/firebase-messaging/index.ts b/src/firebase-messaging/index.ts deleted file mode 100644 index 5e350fc..0000000 --- a/src/firebase-messaging/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getNativeModule } from '../native-modules'; - -interface FirebaseMessagingModuleSpec { - hasPermission(): Promise; -} - -export const RNFBMessagingModule = { - get isAvailable(): boolean { - return !!getNativeModule( - 'RNFBMessagingModule' - ); - }, - hasPermission(): Promise { - return getNativeModule( - 'RNFBMessagingModule' - )!.hasPermission(); - }, -}; diff --git a/src/image-picker/index.ts b/src/image-picker/index.ts deleted file mode 100644 index 67c8a56..0000000 --- a/src/image-picker/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { getNativeModule } from '../native-modules'; - -interface ImagePickerManagerSpec { - showImagePicker?: unknown; -} - -export const ImagePickerManager = { - /** - * `react-native-image-picker` v3 dropped the legacy action-sheet API. Its native module is - * only present pre-v3; use that as a version marker instead of duplicating this check at - * every call site. - */ - get version(): 2 | 4 { - return getNativeModule('ImagePickerManager') - ?.showImagePicker - ? 2 - : 4; - }, -}; diff --git a/src/index.ts b/src/index.ts index bb4ebcd..aa96ec2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,8 +10,4 @@ export * from './encrypted-storage'; export * from './error'; export * from './file-system'; export * from './navigation-mode'; -export * from './image-picker'; -export * from './notifee'; -export * from './firebase-messaging'; -export * from './schedule-exact-alarm'; export * from './native-modules'; diff --git a/src/native-modules/index.ts b/src/native-modules/index.ts index c1c2b61..b9822fc 100644 --- a/src/native-modules/index.ts +++ b/src/native-modules/index.ts @@ -1,8 +1,5 @@ -const TurboModuleRegistry = - require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { - get: >(name: string) => T | null; - }; +import { TurboModuleRegistry } from 'react-native'; export const getNativeModule = >( name: string -): T | null => TurboModuleRegistry.get(name); +): T | null => TurboModuleRegistry.get(name) ?? null; diff --git a/src/navigation-mode/NativeMxNavigation.ts b/src/navigation-mode/NativeMxNavigation.ts index bebaa69..4d6b2a2 100644 --- a/src/navigation-mode/NativeMxNavigation.ts +++ b/src/navigation-mode/NativeMxNavigation.ts @@ -1,10 +1,6 @@ +import { TurboModuleRegistry } from 'react-native'; import type { TurboModule, CodegenTypes } from 'react-native'; -const TurboModuleRegistry = - require('react-native/Libraries/TurboModule/TurboModuleRegistry') as { - getEnforcing: (name: string) => T; - }; - export interface Spec extends TurboModule { isNavigationBarActive(): boolean; getNavigationBarHeight(): CodegenTypes.Double; diff --git a/src/notifee/index.ts b/src/notifee/index.ts deleted file mode 100644 index acae0d6..0000000 --- a/src/notifee/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getNativeModule } from '../native-modules'; - -export const NotifeeApiModule = { - get isAvailable(): boolean { - return !!getNativeModule('NotifeeApiModule'); - }, -}; diff --git a/src/schedule-exact-alarm/index.ts b/src/schedule-exact-alarm/index.ts deleted file mode 100644 index 4c8554a..0000000 --- a/src/schedule-exact-alarm/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { getNativeModule } from '../native-modules'; - -interface ScheduleEASpec { - checkPermission(callback: (isEnabled: boolean) => void): void; -} - -export const ScheduleEA = { - get isAvailable(): boolean { - return !!getNativeModule('ScheduleEA'); - }, - checkPermission(callback: (isEnabled: boolean) => void): void { - getNativeModule('ScheduleEA')!.checkPermission(callback); - }, -}; diff --git a/yarn.lock b/yarn.lock index 3eeb43b..36bfc46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9264,7 +9264,7 @@ __metadata: turbo: "npm:2.8.21" typescript: "npm:5.9.3" peerDependencies: - "@op-engineering/op-sqlite": 15.2.5 + "@op-engineering/op-sqlite": "*" "@react-native-async-storage/async-storage": "*" react: "*" react-native: "*"