@savers_app/react-native-sandbox-sdk 1.2.6

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 (212) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +556 -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 +70 -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/models/tokenModel.js +25 -0
  18. package/lib/module/data/models/tokenModel.js.map +1 -0
  19. package/lib/module/data/network/apiClient.js +109 -0
  20. package/lib/module/data/network/apiClient.js.map +1 -0
  21. package/lib/module/data/network/apiEndpoints.js +7 -0
  22. package/lib/module/data/network/apiEndpoints.js.map +1 -0
  23. package/lib/module/data/network/apiExceptionHandler.js +16 -0
  24. package/lib/module/data/network/apiExceptionHandler.js.map +1 -0
  25. package/lib/module/data/network/apiRepository.js +84 -0
  26. package/lib/module/data/network/apiRepository.js.map +1 -0
  27. package/lib/module/data/network/apiService.js +102 -0
  28. package/lib/module/data/network/apiService.js.map +1 -0
  29. package/lib/module/data/network/dataTypeUtils.js +77 -0
  30. package/lib/module/data/network/dataTypeUtils.js.map +1 -0
  31. package/lib/module/data/network/interceptors/authInterceptor.js +72 -0
  32. package/lib/module/data/network/interceptors/authInterceptor.js.map +1 -0
  33. package/lib/module/data/network/interceptors/errorInterceptor.js +15 -0
  34. package/lib/module/data/network/interceptors/errorInterceptor.js.map +1 -0
  35. package/lib/module/data/network/interceptors/loggingInterceptor.js +17 -0
  36. package/lib/module/data/network/interceptors/loggingInterceptor.js.map +1 -0
  37. package/lib/module/data/network/interceptors/networkInterceptor.js +22 -0
  38. package/lib/module/data/network/interceptors/networkInterceptor.js.map +1 -0
  39. package/lib/module/data/network/interceptors/retryInterceptor.js +22 -0
  40. package/lib/module/data/network/interceptors/retryInterceptor.js.map +1 -0
  41. package/lib/module/data/storage/asyncStorageManager.js +50 -0
  42. package/lib/module/data/storage/asyncStorageManager.js.map +1 -0
  43. package/lib/module/data/storage/deviceIdManager.js +45 -0
  44. package/lib/module/data/storage/deviceIdManager.js.map +1 -0
  45. package/lib/module/data/storage/keysManager.js +70 -0
  46. package/lib/module/data/storage/keysManager.js.map +1 -0
  47. package/lib/module/data/storage/locationManager.js +30 -0
  48. package/lib/module/data/storage/locationManager.js.map +1 -0
  49. package/lib/module/data/storage/reactRefManager.js +22 -0
  50. package/lib/module/data/storage/reactRefManager.js.map +1 -0
  51. package/lib/module/data/storage/sessionManager.js +12 -0
  52. package/lib/module/data/storage/sessionManager.js.map +1 -0
  53. package/lib/module/data/storage/storageKeys.js +7 -0
  54. package/lib/module/data/storage/storageKeys.js.map +1 -0
  55. package/lib/module/data/storage/storageManager.js +76 -0
  56. package/lib/module/data/storage/storageManager.js.map +1 -0
  57. package/lib/module/index.js +20 -0
  58. package/lib/module/index.js.map +1 -0
  59. package/lib/module/package.json +1 -0
  60. package/lib/module/services/device/location.js +47 -0
  61. package/lib/module/services/device/location.js.map +1 -0
  62. package/lib/module/services/navigation/dialPad.js +29 -0
  63. package/lib/module/services/navigation/dialPad.js.map +1 -0
  64. package/lib/module/services/navigation/goBackNavigation.js +19 -0
  65. package/lib/module/services/navigation/goBackNavigation.js.map +1 -0
  66. package/lib/module/services/navigation/openBrowser.js +8 -0
  67. package/lib/module/services/navigation/openBrowser.js.map +1 -0
  68. package/lib/module/services/navigation/openMap.js +42 -0
  69. package/lib/module/services/navigation/openMap.js.map +1 -0
  70. package/lib/module/services/permissions/permissionManager.js +28 -0
  71. package/lib/module/services/permissions/permissionManager.js.map +1 -0
  72. package/lib/module/services/url/urlGenerator.js +94 -0
  73. package/lib/module/services/url/urlGenerator.js.map +1 -0
  74. package/lib/module/services/webview/messageHandler.js +72 -0
  75. package/lib/module/services/webview/messageHandler.js.map +1 -0
  76. package/lib/module/utils/config.js +34 -0
  77. package/lib/module/utils/config.js.map +1 -0
  78. package/lib/module/utils/dependencyManager.js +51 -0
  79. package/lib/module/utils/dependencyManager.js.map +1 -0
  80. package/lib/module/utils/encryption.js +63 -0
  81. package/lib/module/utils/encryption.js.map +1 -0
  82. package/lib/module/utils/errors.js +9 -0
  83. package/lib/module/utils/errors.js.map +1 -0
  84. package/lib/module/utils/logger.js +14 -0
  85. package/lib/module/utils/logger.js.map +1 -0
  86. package/lib/module/utils/platformManager.js +14 -0
  87. package/lib/module/utils/platformManager.js.map +1 -0
  88. package/lib/module/utils/validator.js +26 -0
  89. package/lib/module/utils/validator.js.map +1 -0
  90. package/lib/typescript/package.json +1 -0
  91. package/lib/typescript/src/core/runtime.d.ts +11 -0
  92. package/lib/typescript/src/core/runtime.d.ts.map +1 -0
  93. package/lib/typescript/src/data/models/apiResponse.d.ts +9 -0
  94. package/lib/typescript/src/data/models/apiResponse.d.ts.map +1 -0
  95. package/lib/typescript/src/data/models/onboardingModel.d.ts +24 -0
  96. package/lib/typescript/src/data/models/onboardingModel.d.ts.map +1 -0
  97. package/lib/typescript/src/data/models/tokenModel.d.ts +15 -0
  98. package/lib/typescript/src/data/models/tokenModel.d.ts.map +1 -0
  99. package/lib/typescript/src/data/network/apiClient.d.ts +17 -0
  100. package/lib/typescript/src/data/network/apiClient.d.ts.map +1 -0
  101. package/lib/typescript/src/data/network/apiEndpoints.d.ts +5 -0
  102. package/lib/typescript/src/data/network/apiEndpoints.d.ts.map +1 -0
  103. package/lib/typescript/src/data/network/apiExceptionHandler.d.ts +3 -0
  104. package/lib/typescript/src/data/network/apiExceptionHandler.d.ts.map +1 -0
  105. package/lib/typescript/src/data/network/apiRepository.d.ts +21 -0
  106. package/lib/typescript/src/data/network/apiRepository.d.ts.map +1 -0
  107. package/lib/typescript/src/data/network/apiService.d.ts +25 -0
  108. package/lib/typescript/src/data/network/apiService.d.ts.map +1 -0
  109. package/lib/typescript/src/data/network/dataTypeUtils.d.ts +10 -0
  110. package/lib/typescript/src/data/network/dataTypeUtils.d.ts.map +1 -0
  111. package/lib/typescript/src/data/network/interceptors/authInterceptor.d.ts +15 -0
  112. package/lib/typescript/src/data/network/interceptors/authInterceptor.d.ts.map +1 -0
  113. package/lib/typescript/src/data/network/interceptors/errorInterceptor.d.ts +4 -0
  114. package/lib/typescript/src/data/network/interceptors/errorInterceptor.d.ts.map +1 -0
  115. package/lib/typescript/src/data/network/interceptors/loggingInterceptor.d.ts +5 -0
  116. package/lib/typescript/src/data/network/interceptors/loggingInterceptor.d.ts.map +1 -0
  117. package/lib/typescript/src/data/network/interceptors/networkInterceptor.d.ts +4 -0
  118. package/lib/typescript/src/data/network/interceptors/networkInterceptor.d.ts.map +1 -0
  119. package/lib/typescript/src/data/network/interceptors/retryInterceptor.d.ts +7 -0
  120. package/lib/typescript/src/data/network/interceptors/retryInterceptor.d.ts.map +1 -0
  121. package/lib/typescript/src/data/storage/asyncStorageManager.d.ts +13 -0
  122. package/lib/typescript/src/data/storage/asyncStorageManager.d.ts.map +1 -0
  123. package/lib/typescript/src/data/storage/deviceIdManager.d.ts +2 -0
  124. package/lib/typescript/src/data/storage/deviceIdManager.d.ts.map +1 -0
  125. package/lib/typescript/src/data/storage/keysManager.d.ts +29 -0
  126. package/lib/typescript/src/data/storage/keysManager.d.ts.map +1 -0
  127. package/lib/typescript/src/data/storage/locationManager.d.ts +21 -0
  128. package/lib/typescript/src/data/storage/locationManager.d.ts.map +1 -0
  129. package/lib/typescript/src/data/storage/reactRefManager.d.ts +11 -0
  130. package/lib/typescript/src/data/storage/reactRefManager.d.ts.map +1 -0
  131. package/lib/typescript/src/data/storage/sessionManager.d.ts +3 -0
  132. package/lib/typescript/src/data/storage/sessionManager.d.ts.map +1 -0
  133. package/lib/typescript/src/data/storage/storageKeys.d.ts +5 -0
  134. package/lib/typescript/src/data/storage/storageKeys.d.ts.map +1 -0
  135. package/lib/typescript/src/data/storage/storageManager.d.ts +16 -0
  136. package/lib/typescript/src/data/storage/storageManager.d.ts.map +1 -0
  137. package/lib/typescript/src/index.d.ts +18 -0
  138. package/lib/typescript/src/index.d.ts.map +1 -0
  139. package/lib/typescript/src/services/device/location.d.ts +8 -0
  140. package/lib/typescript/src/services/device/location.d.ts.map +1 -0
  141. package/lib/typescript/src/services/navigation/dialPad.d.ts +3 -0
  142. package/lib/typescript/src/services/navigation/dialPad.d.ts.map +1 -0
  143. package/lib/typescript/src/services/navigation/goBackNavigation.d.ts +3 -0
  144. package/lib/typescript/src/services/navigation/goBackNavigation.d.ts.map +1 -0
  145. package/lib/typescript/src/services/navigation/openBrowser.d.ts +2 -0
  146. package/lib/typescript/src/services/navigation/openBrowser.d.ts.map +1 -0
  147. package/lib/typescript/src/services/navigation/openMap.d.ts +2 -0
  148. package/lib/typescript/src/services/navigation/openMap.d.ts.map +1 -0
  149. package/lib/typescript/src/services/permissions/permissionManager.d.ts +4 -0
  150. package/lib/typescript/src/services/permissions/permissionManager.d.ts.map +1 -0
  151. package/lib/typescript/src/services/url/urlGenerator.d.ts +44 -0
  152. package/lib/typescript/src/services/url/urlGenerator.d.ts.map +1 -0
  153. package/lib/typescript/src/services/webview/messageHandler.d.ts +2 -0
  154. package/lib/typescript/src/services/webview/messageHandler.d.ts.map +1 -0
  155. package/lib/typescript/src/utils/config.d.ts +5 -0
  156. package/lib/typescript/src/utils/config.d.ts.map +1 -0
  157. package/lib/typescript/src/utils/dependencyManager.d.ts +31 -0
  158. package/lib/typescript/src/utils/dependencyManager.d.ts.map +1 -0
  159. package/lib/typescript/src/utils/encryption.d.ts +5 -0
  160. package/lib/typescript/src/utils/encryption.d.ts.map +1 -0
  161. package/lib/typescript/src/utils/errors.d.ts +4 -0
  162. package/lib/typescript/src/utils/errors.d.ts.map +1 -0
  163. package/lib/typescript/src/utils/logger.d.ts +6 -0
  164. package/lib/typescript/src/utils/logger.d.ts.map +1 -0
  165. package/lib/typescript/src/utils/platformManager.d.ts +4 -0
  166. package/lib/typescript/src/utils/platformManager.d.ts.map +1 -0
  167. package/lib/typescript/src/utils/validator.d.ts +4 -0
  168. package/lib/typescript/src/utils/validator.d.ts.map +1 -0
  169. package/package.json +184 -0
  170. package/src/@types/@react-native-async-storage__async-storage.d.ts +7 -0
  171. package/src/@types/@react-native-community__geolocation.d.ts +18 -0
  172. package/src/@types/react-native-aes-gcm-crypto.d.ts +22 -0
  173. package/src/@types/react-native-device-info.d.ts +3 -0
  174. package/src/core/runtime.ts +84 -0
  175. package/src/data/models/apiResponse.ts +28 -0
  176. package/src/data/models/onboardingModel.ts +97 -0
  177. package/src/data/models/tokenModel.ts +43 -0
  178. package/src/data/network/apiClient.ts +148 -0
  179. package/src/data/network/apiEndpoints.ts +4 -0
  180. package/src/data/network/apiExceptionHandler.ts +16 -0
  181. package/src/data/network/apiRepository.ts +130 -0
  182. package/src/data/network/apiService.ts +113 -0
  183. package/src/data/network/dataTypeUtils.ts +78 -0
  184. package/src/data/network/interceptors/authInterceptor.ts +86 -0
  185. package/src/data/network/interceptors/errorInterceptor.ts +13 -0
  186. package/src/data/network/interceptors/loggingInterceptor.ts +16 -0
  187. package/src/data/network/interceptors/networkInterceptor.ts +20 -0
  188. package/src/data/network/interceptors/retryInterceptor.ts +24 -0
  189. package/src/data/storage/asyncStorageManager.ts +56 -0
  190. package/src/data/storage/deviceIdManager.ts +46 -0
  191. package/src/data/storage/keysManager.ts +89 -0
  192. package/src/data/storage/locationManager.ts +39 -0
  193. package/src/data/storage/reactRefManager.ts +25 -0
  194. package/src/data/storage/sessionManager.ts +11 -0
  195. package/src/data/storage/storageKeys.ts +4 -0
  196. package/src/data/storage/storageManager.ts +83 -0
  197. package/src/index.tsx +17 -0
  198. package/src/services/device/location.ts +51 -0
  199. package/src/services/navigation/dialPad.ts +39 -0
  200. package/src/services/navigation/goBackNavigation.ts +19 -0
  201. package/src/services/navigation/openBrowser.ts +6 -0
  202. package/src/services/navigation/openMap.ts +53 -0
  203. package/src/services/permissions/permissionManager.ts +33 -0
  204. package/src/services/url/urlGenerator.ts +140 -0
  205. package/src/services/webview/messageHandler.ts +45 -0
  206. package/src/utils/config.ts +35 -0
  207. package/src/utils/dependencyManager.ts +82 -0
  208. package/src/utils/encryption.ts +96 -0
  209. package/src/utils/errors.ts +6 -0
  210. package/src/utils/logger.ts +11 -0
  211. package/src/utils/platformManager.ts +14 -0
  212. package/src/utils/validator.ts +29 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Faisal Wahab
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,556 @@
1
+ # Savers React Native SDK
2
+
3
+ React Native SDK that bridges host app features like maps, dialer, browser, device info, session storage, URL generation, navigation, and WebView event handling. It also includes a robust networking layer with interceptors.
4
+
5
+ ## Features
6
+ - Open native maps by coordinates with graceful browser fallback
7
+ - Dial pad invocation with optional number and direct call helper
8
+ - External browser navigation from the host app or from web content
9
+ - Close current screen via global `navigationRef` (React Navigation) using **END_SESSION**
10
+ - Device ID retrieval (via `react-native-device-info`)
11
+ - Optional device location retrieval and URL payload enrichment
12
+ - Session and keys management (API key, encryption key, program ref code, auth mode)
13
+ - URL generator to compose signed and encrypted Savers mobile URLs
14
+ - AES-GCM encryption for URL payload (AES-256-GCM)
15
+ - WebView message handler to trigger native actions from web (maps, dialer, browser, session id, end session)
16
+ - Configurable networking layer with interceptors (logging, network connectivity, auth, retry, error formatting)
17
+
18
+ ## Installation
19
+ - Install the library:
20
+
21
+ ```bash
22
+ npm install @savers_app/react-native-sdk
23
+ # or
24
+ yarn add @savers_app/react-native-sdk
25
+ ```
26
+
27
+ - Install required peer dependencies:
28
+
29
+ ```bash
30
+ npm install @react-native-async-storage/async-storage \
31
+ @react-native-community/geolocation \
32
+ @react-native-community/netinfo \
33
+ @react-navigation/native \
34
+ react-native-device-info \
35
+ react-native-aes-gcm-crypto
36
+ # or
37
+ yarn add @react-native-async-storage/async-storage \
38
+ @react-native-community/geolocation \
39
+ @react-native-community/netinfo \
40
+ @react-navigation/native \
41
+ react-native-device-info \
42
+ react-native-aes-gcm-crypto
43
+ ```
44
+
45
+ - Optional (for WebView-based messaging):
46
+
47
+ ```bash
48
+ npm install react-native-webview
49
+ # or
50
+ yarn add react-native-webview
51
+ ```
52
+
53
+ ## iOS Setup
54
+ - Add dialer schemes to Info.plist:
55
+
56
+ ```xml
57
+ <key>LSApplicationQueriesSchemes</key>
58
+ <array>
59
+ <string>tel</string>
60
+ <string>telprompt</string>
61
+ </array>
62
+ ```
63
+
64
+ - Permissions (add keys and descriptions in Info.plist):
65
+ - NSLocationWhenInUseUsageDescription
66
+
67
+ Example:
68
+
69
+ ```xml
70
+ <key>NSLocationWhenInUseUsageDescription</key>
71
+ <string>Location access is required to provide location-based features.</string>
72
+ ```
73
+
74
+ Ensure native pods are installed and linked for the peer dependencies.
75
+
76
+ ## Android Setup
77
+ - Add permissions in AndroidManifest.xml:
78
+
79
+ ```xml
80
+ <uses-permission android:name="android.permission.INTERNET" />
81
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
82
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
83
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
84
+ ```
85
+
86
+ Link and configure the peer dependencies according to their documentation.
87
+
88
+ Requirements for AES-GCM:
89
+ - Android minSdkVersion must be 26 or higher (example app is configured to 26).
90
+ - iOS 13 or higher.
91
+
92
+ ## Quick Start
93
+
94
+ ### 1. Initialize the SDK
95
+
96
+ Before using any other APIs, initialize the SDK with keys you receive from Savers:
97
+
98
+ ```ts
99
+ import { SaversAppSDK } from '@savers_app/react-native-sdk';
100
+
101
+ SaversAppSDK.initialized({
102
+ apiKey: 'YOUR_API_KEY',
103
+ encryptionKey: 'BASE64_256_BIT_ENCRYPTION_KEY',
104
+ pRefCode: 'PROGRAM_REF_CODE',
105
+ authMode: 'CUSTOMER_SIGN_IN_UP_MODE' // 'EMAIL' | 'PHONE'
106
+ });
107
+ ```
108
+
109
+ The SDK stores these values in memory (not in AsyncStorage), via an internal `keysManager`. You can later read them using:
110
+
111
+ ```ts
112
+ import {
113
+ getApiKey,
114
+ getEncryptionKey,
115
+ getPRefCode,
116
+ getAuthMode,
117
+ } from '@savers_app/react-native-sdk';
118
+ ```
119
+
120
+ ### 2. Generate URL
121
+
122
+ ```ts
123
+ import { generateUrl } from '@savers_app/react-native-sdk';
124
+
125
+ const url = await generateUrl({
126
+ // Top-level UrlInput fields
127
+ authType: 'PHONE', // optional, defaults to 'PHONE' | also 'EMAIL' | 'USERNAME'
128
+ profile: {
129
+ // Mandatory fields
130
+ userId: 'USER_ID',
131
+ email: 'jane@example.com',
132
+ firstname: 'Jane',
133
+ lastname: 'Doe',
134
+
135
+ // Conditionally mandatory
136
+ phone: '+15555550100', // required when authType === 'PHONE'
137
+ username: 'jane.doe', // required when authType === 'USERNAME'
138
+
139
+ // Optional profile flags
140
+ pv: '1', // optional: '0' | '1'
141
+ ev: '1', // optional: '0' | '1'
142
+
143
+ // Other optional profile fields
144
+ dob: '1990-01-01',
145
+ city: 'San Francisco',
146
+ zipcode: '94103',
147
+ referrer_user_id: 'REFERRER_ID',
148
+ },
149
+ screen: {
150
+ // Optional screen; defaults to { name: 'Explore' } when omitted
151
+ name: 'Explore',
152
+
153
+ // attributes are optional in general, but mandatory when name === 'OfrDetails'
154
+ attributes: [{ key: 'offerId', value: '123' }],
155
+ },
156
+ // sessionId is optional; when omitted, the SDK uses its stored session id
157
+ // deviceInfo is optional; the SDK builds it internally using device id (and optional coordinates)
158
+ nonce: '<NONCE_TOKEN>',
159
+ });
160
+ // returns https://m.saversapp.com/?pRefCode=...&qP=...
161
+ ```
162
+
163
+ Fetch nonce and call generateUrl:
164
+
165
+ ```ts
166
+ import { ApiService, generateUrl } from '@savers_app/react-native-sdk';
167
+
168
+ const generator = new ApiService().getNonce({
169
+ extUserId: '12345',
170
+ partnerCode: 'abcde',
171
+ });
172
+
173
+ const { value } = await generator.next();
174
+ if (value?.error) throw new Error(value.error);
175
+ if (!value?.token) throw new Error('Nonce not received');
176
+
177
+ const url = await generateUrl({
178
+ authType: 'PHONE',
179
+ profile: {
180
+ userId: 'USER_ID',
181
+ email: 'jane@example.com',
182
+ firstname: 'Jane',
183
+ lastname: 'Doe',
184
+ phone: '+15555550100',
185
+ pv: '1',
186
+ ev: '1',
187
+ },
188
+ screen: { name: 'Explore', attributes: [{ key: 'offerId', value: '123' }] },
189
+ nonce: value.token,
190
+ });
191
+ ```
192
+
193
+ Profile requirements:
194
+ - `userId` and `email` are mandatory
195
+ - `pv` and `ev` are optional (`'0'` or `'1'`)
196
+ - `phone` is mandatory when `authType` is `'PHONE'`
197
+ - `username` is mandatory when `authType` is `'USERNAME'`
198
+ Nonce requirement:
199
+ - `nonce` is mandatory and should be retrieved using `ApiService.getNonce` before calling `generateUrl`.
200
+
201
+ Screen requirements:
202
+ - `screen.name` is optional, defaults to `'Explore'`
203
+ - When `screen.name === 'OfrDetails'`, `screen.attributes` **must** be provided and non-empty
204
+
205
+ Location / coordinates:
206
+ - If you use the location manager (see **Location & Coordinates** below) and set coordinates,
207
+ they are automatically included in the encrypted payload as `deviceInfo.location`.
208
+ - If no coordinates are set, the URL is still generated, and `location` is simply omitted.
209
+
210
+ Notes:
211
+ - The SDK requires `encryptionKey` and `pRefCode` to be initialized via `SaversAppSDK.initialized`; `generateUrl` will throw if either is missing.
212
+ - The `qP` payload is encrypted using AES-256-GCM. The encryption key must be a base64-encoded 32-byte (256-bit) value.
213
+ - The encrypted payload combines `iv`, `content`, and `tag` as `iv:content:tag` internally before being base64-encoded.
214
+
215
+ ## Navigation (End Session)
216
+
217
+ The SDK can close the current screen without knowing the host app's navigation structure. This is useful for flows initiated from web content or deep links that need to programmatically exit back to the host app.
218
+
219
+ One-time host app setup using a global `navigationRef`:
220
+
221
+ ```tsx
222
+ import { NavigationContainer, createNavigationContainerRef } from '@react-navigation/native';
223
+ import { SaversAppSDK } from '@savers_app/react-native-sdk';
224
+
225
+ export const navigationRef = createNavigationContainerRef();
226
+
227
+ export function App() {
228
+ // Initialize the SDK once (e.g., in a root effect or before rendering)
229
+ SaversAppSDK.initialized({
230
+ apiKey: 'YOUR_API_KEY',
231
+ encryptionKey: 'BASE64_256_BIT_ENCRYPTION_KEY',
232
+ pRefCode: 'PROGRAM_REF_CODE',
233
+ authMode: 'EMAIL', // or 'PHONE'
234
+ navigationRef, // pass the ref to the SDK
235
+ });
236
+
237
+ return <NavigationContainer ref={navigationRef}>{/* your navigators */}</NavigationContainer>;
238
+ }
239
+ ```
240
+
241
+ SDK API:
242
+
243
+ ```ts
244
+ import { closeCurrentScreen, closeCurrentScreenSafe } from '@savers_app/react-native-sdk';
245
+
246
+ closeCurrentScreen(); // returns boolean
247
+ closeCurrentScreenSafe(); // Android-only fallback to exitApp if it can't goBack()
248
+ ```
249
+
250
+ Notes:
251
+ - The same `navigationRef` is passed to the `NavigationContainer` and to `SaversAppSDK.initialized`.
252
+ - The SDK stores this ref internally to implement `closeCurrentScreen()` reliably.
253
+
254
+ ## WebView Integration
255
+
256
+ Trigger native actions from web & bind `onMessage` to a `WebView`:
257
+
258
+ ```ts
259
+ import { handleWebMessage } from '@savers_app/react-native-sdk';
260
+ import { WebView } from 'react-native-webview';
261
+ ...
262
+
263
+ const onMessage = (e: any) => {
264
+ const raw = e?.nativeEvent?.data;
265
+ const postBack = (data: any) => {
266
+ // send data back to the webview as needed
267
+ };
268
+ handleWebMessage(raw, postBack);
269
+ };
270
+
271
+ <WebView
272
+ originWhitelist={['*']}
273
+ source={{ html }}
274
+ onMessage={onMessage}
275
+ />;
276
+ ```
277
+
278
+
279
+
280
+ Supported actions:
281
+ - `OPEN_MAP` `{ lat, lng, label }`
282
+ - `END_SESSION`
283
+ - `SHOW_DIAL_PAD` `{ number? }`
284
+ - `MERCHANT_PORTAL_REDIRECT` `{ url }`
285
+ - `SESSION_ID` `{ sessionId }`
286
+
287
+ Note: unified WebView helpers were removed. Use `handleWebMessage` directly with `react-native-webview`.
288
+
289
+ ### Web Messaging (for Web Developers)
290
+
291
+ Your web page loaded in react-native-webview can trigger native features by posting a JSON message. Use:
292
+
293
+ ```html
294
+ <script>
295
+ function sendNative(action, payload) {
296
+ const msg = JSON.stringify({ action, payload });
297
+ window.ReactNativeWebView?.postMessage(msg);
298
+ }
299
+
300
+ // Examples:
301
+ // Open map
302
+ sendNative('OPEN_MAP', { lat: 37.7749, lng: -122.4194, label: 'San Francisco' });
303
+
304
+ // Dial pad
305
+ sendNative('SHOW_DIAL_PAD', { number: '+1234567890' });
306
+
307
+ // Open external browser
308
+ sendNative('MERCHANT_PORTAL_REDIRECT', { url: 'https://www.example.com' });
309
+
310
+ // Set session ID
311
+ sendNative('SESSION_ID', { sessionId: '123456789' });
312
+
313
+ // End session / close current screen (goBack if possible)
314
+ sendNative('END_SESSION');
315
+
316
+ // Receive postBack from native (optional)
317
+ document.addEventListener('message', function (e) {
318
+ try {
319
+ const data = JSON.parse(e.data);
320
+ console.log('Native postBack:', data);
321
+ // { ok: boolean, action: string, ...additional fields }
322
+ } catch (_) {}
323
+ });
324
+ </script>
325
+ ```
326
+
327
+ Message schema:
328
+ - `action`: one of `OPEN_MAP`, `END_SESSION`, `SHOW_DIAL_PAD`, `MERCHANT_PORTAL_REDIRECT`, `SESSION_ID`
329
+ - `payload`: object with action-specific fields:
330
+ - `OPEN_MAP`: `{ lat: number, lng: number, label?: string }`
331
+ - `SHOW_DIAL_PAD`: `{ number?: string }`
332
+ - `MERCHANT_PORTAL_REDIRECT`: `{ url: string }`
333
+ - `SESSION_ID`: `{ sessionId: string }`
334
+ - `END_SESSION`: no payload required
335
+
336
+ ## Device & Session Management
337
+
338
+ The SDK provides helpers for device id, session id, and keys:
339
+
340
+ ```ts
341
+ import {
342
+ getDeviceId,
343
+ setSessionId,
344
+ getSessionId,
345
+ getApiKey,
346
+ getEncryptionKey,
347
+ getPRefCode,
348
+ getAuthMode,
349
+ } from '@savers_app/react-native-sdk';
350
+ ```
351
+
352
+ - `getDeviceId()`: uses `react-native-device-info` to resolve a unique device id and caches it in memory and AsyncStorage.
353
+ - `setSessionId(sessionId)` / `getSessionId()`: store and retrieve a session identifier using AsyncStorage.
354
+ - `getApiKey()`, `getEncryptionKey()`, `getPRefCode()`, `getAuthMode()`: read values initialized via `SaversAppSDK.initialized`.
355
+
356
+ ## Location & Coordinates
357
+
358
+ There are two ways to work with location:
359
+
360
+ 1. **Device location service** (geolocation + permissions):
361
+
362
+ ```ts
363
+ import { getDeviceLocation } from '@savers_app/react-native-sdk';
364
+
365
+ const loc = await getDeviceLocation();
366
+ // { lat, lng } or throws if unavailable / permission denied
367
+ ```
368
+
369
+ This uses:
370
+ - `@react-native-community/geolocation`
371
+ - `ensureLocationPermission` (Android runtime permissions)
372
+ - `resolveNativeDependencies` to check if the native module is linked
373
+
374
+ 2. **Manual coordinates for URL generation**:
375
+
376
+ ```ts
377
+ import {
378
+ setLocationCoordinates,
379
+ getLocationCoordinates,
380
+ } from '@savers_app/react-native-sdk';
381
+
382
+ await setLocationCoordinates(37.7749, -122.4194);
383
+ const coords = await getLocationCoordinates(); // { lat, lng } | null
384
+ ```
385
+
386
+ If coordinates are available, `generateUrl` automatically includes them in the encrypted payload as `deviceInfo.location`. If not, the URL is still generated without `location`.
387
+
388
+ ## Maps, Dialer & Browser Helpers
389
+
390
+ ```ts
391
+ import {
392
+ openMap,
393
+ openDialPad,
394
+ callPhone,
395
+ openBrowser,
396
+ } from '@savers_app/react-native-sdk';
397
+ ```
398
+
399
+ - `openMap(lat, lng, label?)`: opens the native maps app if available, otherwise falls back to browser (Apple Maps / Google Maps).
400
+ - `openDialPad(number?)`: opens the dial pad; if a number is provided, it pre-fills the dialer.
401
+ - `callPhone(number)`: directly attempts to call the number; validates format and throws errors like `INVALID_PHONE_NUMBER` or `CALL_NOT_SUPPORTED`.
402
+ - `openBrowser(url)`: opens an external browser with the given URL.
403
+
404
+ ## Networking (ApiService)
405
+
406
+ Use the `ApiService` to make network requests with unified error handling, caching, and interceptors.
407
+
408
+ ### ApiService Overview
409
+
410
+ ```ts
411
+ import { ApiService } from '@savers_app/react-native-sdk';
412
+
413
+ const apiService = new ApiService(); // defaults to production base URL
414
+ ```
415
+
416
+ - `ApiService` uses:
417
+ - `ApiClient` (wraps `fetch` and applies interceptors)
418
+ - `ApiRepository` (adds caching strategies)
419
+ - `ApiEndpoints` (centralized endpoint paths)
420
+ - `ApiResponse<T>` model for response shape
421
+
422
+ ### Onboarding Example
423
+
424
+ ```ts
425
+ import { ApiService } from '@savers_app/react-native-sdk';
426
+
427
+ const apiService = new ApiService();
428
+
429
+ // Example: fetch onboarding data as an async generator
430
+ const fetchOnboarding = async () => {
431
+ try {
432
+ const generator = apiService.getOnBoarding();
433
+ for await (const response of generator) {
434
+ if (response.status) {
435
+ console.log('Data:', response.data);
436
+ } else {
437
+ console.error('Error:', response.message);
438
+ }
439
+ }
440
+ } catch (error) {
441
+ console.error('Request failed:', error);
442
+ }
443
+ };
444
+ ```
445
+
446
+ - Responses use the shape: `ApiResponse<T> = { data?: T | null; status?: boolean; message?: string; fromCache: boolean }`.
447
+ - `CacheStrategy` controls whether data comes from cache, network, or both.
448
+
449
+ Interceptors:
450
+ - `LoggingInterceptor`: logs requests and responses to the console.
451
+ - `NetworkInterceptor`: uses `@react-native-community/netinfo` to detect no-internet conditions and throws a unified error.
452
+ - `RetryInterceptor`: retries failed requests a configurable number of times.
453
+ - `ErrorInterceptor`: maps errors to user-friendly messages.
454
+ - `AuthInterceptor`: placeholder for attaching auth / user information to requests.
455
+ ## Example App
456
+
457
+ This repository includes an example React Native app that demonstrates most of the SDK features end‑to‑end:
458
+
459
+ - SDK initialization (`SaversAppSDK.initialized`)
460
+ - Device id, keys, session id, and coordinates usage
461
+ - URL generation (`generateUrl`) and opening the resulting URL in a browser
462
+ - Navigation and end‑session flow via `navigationRef` and `END_SESSION`
463
+ - WebView actions (`OPEN_MAP`, `SHOW_DIAL_PAD`, `MERCHANT_PORTAL_REDIRECT`, `SESSION_ID`, `END_SESSION`)
464
+ - Networking with `ApiService.getOnBoarding()`
465
+
466
+ To run the example:
467
+
468
+ ```bash
469
+ # Install dependencies (root + example workspace)
470
+ npm install
471
+ # or
472
+ yarn install
473
+
474
+ # Start the Metro bundler for the example app
475
+ yarn workspace @saversapp/react-native-sdk-example start
476
+
477
+ # Run the example app on a device / simulator (from the repo root)
478
+ yarn run:ios # uses scripts.run:ios from package.json
479
+ yarn run:android # uses scripts.run:android from package.json
480
+ ```
481
+
482
+ ## Development
483
+
484
+ Common scripts from the root library package (`package.json`):
485
+
486
+ ```bash
487
+ # Lint, typecheck, test and build the library
488
+ npm run lint
489
+ npm run typecheck
490
+ npm run test
491
+ npm run prepare # builds the library via react-native-builder-bob
492
+
493
+ # or using yarn
494
+ yarn lint
495
+ yarn typecheck
496
+ yarn test
497
+ yarn prepare
498
+
499
+ # Helper scripts to run the example app from the root
500
+ yarn run:ios
501
+ yarn run:android
502
+ ```
503
+
504
+ In the example app workspace (`@saversapp/react-native-sdk-example`), you can also run:
505
+
506
+ ```bash
507
+ yarn --workspace @saversapp/react-native-sdk-example run lint
508
+ yarn --workspace @saversapp/react-native-sdk-example run test
509
+ ```
510
+
511
+ ## Publishing to npm
512
+
513
+ This package is configured to publish to the public npm registry and uses `release-it` for versioning and release automation (see `publishConfig` and `release-it` in `package.json`).
514
+
515
+ Basic flow to publish a new version:
516
+
517
+ ```bash
518
+ # 1. Make sure you are logged in to npm
519
+ npm login
520
+
521
+ # 2. Ensure the code passes checks and is built
522
+ yarn lint
523
+ yarn typecheck
524
+ yarn test
525
+ yarn prepare
526
+
527
+ # 3. Run the release script from the repo root
528
+ # This will:
529
+ # - bump the version
530
+ # - create a git tag
531
+ # - publish to npm (using publishConfig.registry)
532
+ # - create a GitHub release
533
+ yarn release
534
+ ```
535
+
536
+ If you prefer a fully manual publish flow, you can instead:
537
+
538
+ ```bash
539
+ # Bump the version number in package.json (or use `npm version patch|minor|major`)
540
+ npm version patch
541
+
542
+ # Build the library
543
+ yarn prepare
544
+
545
+ # Publish to npm
546
+ npm publish
547
+ ```
548
+
549
+ ## Troubleshooting
550
+ - Ensure peer dependencies are installed and linked (AsyncStorage, Geolocation, NetInfo, DeviceInfo, WebView, React Navigation).
551
+ - On Android, grant runtime permissions for location when using geolocation.
552
+ - If `SaversAppSDK.initialized` logs missing modules, install the indicated packages.
553
+ - If AES‑GCM encryption fails, verify that `encryptionKey` is a base64‑encoded 32‑byte (256‑bit) value and that your Android/iOS versions meet the minimum requirements.
554
+
555
+ ## License
556
+ MIT
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=@react-native-async-storage__async-storage.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["@types/@react-native-async-storage__async-storage.d.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=@react-native-community__geolocation.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["@types/@react-native-community__geolocation.d.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=react-native-aes-gcm-crypto.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["@types/react-native-aes-gcm-crypto.d.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=react-native-device-info.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["@types/react-native-device-info.d.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ // Utilities
4
+ import { logger } from "../utils/logger.js";
5
+ import { SDKRequirements } from "../utils/dependencyManager.js";
6
+
7
+ // Data / Storage
8
+ import { setApiKey, setEncryptionKey, setPRefCode, setAuthMode } from "../data/storage/keysManager.js";
9
+ import { getDeviceId } from "../data/storage/deviceIdManager.js";
10
+ import { setReactRef } from "../data/storage/reactRefManager.js";
11
+
12
+ // Services
13
+ // import { getDeviceLocation } from '../services/device/location';
14
+
15
+ export function initializeSDK(providedKeys) {
16
+ const keys = providedKeys;
17
+ const missing = [];
18
+ if (!keys.apiKey) missing.push('apiKey');
19
+ if (!keys.encryptionKey) missing.push('encryptionKey');
20
+ if (!keys.pRefCode) missing.push('pRefCode');
21
+ if (!keys.authMode) missing.push('authMode');
22
+ if (!keys.navigationRef) missing.push('navigationRef');
23
+ if (missing.length) {
24
+ const msg = `[SDK] Missing required keys: ${missing.join(', ')}`;
25
+ logger.warn(msg);
26
+ throw new Error(msg);
27
+ }
28
+ setApiKey(keys.apiKey);
29
+ setEncryptionKey(keys.encryptionKey);
30
+ setPRefCode(keys.pRefCode);
31
+ setAuthMode(keys.authMode);
32
+ setReactRef(keys.navigationRef);
33
+ getDeviceId().then(id => {
34
+ logger.info('[SDK] Device ID availability', {
35
+ deviceId: Boolean(id)
36
+ });
37
+ }).catch(() => {
38
+ logger.warn('[SDK] Device ID unavailable');
39
+ });
40
+
41
+ // getDeviceLocation()
42
+ // .then((loc) => {
43
+ // logger.info('[SDK] Device location availability', {
44
+ // location: Boolean(loc),
45
+ // });
46
+ // })
47
+ // .catch(() => {
48
+ // logger.warn('[SDK] Device location unavailable');
49
+ // });
50
+
51
+ const {
52
+ asyncStorage,
53
+ geolocation,
54
+ deviceInfo
55
+ } = SDKRequirements;
56
+ if (asyncStorage && geolocation && deviceInfo) return;
57
+ if (!asyncStorage) {
58
+ logger.warn('[SDK] Missing AsyncStorage. Install @react-native-async-storage/async-storage for session/device features.');
59
+ }
60
+ if (!geolocation) {
61
+ logger.warn('[SDK] Missing Geolocation. Install @react-native-community/geolocation for location features.');
62
+ }
63
+ if (!deviceInfo) {
64
+ logger.warn('[SDK] Missing DeviceInfo. Install react-native-device-info for device identification.');
65
+ }
66
+ }
67
+ export const SaversAppSDK = {
68
+ initialized: initializeSDK
69
+ };
70
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["logger","SDKRequirements","setApiKey","setEncryptionKey","setPRefCode","setAuthMode","getDeviceId","setReactRef","initializeSDK","providedKeys","keys","missing","apiKey","push","encryptionKey","pRefCode","authMode","navigationRef","length","msg","join","warn","Error","then","id","info","deviceId","Boolean","catch","asyncStorage","geolocation","deviceInfo","SaversAppSDK","initialized"],"sourceRoot":"../../../src","sources":["core/runtime.ts"],"mappings":";;AAAA;AACA,SAASA,MAAM,QAAQ,oBAAiB;AACxC,SAASC,eAAe,QAAQ,+BAA4B;;AAE5D;AACA,SACEC,SAAS,EACTC,gBAAgB,EAChBC,WAAW,EACXC,WAAW,QACN,gCAA6B;AACpC,SAASC,WAAW,QAAQ,oCAAiC;AAC7D,SAASC,WAAW,QAAQ,oCAAiC;;AAE7D;AACA;;AAEA,OAAO,SAASC,aAAaA,CAACC,YAM7B,EAAE;EACD,MAAMC,IAAI,GAAGD,YAAY;EACzB,MAAME,OAAiB,GAAG,EAAE;EAC5B,IAAI,CAACD,IAAI,CAACE,MAAM,EAAED,OAAO,CAACE,IAAI,CAAC,QAAQ,CAAC;EACxC,IAAI,CAACH,IAAI,CAACI,aAAa,EAAEH,OAAO,CAACE,IAAI,CAAC,eAAe,CAAC;EACtD,IAAI,CAACH,IAAI,CAACK,QAAQ,EAAEJ,OAAO,CAACE,IAAI,CAAC,UAAU,CAAC;EAC5C,IAAI,CAACH,IAAI,CAACM,QAAQ,EAAEL,OAAO,CAACE,IAAI,CAAC,UAAU,CAAC;EAC5C,IAAI,CAACH,IAAI,CAACO,aAAa,EAAEN,OAAO,CAACE,IAAI,CAAC,eAAe,CAAC;EAEtD,IAAIF,OAAO,CAACO,MAAM,EAAE;IAClB,MAAMC,GAAG,GAAG,gCAAgCR,OAAO,CAACS,IAAI,CAAC,IAAI,CAAC,EAAE;IAChEpB,MAAM,CAACqB,IAAI,CAACF,GAAG,CAAC;IAChB,MAAM,IAAIG,KAAK,CAACH,GAAG,CAAC;EACtB;EACAjB,SAAS,CAACQ,IAAI,CAACE,MAAM,CAAC;EACtBT,gBAAgB,CAACO,IAAI,CAACI,aAAa,CAAC;EACpCV,WAAW,CAACM,IAAI,CAACK,QAAQ,CAAC;EAC1BV,WAAW,CAACK,IAAI,CAACM,QAAQ,CAAC;EAC1BT,WAAW,CAACG,IAAI,CAACO,aAAa,CAAC;EAE/BX,WAAW,CAAC,CAAC,CACViB,IAAI,CAAEC,EAAE,IAAK;IACZxB,MAAM,CAACyB,IAAI,CAAC,8BAA8B,EAAE;MAAEC,QAAQ,EAAEC,OAAO,CAACH,EAAE;IAAE,CAAC,CAAC;EACxE,CAAC,CAAC,CACDI,KAAK,CAAC,MAAM;IACX5B,MAAM,CAACqB,IAAI,CAAC,6BAA6B,CAAC;EAC5C,CAAC,CAAC;;EAEJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA,MAAM;IAAEQ,YAAY;IAAEC,WAAW;IAAEC;EAAW,CAAC,GAAG9B,eAAe;EACjE,IAAI4B,YAAY,IAAIC,WAAW,IAAIC,UAAU,EAAE;EAC/C,IAAI,CAACF,YAAY,EAAE;IACjB7B,MAAM,CAACqB,IAAI,CACT,4GACF,CAAC;EACH;EACA,IAAI,CAACS,WAAW,EAAE;IAChB9B,MAAM,CAACqB,IAAI,CACT,+FACF,CAAC;EACH;EAEA,IAAI,CAACU,UAAU,EAAE;IACf/B,MAAM,CAACqB,IAAI,CACT,uFACF,CAAC;EACH;AACF;AAEA,OAAO,MAAMW,YAAY,GAAG;EAC1BC,WAAW,EAAEzB;AACf,CAAC","ignoreList":[]}