@savers_app/react-native-sdk 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +508 -0
  3. package/lib/module/@types/@react-native-async-storage__async-storage.d.js +2 -0
  4. package/lib/module/@types/@react-native-async-storage__async-storage.d.js.map +1 -0
  5. package/lib/module/@types/@react-native-community__geolocation.d.js +2 -0
  6. package/lib/module/@types/@react-native-community__geolocation.d.js.map +1 -0
  7. package/lib/module/@types/react-native-aes-gcm-crypto.d.js +2 -0
  8. package/lib/module/@types/react-native-aes-gcm-crypto.d.js.map +1 -0
  9. package/lib/module/@types/react-native-device-info.d.js +2 -0
  10. package/lib/module/@types/react-native-device-info.d.js.map +1 -0
  11. package/lib/module/core/runtime.js +67 -0
  12. package/lib/module/core/runtime.js.map +1 -0
  13. package/lib/module/data/models/apiResponse.js +19 -0
  14. package/lib/module/data/models/apiResponse.js.map +1 -0
  15. package/lib/module/data/models/onboardingModel.js +67 -0
  16. package/lib/module/data/models/onboardingModel.js.map +1 -0
  17. package/lib/module/data/network/apiClient.js +109 -0
  18. package/lib/module/data/network/apiClient.js.map +1 -0
  19. package/lib/module/data/network/apiEndpoints.js +6 -0
  20. package/lib/module/data/network/apiEndpoints.js.map +1 -0
  21. package/lib/module/data/network/apiExceptionHandler.js +16 -0
  22. package/lib/module/data/network/apiExceptionHandler.js.map +1 -0
  23. package/lib/module/data/network/apiRepository.js +70 -0
  24. package/lib/module/data/network/apiRepository.js.map +1 -0
  25. package/lib/module/data/network/apiService.js +66 -0
  26. package/lib/module/data/network/apiService.js.map +1 -0
  27. package/lib/module/data/network/dataTypeUtils.js +77 -0
  28. package/lib/module/data/network/dataTypeUtils.js.map +1 -0
  29. package/lib/module/data/network/interceptors/authInterceptor.js +69 -0
  30. package/lib/module/data/network/interceptors/authInterceptor.js.map +1 -0
  31. package/lib/module/data/network/interceptors/errorInterceptor.js +15 -0
  32. package/lib/module/data/network/interceptors/errorInterceptor.js.map +1 -0
  33. package/lib/module/data/network/interceptors/loggingInterceptor.js +17 -0
  34. package/lib/module/data/network/interceptors/loggingInterceptor.js.map +1 -0
  35. package/lib/module/data/network/interceptors/networkInterceptor.js +22 -0
  36. package/lib/module/data/network/interceptors/networkInterceptor.js.map +1 -0
  37. package/lib/module/data/network/interceptors/retryInterceptor.js +22 -0
  38. package/lib/module/data/network/interceptors/retryInterceptor.js.map +1 -0
  39. package/lib/module/data/storage/asyncStorageManager.js +50 -0
  40. package/lib/module/data/storage/asyncStorageManager.js.map +1 -0
  41. package/lib/module/data/storage/deviceIdManager.js +45 -0
  42. package/lib/module/data/storage/deviceIdManager.js.map +1 -0
  43. package/lib/module/data/storage/keysManager.js +70 -0
  44. package/lib/module/data/storage/keysManager.js.map +1 -0
  45. package/lib/module/data/storage/locationManager.js +30 -0
  46. package/lib/module/data/storage/locationManager.js.map +1 -0
  47. package/lib/module/data/storage/sessionManager.js +12 -0
  48. package/lib/module/data/storage/sessionManager.js.map +1 -0
  49. package/lib/module/data/storage/storageKeys.js +7 -0
  50. package/lib/module/data/storage/storageKeys.js.map +1 -0
  51. package/lib/module/data/storage/storageManager.js +76 -0
  52. package/lib/module/data/storage/storageManager.js.map +1 -0
  53. package/lib/module/index.js +20 -0
  54. package/lib/module/index.js.map +1 -0
  55. package/lib/module/package.json +1 -0
  56. package/lib/module/services/device/location.js +47 -0
  57. package/lib/module/services/device/location.js.map +1 -0
  58. package/lib/module/services/navigation/dialPad.js +29 -0
  59. package/lib/module/services/navigation/dialPad.js.map +1 -0
  60. package/lib/module/services/navigation/goBackNavigation.js +22 -0
  61. package/lib/module/services/navigation/goBackNavigation.js.map +1 -0
  62. package/lib/module/services/navigation/openBrowser.js +8 -0
  63. package/lib/module/services/navigation/openBrowser.js.map +1 -0
  64. package/lib/module/services/navigation/openMap.js +26 -0
  65. package/lib/module/services/navigation/openMap.js.map +1 -0
  66. package/lib/module/services/permissions/permissionManager.js +28 -0
  67. package/lib/module/services/permissions/permissionManager.js.map +1 -0
  68. package/lib/module/services/url/urlGenerator.js +90 -0
  69. package/lib/module/services/url/urlGenerator.js.map +1 -0
  70. package/lib/module/services/webview/messageHandler.js +69 -0
  71. package/lib/module/services/webview/messageHandler.js.map +1 -0
  72. package/lib/module/utils/dependencyManager.js +51 -0
  73. package/lib/module/utils/dependencyManager.js.map +1 -0
  74. package/lib/module/utils/encryption.js +43 -0
  75. package/lib/module/utils/encryption.js.map +1 -0
  76. package/lib/module/utils/errors.js +9 -0
  77. package/lib/module/utils/errors.js.map +1 -0
  78. package/lib/module/utils/logger.js +14 -0
  79. package/lib/module/utils/logger.js.map +1 -0
  80. package/lib/module/utils/platformManager.js +14 -0
  81. package/lib/module/utils/platformManager.js.map +1 -0
  82. package/lib/module/utils/validator.js +26 -0
  83. package/lib/module/utils/validator.js.map +1 -0
  84. package/lib/typescript/package.json +1 -0
  85. package/lib/typescript/src/core/runtime.d.ts +10 -0
  86. package/lib/typescript/src/core/runtime.d.ts.map +1 -0
  87. package/lib/typescript/src/data/models/apiResponse.d.ts +9 -0
  88. package/lib/typescript/src/data/models/apiResponse.d.ts.map +1 -0
  89. package/lib/typescript/src/data/models/onboardingModel.d.ts +24 -0
  90. package/lib/typescript/src/data/models/onboardingModel.d.ts.map +1 -0
  91. package/lib/typescript/src/data/network/apiClient.d.ts +17 -0
  92. package/lib/typescript/src/data/network/apiClient.d.ts.map +1 -0
  93. package/lib/typescript/src/data/network/apiEndpoints.d.ts +4 -0
  94. package/lib/typescript/src/data/network/apiEndpoints.d.ts.map +1 -0
  95. package/lib/typescript/src/data/network/apiExceptionHandler.d.ts +3 -0
  96. package/lib/typescript/src/data/network/apiExceptionHandler.d.ts.map +1 -0
  97. package/lib/typescript/src/data/network/apiRepository.d.ts +19 -0
  98. package/lib/typescript/src/data/network/apiRepository.d.ts.map +1 -0
  99. package/lib/typescript/src/data/network/apiService.d.ts +19 -0
  100. package/lib/typescript/src/data/network/apiService.d.ts.map +1 -0
  101. package/lib/typescript/src/data/network/dataTypeUtils.d.ts +10 -0
  102. package/lib/typescript/src/data/network/dataTypeUtils.d.ts.map +1 -0
  103. package/lib/typescript/src/data/network/interceptors/authInterceptor.d.ts +13 -0
  104. package/lib/typescript/src/data/network/interceptors/authInterceptor.d.ts.map +1 -0
  105. package/lib/typescript/src/data/network/interceptors/errorInterceptor.d.ts +4 -0
  106. package/lib/typescript/src/data/network/interceptors/errorInterceptor.d.ts.map +1 -0
  107. package/lib/typescript/src/data/network/interceptors/loggingInterceptor.d.ts +5 -0
  108. package/lib/typescript/src/data/network/interceptors/loggingInterceptor.d.ts.map +1 -0
  109. package/lib/typescript/src/data/network/interceptors/networkInterceptor.d.ts +4 -0
  110. package/lib/typescript/src/data/network/interceptors/networkInterceptor.d.ts.map +1 -0
  111. package/lib/typescript/src/data/network/interceptors/retryInterceptor.d.ts +7 -0
  112. package/lib/typescript/src/data/network/interceptors/retryInterceptor.d.ts.map +1 -0
  113. package/lib/typescript/src/data/storage/asyncStorageManager.d.ts +13 -0
  114. package/lib/typescript/src/data/storage/asyncStorageManager.d.ts.map +1 -0
  115. package/lib/typescript/src/data/storage/deviceIdManager.d.ts +2 -0
  116. package/lib/typescript/src/data/storage/deviceIdManager.d.ts.map +1 -0
  117. package/lib/typescript/src/data/storage/keysManager.d.ts +29 -0
  118. package/lib/typescript/src/data/storage/keysManager.d.ts.map +1 -0
  119. package/lib/typescript/src/data/storage/locationManager.d.ts +21 -0
  120. package/lib/typescript/src/data/storage/locationManager.d.ts.map +1 -0
  121. package/lib/typescript/src/data/storage/sessionManager.d.ts +3 -0
  122. package/lib/typescript/src/data/storage/sessionManager.d.ts.map +1 -0
  123. package/lib/typescript/src/data/storage/storageKeys.d.ts +5 -0
  124. package/lib/typescript/src/data/storage/storageKeys.d.ts.map +1 -0
  125. package/lib/typescript/src/data/storage/storageManager.d.ts +16 -0
  126. package/lib/typescript/src/data/storage/storageManager.d.ts.map +1 -0
  127. package/lib/typescript/src/index.d.ts +18 -0
  128. package/lib/typescript/src/index.d.ts.map +1 -0
  129. package/lib/typescript/src/services/device/location.d.ts +8 -0
  130. package/lib/typescript/src/services/device/location.d.ts.map +1 -0
  131. package/lib/typescript/src/services/navigation/dialPad.d.ts +3 -0
  132. package/lib/typescript/src/services/navigation/dialPad.d.ts.map +1 -0
  133. package/lib/typescript/src/services/navigation/goBackNavigation.d.ts +4 -0
  134. package/lib/typescript/src/services/navigation/goBackNavigation.d.ts.map +1 -0
  135. package/lib/typescript/src/services/navigation/openBrowser.d.ts +2 -0
  136. package/lib/typescript/src/services/navigation/openBrowser.d.ts.map +1 -0
  137. package/lib/typescript/src/services/navigation/openMap.d.ts +2 -0
  138. package/lib/typescript/src/services/navigation/openMap.d.ts.map +1 -0
  139. package/lib/typescript/src/services/permissions/permissionManager.d.ts +4 -0
  140. package/lib/typescript/src/services/permissions/permissionManager.d.ts.map +1 -0
  141. package/lib/typescript/src/services/url/urlGenerator.d.ts +43 -0
  142. package/lib/typescript/src/services/url/urlGenerator.d.ts.map +1 -0
  143. package/lib/typescript/src/services/webview/messageHandler.d.ts +2 -0
  144. package/lib/typescript/src/services/webview/messageHandler.d.ts.map +1 -0
  145. package/lib/typescript/src/utils/dependencyManager.d.ts +31 -0
  146. package/lib/typescript/src/utils/dependencyManager.d.ts.map +1 -0
  147. package/lib/typescript/src/utils/encryption.d.ts +5 -0
  148. package/lib/typescript/src/utils/encryption.d.ts.map +1 -0
  149. package/lib/typescript/src/utils/errors.d.ts +4 -0
  150. package/lib/typescript/src/utils/errors.d.ts.map +1 -0
  151. package/lib/typescript/src/utils/logger.d.ts +6 -0
  152. package/lib/typescript/src/utils/logger.d.ts.map +1 -0
  153. package/lib/typescript/src/utils/platformManager.d.ts +4 -0
  154. package/lib/typescript/src/utils/platformManager.d.ts.map +1 -0
  155. package/lib/typescript/src/utils/validator.d.ts +4 -0
  156. package/lib/typescript/src/utils/validator.d.ts.map +1 -0
  157. package/package.json +176 -0
  158. package/src/@types/@react-native-async-storage__async-storage.d.ts +7 -0
  159. package/src/@types/@react-native-community__geolocation.d.ts +18 -0
  160. package/src/@types/react-native-aes-gcm-crypto.d.ts +22 -0
  161. package/src/@types/react-native-device-info.d.ts +3 -0
  162. package/src/core/runtime.ts +80 -0
  163. package/src/data/models/apiResponse.ts +28 -0
  164. package/src/data/models/onboardingModel.ts +99 -0
  165. package/src/data/network/apiClient.ts +148 -0
  166. package/src/data/network/apiEndpoints.ts +3 -0
  167. package/src/data/network/apiExceptionHandler.ts +16 -0
  168. package/src/data/network/apiRepository.ts +106 -0
  169. package/src/data/network/apiService.ts +72 -0
  170. package/src/data/network/dataTypeUtils.ts +78 -0
  171. package/src/data/network/interceptors/authInterceptor.ts +77 -0
  172. package/src/data/network/interceptors/errorInterceptor.ts +13 -0
  173. package/src/data/network/interceptors/loggingInterceptor.ts +16 -0
  174. package/src/data/network/interceptors/networkInterceptor.ts +20 -0
  175. package/src/data/network/interceptors/retryInterceptor.ts +24 -0
  176. package/src/data/storage/asyncStorageManager.ts +56 -0
  177. package/src/data/storage/deviceIdManager.ts +46 -0
  178. package/src/data/storage/keysManager.ts +89 -0
  179. package/src/data/storage/locationManager.ts +39 -0
  180. package/src/data/storage/sessionManager.ts +11 -0
  181. package/src/data/storage/storageKeys.ts +4 -0
  182. package/src/data/storage/storageManager.ts +83 -0
  183. package/src/index.tsx +17 -0
  184. package/src/services/device/location.ts +51 -0
  185. package/src/services/navigation/dialPad.ts +39 -0
  186. package/src/services/navigation/goBackNavigation.ts +22 -0
  187. package/src/services/navigation/openBrowser.ts +6 -0
  188. package/src/services/navigation/openMap.ts +39 -0
  189. package/src/services/permissions/permissionManager.ts +33 -0
  190. package/src/services/url/urlGenerator.ts +132 -0
  191. package/src/services/webview/messageHandler.ts +48 -0
  192. package/src/utils/dependencyManager.ts +82 -0
  193. package/src/utils/encryption.ts +58 -0
  194. package/src/utils/errors.ts +6 -0
  195. package/src/utils/logger.ts +11 -0
  196. package/src/utils/platformManager.ts +14 -0
  197. package/src/utils/validator.ts +29 -0
@@ -0,0 +1,33 @@
1
+ // React Native Core
2
+ import { Platform, PermissionsAndroid } from 'react-native';
3
+
4
+ export const requestPermission = async (
5
+ permission: Parameters<typeof PermissionsAndroid.request>[0]
6
+ ) => {
7
+ if (Platform.OS === 'ios') return true;
8
+
9
+ const already = await PermissionsAndroid.check(permission);
10
+ if (already) return true;
11
+ const result = await PermissionsAndroid.request(permission);
12
+ if (result === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) return false;
13
+ return result === PermissionsAndroid.RESULTS.GRANTED;
14
+ };
15
+
16
+ export async function ensureLocationPermission(): Promise<boolean> {
17
+ if (Platform.OS === 'ios') return true;
18
+ const fine = PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION;
19
+ const coarse = PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION;
20
+ const fineGranted = await PermissionsAndroid.check(fine);
21
+ const coarseGranted = await PermissionsAndroid.check(coarse);
22
+ if (fineGranted || coarseGranted) return true;
23
+ const res = await PermissionsAndroid.requestMultiple([fine, coarse]);
24
+ const fineOk = res[fine] === PermissionsAndroid.RESULTS.GRANTED;
25
+ const coarseOk = res[coarse] === PermissionsAndroid.RESULTS.GRANTED;
26
+ if (
27
+ res[fine] === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN ||
28
+ res[coarse] === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN
29
+ ) {
30
+ return false;
31
+ }
32
+ return fineOk || coarseOk;
33
+ }
@@ -0,0 +1,132 @@
1
+ // Utilities / Helpers
2
+ import { SDKError } from '../../utils/errors';
3
+ import { aesEncrypt } from '../../utils/encryption';
4
+
5
+ // Storage / Session
6
+ import { getDeviceId } from '../../data/storage/deviceIdManager';
7
+ import { getSessionId } from '../../data/storage/sessionManager';
8
+ import { getLocationCoordinates } from '../../data/storage/locationManager';
9
+ import { getEncryptionKey, getPRefCode } from '../../data/storage/keysManager';
10
+
11
+ export type Attribute = { key: string; value: string };
12
+ export type Screen = { name?: string; attributes?: Attribute[] };
13
+ export type Profile = {
14
+ userId: string;
15
+ phone?: string;
16
+ firstname: string;
17
+ lastname: string;
18
+ email: string;
19
+ dob?: string;
20
+ pv?: '0' | '1';
21
+ ev?: '0' | '1';
22
+ city?: string;
23
+ zipcode?: string;
24
+ referrer_user_id?: string;
25
+ username?: string;
26
+ };
27
+ export type AuthType = 'PHONE' | 'EMAIL' | 'USERNAME';
28
+ export type DeviceInfo = {
29
+ dId: string;
30
+ location?: { lat: number; lng: number };
31
+ };
32
+
33
+ export type UrlInput = {
34
+ screen?: Screen;
35
+ profile: Profile;
36
+ authType?: AuthType;
37
+ deviceInfo?: DeviceInfo;
38
+ sessionId?: string;
39
+ };
40
+ export function validateInput(input: UrlInput): {
41
+ ok: boolean;
42
+ errors: string[];
43
+ } {
44
+ const errors: string[] = [];
45
+ const auth = input.authType ?? 'PHONE';
46
+ if (!input.profile) errors.push('profile is mandatory');
47
+ if (!input.profile?.userId) errors.push('userId is mandatory');
48
+ if (!input.profile?.email) errors.push('email is mandatory');
49
+ const pv = input.profile?.pv;
50
+ const ev = input.profile?.ev;
51
+ if (typeof pv !== 'undefined' && pv !== '0' && pv !== '1') {
52
+ errors.push('pv must be 0 or 1');
53
+ }
54
+ if (typeof ev !== 'undefined' && ev !== '0' && ev !== '1') {
55
+ errors.push('ev must be 0 or 1');
56
+ }
57
+ if (!auth) errors.push('authType is mandatory');
58
+
59
+ if (auth === 'USERNAME' && !input.profile?.username) {
60
+ errors.push('username is mandatory for USERNAME authType');
61
+ }
62
+ if (auth === 'PHONE' && !input.profile?.phone) {
63
+ errors.push('phone is mandatory for PHONE authType');
64
+ }
65
+
66
+ const screenName = input.screen?.name;
67
+ if (screenName === 'OfrDetails') {
68
+ const attrs = input.screen?.attributes ?? [];
69
+ if (!attrs.length) {
70
+ errors.push(
71
+ 'screen.attributes is mandatory when screen.name is OfrDetails'
72
+ );
73
+ }
74
+ }
75
+
76
+ return { ok: errors.length === 0, errors };
77
+ }
78
+
79
+ export async function generateUrl(input: UrlInput): Promise<string> {
80
+ const deviceId = await getDeviceId();
81
+ const storedLocation = await getLocationCoordinates();
82
+ const sessionId = await getSessionId();
83
+
84
+ const deviceInfo: DeviceInfo =
85
+ storedLocation != null
86
+ ? { dId: deviceId, location: storedLocation }
87
+ : { dId: deviceId };
88
+
89
+ const normalized: Required<Pick<UrlInput, 'profile'>> &
90
+ Pick<UrlInput, 'screen' | 'authType' | 'sessionId'> & {
91
+ deviceInfo: DeviceInfo;
92
+ } = {
93
+ profile: input.profile,
94
+ screen: input.screen,
95
+ authType: input.authType ?? 'PHONE',
96
+ sessionId: sessionId ?? '',
97
+ deviceInfo,
98
+ };
99
+
100
+ const validation = validateInput({
101
+ ...normalized,
102
+ deviceInfo: normalized.deviceInfo,
103
+ });
104
+ if (!validation.ok) {
105
+ throw new SDKError(`Validation failed: ${validation.errors.join(', ')}`);
106
+ }
107
+
108
+ const payload = {
109
+ screen: normalized.screen ?? { name: 'Explore' },
110
+ profile: normalized.profile,
111
+ authType: normalized.authType,
112
+ deviceInfo: normalized.deviceInfo,
113
+ sessionId: normalized.sessionId,
114
+ };
115
+
116
+ const json = JSON.stringify(payload);
117
+ const key = await getEncryptionKey();
118
+ if (!key || key === '-') {
119
+ throw new SDKError(
120
+ 'Encryption key is mandatory. Initialize SDK with encryptionKey.'
121
+ );
122
+ }
123
+ const encoded = await aesEncrypt(json, key);
124
+
125
+ const programCode = await getPRefCode();
126
+ if (!programCode || programCode === '-') {
127
+ throw new SDKError('pRefCode is mandatory. Initialize SDK with pRefCode.');
128
+ }
129
+ return `https://m.saversapp.com/?pRefCode=${encodeURIComponent(
130
+ programCode
131
+ )}&qP=${encodeURIComponent(encoded)}`;
132
+ }
@@ -0,0 +1,48 @@
1
+ // Screens / SDKs / External packages
2
+ import {
3
+ openMap,
4
+ openDialPad,
5
+ openBrowser,
6
+ closeCurrentScreenSafe,
7
+ setSessionId,
8
+ } from '@saversapp/react-native-sdk';
9
+
10
+ export function handleWebMessage(raw: string, postBack?: (data: any) => void) {
11
+ let msg: { action?: string; payload?: any };
12
+ try {
13
+ msg = JSON.parse(raw);
14
+ } catch {
15
+ return;
16
+ }
17
+ const action = msg?.action;
18
+ const payload = msg?.payload;
19
+
20
+ const reply = (data: any) => postBack?.(data);
21
+
22
+ (async () => {
23
+ try {
24
+ if (action === 'OPEN_MAP') {
25
+ const { lat, lng, label } = payload || {};
26
+ await openMap(lat, lng, label);
27
+ reply({ ok: true, action });
28
+ } else if (action === 'SHOW_DIAL_PAD') {
29
+ await openDialPad(payload?.number);
30
+ reply({ ok: true, action });
31
+ } else if (action === 'MERCHANT_PORTAL_REDIRECT') {
32
+ await openBrowser(payload?.url);
33
+ reply({ ok: true, action });
34
+ } else if (action === 'SESSION_ID') {
35
+ const { sessionId } = payload || {};
36
+ const id = await setSessionId(sessionId);
37
+ reply({ ok: true, action, sessionId: id });
38
+ } else if (action === 'END_SESSION') {
39
+ closeCurrentScreenSafe();
40
+ // reply({ ok: true, action, closed });
41
+ } else {
42
+ reply({ ok: false, error: 'UNKNOWN_ACTION', action });
43
+ }
44
+ } catch (e: any) {
45
+ reply({ ok: false, error: e?.message ?? String(e), action });
46
+ }
47
+ })();
48
+ }
@@ -0,0 +1,82 @@
1
+ type AsyncStorageModule =
2
+ | {
3
+ getItem: (key: string) => Promise<string | null>;
4
+ setItem: (key: string, value: string) => Promise<void>;
5
+ }
6
+ | undefined;
7
+
8
+ type GeolocationModule =
9
+ | {
10
+ getCurrentPosition: (
11
+ success: (pos: {
12
+ coords: { latitude: number; longitude: number };
13
+ }) => void,
14
+ error?: (err: unknown) => void,
15
+ options?: {
16
+ enableHighAccuracy?: boolean;
17
+ timeout?: number;
18
+ maximumAge?: number;
19
+ }
20
+ ) => void;
21
+ }
22
+ | undefined;
23
+
24
+ type DeviceInfoModule =
25
+ | {
26
+ getUniqueId?: () => Promise<string>;
27
+ }
28
+ | undefined;
29
+
30
+ let AsyncStorage: AsyncStorageModule;
31
+ let Geolocation: GeolocationModule;
32
+ let DeviceInfo: DeviceInfoModule;
33
+
34
+ function loadAsyncStorage(): AsyncStorageModule {
35
+ try {
36
+ const mod = require('@react-native-async-storage/async-storage');
37
+ return mod?.default ?? mod;
38
+ } catch {
39
+ return undefined;
40
+ }
41
+ }
42
+
43
+ function loadGeolocation(): GeolocationModule {
44
+ try {
45
+ const mod = require('@react-native-community/geolocation');
46
+ return mod?.default ?? mod;
47
+ } catch {
48
+ return undefined;
49
+ }
50
+ }
51
+
52
+ function loadDeviceInfo(): DeviceInfoModule {
53
+ try {
54
+ const mod = require('react-native-device-info');
55
+ return mod?.default ?? mod;
56
+ } catch {
57
+ return undefined;
58
+ }
59
+ }
60
+
61
+ export function resolveNativeDependencies() {
62
+ if (!AsyncStorage) AsyncStorage = loadAsyncStorage();
63
+ if (!Geolocation) Geolocation = loadGeolocation();
64
+ if (!DeviceInfo) DeviceInfo = loadDeviceInfo();
65
+ return {
66
+ AsyncStorage,
67
+ Geolocation,
68
+ DeviceInfo,
69
+ };
70
+ }
71
+
72
+ export const SDKRequirements = {
73
+ get asyncStorage() {
74
+ return Boolean(resolveNativeDependencies().AsyncStorage);
75
+ },
76
+ get geolocation() {
77
+ return Boolean(resolveNativeDependencies().Geolocation);
78
+ },
79
+ get deviceInfo() {
80
+ return Boolean(resolveNativeDependencies().DeviceInfo);
81
+ },
82
+ };
@@ -0,0 +1,58 @@
1
+ // Third-party libraries
2
+ import AesGcmCrypto from 'react-native-aes-gcm-crypto';
3
+
4
+ function isBase64(input: string): boolean {
5
+ return /^[A-Za-z0-9+/]+={0,2}$/.test(input);
6
+ }
7
+
8
+ function base64ByteLength(b64: string): number {
9
+ const cleaned = b64.replace(/=+$/, '');
10
+ return Math.floor((cleaned.length * 3) / 4);
11
+ }
12
+
13
+ export async function aesEncrypt(text: string, key: string): Promise<string> {
14
+ if (!isBase64(key) || base64ByteLength(key) !== 32) {
15
+ throw new Error(
16
+ 'Encryption key must be base64-encoded 32-byte (256-bit) value'
17
+ );
18
+ }
19
+ const { iv, tag, content } = await AesGcmCrypto.encrypt(text, false, key);
20
+ return base64Encrypt(`${iv}:${content}:${tag}`);
21
+ }
22
+
23
+ export async function aesDecrypt(
24
+ ciphertext: string,
25
+ key: string
26
+ ): Promise<string> {
27
+ if (!isBase64(key) || base64ByteLength(key) !== 32) {
28
+ throw new Error(
29
+ 'Encryption key must be base64-encoded 32-byte (256-bit) value'
30
+ );
31
+ }
32
+ const parts = ciphertext.split(':');
33
+ const iv = parts[0] ?? '';
34
+ const content = parts[1] ?? '';
35
+ const tag = parts[2] ?? '';
36
+ const decrypted = await AesGcmCrypto.decrypt(content, key, iv, tag, false);
37
+ return decrypted;
38
+ }
39
+
40
+ declare function btoa(data: string): string;
41
+ declare function atob(data: string): string;
42
+
43
+ export function base64Encrypt(plain: string): string {
44
+ const utf8 = encodeURIComponent(plain).replace(
45
+ /%([0-9A-F]{2})/g,
46
+ (_, p1: string) => String.fromCharCode(parseInt(p1, 16))
47
+ );
48
+ return btoa(utf8);
49
+ }
50
+
51
+ export function base64Decrypt(encoded: string): string {
52
+ const binary = atob(encoded);
53
+ const utf8 = binary
54
+ .split('')
55
+ .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
56
+ .join('');
57
+ return decodeURIComponent(utf8);
58
+ }
@@ -0,0 +1,6 @@
1
+ export class SDKError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'SDKError';
5
+ }
6
+ }
@@ -0,0 +1,11 @@
1
+ export const logger = {
2
+ info: (...args: unknown[]) => {
3
+ console.info(...args);
4
+ },
5
+ warn: (...args: unknown[]) => {
6
+ console.warn(...args);
7
+ },
8
+ error: (...args: unknown[]) => {
9
+ console.error(...args);
10
+ },
11
+ };
@@ -0,0 +1,14 @@
1
+ // React Native Core
2
+ import { Platform } from 'react-native';
3
+
4
+ export function isIOS(): boolean {
5
+ return Platform.OS === 'ios';
6
+ }
7
+
8
+ export function isAndroid(): boolean {
9
+ return Platform.OS === 'android';
10
+ }
11
+
12
+ export function platformVersion(): number {
13
+ return Number(Platform.Version);
14
+ }
@@ -0,0 +1,29 @@
1
+ // React Native Core
2
+ import { Linking } from 'react-native';
3
+
4
+ // Platform / Environment helpers
5
+ import { isIOS } from './platformManager';
6
+
7
+ export function isValidPhoneNumber(input: string): boolean {
8
+ if (!input) return false;
9
+ return /^\+?[0-9]{8,15}$/.test(input);
10
+ }
11
+
12
+ export async function isMapAppAvailable(): Promise<boolean> {
13
+ if (isIOS()) {
14
+ // Apple Maps scheme
15
+ return Linking.canOpenURL('maps:0,0?q=test');
16
+ }
17
+ // Android geo scheme
18
+ return Linking.canOpenURL('geo:0,0?q=0,0');
19
+ }
20
+
21
+ export async function isValidCoordinates(
22
+ lat: number,
23
+ lng: number
24
+ ): Promise<boolean> {
25
+ if (!Number.isFinite(lat) || !Number.isFinite(lng)) return false;
26
+ if (lat < -90 || lat > 90) return false;
27
+ if (lng < -180 || lng > 180) return false;
28
+ return true;
29
+ }