@glomopay/react-native-sdk 2.0.2 → 3.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 (80) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/MIGRATION.md +50 -0
  3. package/README.md +348 -316
  4. package/lib/config/base.d.ts +17 -11
  5. package/lib/config/base.d.ts.map +1 -1
  6. package/lib/config/base.js +19 -7
  7. package/lib/config/segment.js +3 -3
  8. package/lib/glomo-checkout.d.ts +8 -0
  9. package/lib/glomo-checkout.d.ts.map +1 -0
  10. package/lib/glomo-checkout.js +106 -0
  11. package/lib/glomo-lrs-checkout.js +9 -9
  12. package/lib/glomo-standard-checkout.d.ts +25 -0
  13. package/lib/glomo-standard-checkout.d.ts.map +1 -0
  14. package/lib/glomo-standard-checkout.js +229 -0
  15. package/lib/glomo-subscriptions-checkout.d.ts +8 -0
  16. package/lib/glomo-subscriptions-checkout.d.ts.map +1 -0
  17. package/lib/glomo-subscriptions-checkout.js +85 -0
  18. package/lib/index.d.ts +5 -4
  19. package/lib/index.d.ts.map +1 -1
  20. package/lib/index.js +7 -5
  21. package/lib/injections/index.d.ts +1 -0
  22. package/lib/injections/index.d.ts.map +1 -1
  23. package/lib/injections/index.js +2 -0
  24. package/lib/injections/webview-flow.injection.d.ts.map +1 -1
  25. package/lib/injections/webview-flow.injection.js +106 -69
  26. package/lib/injections/webview-main.injection.d.ts.map +1 -1
  27. package/lib/injections/webview-main.injection.js +112 -77
  28. package/lib/injections/webview-standard.injection.d.ts +3 -0
  29. package/lib/injections/webview-standard.injection.d.ts.map +1 -0
  30. package/lib/injections/webview-standard.injection.js +214 -0
  31. package/lib/services/order-type-fetcher.d.ts +28 -0
  32. package/lib/services/order-type-fetcher.d.ts.map +1 -0
  33. package/lib/services/order-type-fetcher.js +99 -0
  34. package/lib/types/checkout.d.ts +65 -0
  35. package/lib/types/checkout.d.ts.map +1 -0
  36. package/lib/types/checkout.js +3 -0
  37. package/lib/types/standard-checkout.d.ts +40 -0
  38. package/lib/types/standard-checkout.d.ts.map +1 -0
  39. package/lib/types/standard-checkout.js +3 -0
  40. package/lib/types/subscriptions-checkout.d.ts +29 -0
  41. package/lib/types/subscriptions-checkout.d.ts.map +1 -0
  42. package/lib/types/subscriptions-checkout.js +3 -0
  43. package/lib/use-glomo-checkout.d.ts +54 -0
  44. package/lib/use-glomo-checkout.d.ts.map +1 -0
  45. package/lib/use-glomo-checkout.js +261 -0
  46. package/lib/use-lrs-checkout.d.ts +9 -4
  47. package/lib/use-lrs-checkout.d.ts.map +1 -1
  48. package/lib/use-lrs-checkout.js +76 -93
  49. package/lib/use-standard-checkout.d.ts +74 -0
  50. package/lib/use-standard-checkout.d.ts.map +1 -0
  51. package/lib/use-standard-checkout.js +849 -0
  52. package/lib/utils/analytics.d.ts +188 -2
  53. package/lib/utils/analytics.d.ts.map +1 -1
  54. package/lib/utils/analytics.js +636 -22
  55. package/lib/utils/device-compliance.d.ts.map +1 -1
  56. package/lib/utils/device-compliance.js +3 -4
  57. package/lib/utils/validation.d.ts.map +1 -1
  58. package/lib/utils/validation.js +7 -6
  59. package/package.json +17 -5
  60. package/src/config/base.ts +36 -17
  61. package/src/config/segment.ts +3 -3
  62. package/src/glomo-checkout.tsx +147 -0
  63. package/src/glomo-lrs-checkout.tsx +9 -9
  64. package/src/glomo-standard-checkout.tsx +353 -0
  65. package/src/glomo-subscriptions-checkout.tsx +83 -0
  66. package/src/index.ts +13 -7
  67. package/src/injections/index.ts +2 -0
  68. package/src/injections/webview-flow.injection.ts +106 -69
  69. package/src/injections/webview-main.injection.ts +112 -77
  70. package/src/injections/webview-standard.injection.ts +211 -0
  71. package/src/services/order-type-fetcher.ts +86 -0
  72. package/src/types/checkout.ts +72 -0
  73. package/src/types/standard-checkout.ts +49 -0
  74. package/src/types/subscriptions-checkout.ts +31 -0
  75. package/src/use-glomo-checkout.tsx +369 -0
  76. package/src/use-lrs-checkout.tsx +91 -111
  77. package/src/use-standard-checkout.tsx +1203 -0
  78. package/src/utils/analytics.ts +908 -34
  79. package/src/utils/device-compliance.ts +3 -4
  80. package/src/utils/validation.ts +7 -8
package/README.md CHANGED
@@ -1,135 +1,107 @@
1
- # GlomoPay React Native SDK 💳
1
+ # GlomoPay React Native SDK
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@glomopay/react-native-sdk.svg)](https://www.npmjs.com/package/@glomopay/react-native-sdk)
4
4
  [![License](https://img.shields.io/npm/l/@glomopay/react-native-sdk.svg)](LICENSE)
5
5
 
6
6
  Official React Native SDK for integrating GlomoPay payment checkout flows into your mobile applications.
7
7
 
8
- ## ✨ Features
9
-
10
- - 📱 **Cross-Platform** - Works seamlessly on both iOS and Android
11
- - 🔷 **TypeScript Support** - Full type definitions included
12
- - ⚡ **Simple Integration** - Minimal configuration required
13
- - 🔒 **Secure** - WebView-based checkout with signature verification
14
- - 🛡️ **Device Security Compliance** - Prevents unsafe/non-compliant devices from initiating checkouts as per regulatory policies
15
- - 💰 **Flexible** - Support for multiple payment methods through GlomoPay
16
-
17
- ## 📋 Prerequisites
18
-
19
- Before using this SDK, you need:
8
+ ## Prerequisites
20
9
 
21
10
  - API credentials (Public Key) from your GlomoPay dashboard
11
+ - An order ID created via the GlomoPay API
22
12
 
23
- ## 🛠️ System Requirements
24
-
25
- - React Native >= 0.68.0
26
- - React >= 17.0.0
27
- - Node.js >= 16.0.0
28
- - npm >= 8.0.0
13
+ ## System Requirements
29
14
 
30
- ## 📦 Installation
15
+ | Requirement | Version |
16
+ | ---------------------- | ------------ |
17
+ | Node.js | >= 16.0.0 |
18
+ | npm | >= 8.0.0 |
19
+ | React | >= 17.0.0 |
20
+ | React Native | >= 0.68.0 |
21
+ | react-native-webview | ^13.0.0 |
22
+ | jail-monkey (optional) | ^2.6.0 |
31
23
 
32
- ### 📲 1. Standard React Native CLI project
24
+ ## Installation
33
25
 
34
- For standard installations, this SDK requires `react-native-webview` as a peer dependency. Install it first:
26
+ ### React Native CLI
35
27
 
36
28
  ```bash
37
- npm install react-native-webview
29
+ npm install @glomopay/react-native-sdk react-native-webview
30
+ cd ios && pod install
38
31
  ```
39
32
 
40
- Then install the SDK
33
+ ### Expo
41
34
 
42
35
  ```bash
43
- npm install @glomopay/react-native-sdk
36
+ npx expo install @glomopay/react-native-sdk react-native-webview
44
37
  ```
45
38
 
46
- **🔒 Recommended: Enhanced Security Compliance**
39
+ ### Recommended: Device Security Compliance
47
40
 
48
- For enhanced device security compliance (rooted/jailbroken device detection), we HIGHLY recommend installing the peer dependency `jail-monkey`:
41
+ For rooted/jailbroken device detection (strongly recommended for regulated flows):
49
42
 
50
43
  ```bash
51
44
  npm install jail-monkey
52
45
  ```
53
46
 
54
- **Note:** The SDK works without `jail-monkey`, but installing it enables automatic device security compliance checks that help meet regulatory requirements. See [Device Security Compliance](#device-security-compliance-) section for more details.
55
-
56
- ### 🔧 2. Expo Projects
57
-
58
- This SDK is compatible with Expo projects. Install with:
59
-
60
- ```bash
61
- npx expo install react-native-webview
62
- npx expo install @glomopay/react-native-sdk
63
- ```
64
-
65
- **Note**: Requires custom dev client or EAS Build. Not compatible with Expo Go app.
66
-
67
- For Expo Go limitations, see [Expo documentation](https://docs.expo.dev/workflow/customizing/).
68
-
69
- ## 🚀 Quick Start
70
-
71
- Before start the checkout flow, you'll need to create an LRS order using other Glomo SDKs and obtain the Order ID (Alphanumeric, starts with `order_`).
47
+ The SDK works without `jail-monkey`, but installing it enables automatic device security checks. Without it, the SDK logs a warning on every `start()` call.
72
48
 
73
- ### Breaking Changes (latest)
74
-
75
- - `educationURL` has been removed from the public API. The SDK now manages any educational content behavior internally.
76
-
77
- ### 1. Import the SDK
49
+ ## Quick Start
78
50
 
79
51
  ```tsx
52
+ import React, { useRef } from "react";
53
+ import { View, Button } from "react-native";
80
54
  import {
81
- GlomoLrsCheckout,
82
- type GlomoLrsCheckoutRef,
55
+ GlomoCheckout,
56
+ type GlomoCheckoutRef,
57
+ type GlomoCheckoutPayload,
83
58
  type SdkError,
84
- } from '@glomopay/react-native-sdk';
85
- ```
86
-
87
- ### 2. Add the Component to Your App
88
-
89
- ```tsx
90
- import React, { useState, useRef } from 'react';
91
- import { View } from 'react-native';
92
- import {
93
- GlomoLrsCheckout,
94
- type GlomoLrsCheckoutRef,
95
- } from '@glomopay/react-native-sdk';
59
+ } from "@glomopay/react-native-sdk";
96
60
 
97
- function CheckoutScreen()
98
- {
99
- const [orderId, setOrderId] = useState('YOUR_ORDER_ID');
100
- const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);
61
+ export default function PaymentScreen() {
62
+ const checkoutRef = useRef<GlomoCheckoutRef>(null);
101
63
 
102
- const startLrsCheckout = () => {
103
- const started = checkoutRef.current?.start();
64
+ const handlePay = async () => {
65
+ const started = await checkoutRef.current?.start();
104
66
  if (!started) {
105
- const status = checkoutRef.current?.getStatus();
106
- console.log('Checkout could not be started. Current status:', status);
67
+ console.log("Checkout could not start - check onSdkError for details");
107
68
  }
108
69
  };
109
70
 
110
71
  return (
111
- <View>
112
- <GlomoLrsCheckout
72
+ <View style={{ flex: 1 }}>
73
+ <Button title="Pay Now" onPress={handlePay} />
74
+
75
+ <GlomoCheckout
113
76
  ref={checkoutRef}
114
- publicKey={'YOUR_PUBLIC_KEY'}
115
- orderId={orderId}
116
- onPaymentSuccess={(payload) => {
117
- console.log('Payment successful!', payload);
118
- // Handle successful payment
77
+ publicKey="live_pk_abc123"
78
+ orderId="order_xyz789"
79
+ onPaymentSuccess={(payload: GlomoCheckoutPayload) => {
80
+ console.log("Payment success:", payload.paymentId);
81
+ }}
82
+ onPaymentFailure={(payload: GlomoCheckoutPayload) => {
83
+ console.log("Payment failed:", payload.paymentId);
119
84
  }}
120
- onPaymentFailure={(payload) => {
121
- console.log('Payment failed!', payload);
122
- // Handle failed payment
85
+ onPaymentTerminate={() => {
86
+ console.log("User dismissed checkout");
123
87
  }}
124
88
  onConnectionError={(error) => {
125
- console.log('Could not open LRS checkout!', error);
126
- // Handle connection/network errors
89
+ console.log("Connection error:", error);
90
+ }}
91
+ onBankTransferSubmitted={(payload) => {
92
+ console.log("Bank transfer submitted:", payload?.transactionReference);
93
+ }}
94
+ onPayViaBankCompleted={(payload) => {
95
+ console.log("Pay via bank completed:", payload.status);
96
+ }}
97
+ onPayViaBankBankConnectionSuccessful={(payload) => {
98
+ console.log("Bank connected:", payload?.bankName);
127
99
  }}
128
- onSdkError={(errors) => {
129
- errors.forEach((error) => {
130
- console.error('SDK Error:', error.message);
131
- // Handle validation errors
132
- });
100
+ onUserRefusedCameraPermissions={() => {
101
+ console.log("User refused camera - cannot proceed with bank authentication");
102
+ }}
103
+ onSdkError={(errors: SdkError[]) => {
104
+ errors.forEach((e) => console.error(e.type, e.message, e.field));
133
105
  }}
134
106
  />
135
107
  </View>
@@ -137,314 +109,374 @@ function CheckoutScreen()
137
109
  }
138
110
  ```
139
111
 
140
- ## 📚 API Reference
112
+ ## Breaking Changes (v3)
141
113
 
142
- ### `GlomoLrsCheckout` Component
114
+ - `GlomoLrsCheckout` has been replaced by `GlomoCheckout` - the new component now works for all checkout orders (including LRS)
115
+ - `start()` is now async - returns `Promise<boolean>` instead of `boolean`
116
+ - All LRS-specific exports have been renamed (e.g. `GlomoLrsCheckoutRef` -> `GlomoCheckoutRef`)
143
117
 
144
- #### Props
118
+ For migration details, see the [Migration from v2](#migration-from-v2) section below or MIGRATION.md included in this package.
145
119
 
146
- | Prop | Type | Required | Description |
147
- |------|------|----------|-------------|
148
- | `publicKey` | `string` | Yes | Your public key. If it starts with `test_`, mock mode will be enabled automatically. Otherwise, live mode is used. |
149
- | `orderId` | `string` | Yes | The order ID for this transaction. Must start with `order_` |
150
- | `onPaymentSuccess` | `(payload: GlomoLrsCheckoutPayload) => void` | Yes | Callback function called when the payment is successful |
151
- | `onPaymentFailure` | `(payload: GlomoLrsCheckoutPayload) => void` | Yes | Callback function called when the payment fails |
152
- | `onConnectionError` | `(error: unknown) => void` | No | Will be called on network connection problems. The checkout modal will automatically close before this is triggered. |
153
- | `onPaymentTerminate` | `() => void` | No | Callback called when checkout is terminated. Triggered when the `checkout.closed` event is received from the WebView or when the user dismisses the modal (iOS swipe down) or presses the back button (Android) |
154
- | `onSdkError` | `(errors: SdkError[]) => void` | No | Callback for SDK validation errors and configuration issues. Receives an array of `SdkError` objects when validation fails. |
155
- | `devMode` | `boolean` | No | Enable debug logging (default: `false`) |
156
- | `visible` | `boolean` | No | Control modal visibility manually (advanced usage only). It is HIGHLY recommended to not use this prop directly. |
120
+ ## Subscriptions Checkout
157
121
 
158
- ### Ref Methods
122
+ To process subscription payments, pass a `subscriptionId` instead of an `orderId`:
159
123
 
160
124
  ```tsx
161
- interface GlomoLrsCheckoutRef {
162
- start: () => boolean; // Starts the checkout flow. Returns true if started, false if it cannot be started.
163
- getStatus: () => LrsCheckoutStatus; // Returns the current checkout status
164
- }
125
+ <GlomoCheckout
126
+ ref={checkoutRef}
127
+ publicKey="live_pk_abc123"
128
+ subscriptionId="sub_xyz789"
129
+ onPaymentSuccess={(payload) => {
130
+ console.log("Subscription payment success:", payload.paymentId);
131
+ }}
132
+ onPaymentFailure={(payload) => {
133
+ console.log("Subscription payment failed:", payload.paymentId);
134
+ }}
135
+ onSdkError={(errors) => {
136
+ errors.forEach((e) => console.error(e.type, e.message));
137
+ }}
138
+ />
165
139
  ```
166
140
 
167
- Usage:
141
+ When `subscriptionId` is provided:
142
+ - The SDK skips order type detection (no API call)
143
+ - The `subscriptionId` must start with `sub_`
144
+ - Bank transfer callbacks (`onBankTransferSubmitted`, `onPayViaBankCompleted`) are not applicable - subscriptions are card-only
145
+ - Do not pass both `orderId` and `subscriptionId` - the SDK will fire `onSdkError`
146
+ - The `detecting_order_type` status is not emitted for subscription flows
147
+
148
+ ## Features
149
+
150
+ - **Cross-platform** - works on both iOS and Android
151
+ - **TypeScript** - full type definitions for all exports
152
+ - **Unified checkout** - renders the correct checkout flow automatically based on your order
153
+ - **Bank transfer support** - callback for bank transfer submission events
154
+ - **Pay via bank** - bank payment flow completion and connection callbacks
155
+ - **Camera permissions** - built-in handling for bank authentication
156
+ - **Device security** - optional **(but strongly recommended)** `jail-monkey` integration for rooted/jailbroken device detection
157
+ - **Input validation** - publicKey and orderId format enforcement before checkout starts
158
+ - **Mock mode** - test with `test_` / `mock_` prefixed keys without hitting production
159
+
160
+ ## useGlomoCheckout Hook (Deprecated)
161
+
162
+ > **Deprecated** - Legacy hook, will be removed in a future major version.
163
+
164
+ `useGlomoCheckout` is a legacy placeholder from the v1.x hook-based API. In v1.x, the equivalent
165
+ hook (`useLrsCheckout`) provided reactive WebView state and rendering primitives that merchants used
166
+ to build custom checkout UIs. In v3, the inner checkout components are no longer exported, making
167
+ this hook ineffective for custom rendering.
168
+
169
+ The hook's public return type (`UseGlomoCheckoutReturn`) exposes:
170
+ - `start()` - identical to `GlomoCheckoutRef.start()`. Returns `Promise<boolean>`.
171
+ - `getStatus()` - returns a point-in-time `CheckoutStatus` snapshot. **Not reactive** - does not
172
+ trigger re-renders when status changes.
173
+
174
+ **Use the `GlomoCheckout` component with a ref instead:**
175
+
168
176
  ```tsx
169
- const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);
170
-
171
- // Start checkout - returns true if successful, false otherwise
172
- const started = checkoutRef.current?.start();
173
- if (started) {
174
- console.log('Checkout started successfully');
175
- } else {
176
- console.log('Checkout could not be started. Check the status.');
177
- }
177
+ import React, { useRef } from "react";
178
+ import { GlomoCheckout, type GlomoCheckoutRef } from "@glomopay/react-native-sdk";
179
+
180
+ const checkoutRef = useRef<GlomoCheckoutRef>(null);
181
+
182
+ // Start checkout
183
+ const started = await checkoutRef.current?.start();
184
+
185
+ // Check status (point-in-time, same as hook)
186
+ const status = checkoutRef.current?.getStatus();
187
+ ```
188
+
189
+ The component-based API provides the same functionality with proper lifecycle management.
190
+
191
+ ## API Reference
178
192
 
179
- // Check status
180
- const currentStatus = checkoutRef.current?.getStatus();
193
+ ### GlomoCheckout Component
194
+
195
+ The unified checkout component. Place it in your render tree and control it via a ref.
196
+
197
+ ```tsx
198
+ <GlomoCheckout ref={checkoutRef} {...props} />
181
199
  ```
182
200
 
183
- **Note:**
184
- - The `start()` method returns `true` if the checkout was started successfully, `false` otherwise
185
- - The `start()` method performs device compliance checks first (before any other validation) **if `jail-monkey` is installed**.
186
- - If the device is rooted or jailbroken and `jail-monkey` is available, it will return `false` and trigger the `onSdkError` callback with a `device_forbidden` error.
187
- - If `jail-monkey` is not installed, compliance checks are skipped and checkout proceeds normally.
188
- - The `start()` method may be used to restart an LRS checkout for an existing order,
189
- - If the user cancelled the payment midway (`"payment_cancelled"` status) by pressing the back button on Android, or dismissing the modal on iOS
190
- - Or if the payment failed or timed-out (`"payment_failed"` status)
191
- - After an LRS checkout for an `orderId` is successful, further calls to the `start()` method will return false, and will not re-trigger an LRS checkout (`"payment_successful"` status)
192
- - Changing the `orderId`/`publicKey` props resets the flow, and `start()` can be triggered again
193
-
194
- #### `GlomoLrsCheckoutPayload`
195
-
196
-
197
- ```typescript
198
- interface GlomoLrsCheckoutPayload {
199
- orderId: string; // Order identifier (e.g., "order_abc123")
200
- paymentId: string; // Payment id from GlomoPay
201
- signature: string; // Signature for verification
201
+ #### Props (`GlomoCheckoutProps`)
202
+
203
+ | Prop | Type | Required | Description |
204
+ | -------------------------------- | ----------------------------------------------- | -------- | ------------------------------------------------------------------- |
205
+ | `publicKey` | `string` | Yes | Your GlomoPay public key (must start with `live_`, `mock_`, or `test_`) |
206
+ | `orderId` | `string` | No* | Order ID from the GlomoPay API (must start with `order_`) |
207
+ | `subscriptionId` | `string` | No* | Subscription ID (must start with `sub_`). Bypasses order type detection. |
208
+ | `onPaymentSuccess` | `(payload: GlomoCheckoutPayload) => void` | Yes | Called when payment succeeds |
209
+ | `onPaymentFailure` | `(payload: GlomoCheckoutPayload) => void` | Yes | Called when payment fails |
210
+ | `onConnectionError` | `(error: unknown) => void` | No | Called on network/connection errors |
211
+ | `onPaymentTerminate` | `() => void` | No | Called when user dismisses checkout (back button or swipe) |
212
+ | `onSdkError` | `(errors: SdkError[]) => void` | No | Called on validation errors or device compliance failures |
213
+ | `onBankTransferSubmitted` | `(payload: GlomoBankTransferPayload \| null \| undefined) => void` | No | Called when user submits bank transfer details |
214
+ | `onPayViaBankCompleted` | `(payload: { status: string }) => void` | No | Called when pay via bank flow completes |
215
+ | `onPayViaBankBankConnectionSuccessful` | `(payload: GlomoPayViaBankConnectionPayload \| null \| undefined) => void` | No | Called when bank connection is established during pay via bank flow |
216
+ | `onUserRefusedCameraPermissions` | `() => void` | No | Called when user denies camera access needed for bank authentication |
217
+
218
+ *Exactly one of `orderId` or `subscriptionId` must be provided. If both or neither are set, `onSdkError` fires and `start()` returns `false`.
219
+
220
+ #### Ref Methods (`GlomoCheckoutRef`)
221
+
222
+ | Method | Signature | Description |
223
+ | ------------ | ------------------------ | --------------------------------------------------------------------------------------------------------- |
224
+ | `start()` | `() => Promise<boolean>` | Validates inputs, and opens the checkout modal. Resolves `true` if successful, `false` otherwise. |
225
+ | `getStatus()`| `() => CheckoutStatus` | Returns the current checkout status. |
226
+
227
+ #### CheckoutStatus
228
+
229
+ | Status | Description |
230
+ | -------------------------- | -------------------------------------------------------------- |
231
+ | `ready` | Initial state - checkout can be started |
232
+ | `detecting_order_type` | Order type detection in progress (after `start()`, before checkout opens) |
233
+ | `payment_in_progress` | Checkout modal is open, user is interacting |
234
+ | `payment_successful` | Payment completed successfully. Cannot restart with same order |
235
+ | `payment_failed` | Payment failed. Can retry with same order |
236
+ | `payment_cancelled` | User dismissed checkout mid-flow. Can retry |
237
+ | `bank_transfer_submitted` | User submitted bank transfer details |
238
+ | `pay_via_bank_completed` | Pay via bank flow completed |
239
+
240
+ ### Type Definitions
241
+
242
+ #### GlomoCheckoutPayload
243
+
244
+ ```ts
245
+ interface GlomoCheckoutPayload {
246
+ orderId: string;
247
+ paymentId: string;
248
+ signature: string;
202
249
  }
203
250
  ```
204
251
 
205
- The payload is returned for both successful and failed LRS payments.
252
+ #### GlomoBankTransferPayload
206
253
 
207
- #### `SdkError`
254
+ ```ts
255
+ interface GlomoBankTransferPayload {
256
+ orderId: string;
257
+ senderAccountNumber: string;
258
+ transactionReference: string;
259
+ }
260
+ ```
208
261
 
209
- The SDK provides validation and error reporting through the `onSdkError` callback:
262
+ #### GlomoPayViaBankConnectionPayload
210
263
 
211
- ```typescript
264
+ ```ts
265
+ interface GlomoPayViaBankConnectionPayload {
266
+ bankIdentifier: string;
267
+ cooldownPeriodInMinutes: number;
268
+ bankName: string;
269
+ bankImageSrc: string;
270
+ bankImageAlt: string;
271
+ }
272
+ ```
273
+
274
+ #### SdkError
275
+
276
+ ```ts
212
277
  interface SdkError {
213
278
  type: "validation_error" | "device_forbidden";
214
279
  message: string;
215
- field?: "publicKey" | "orderId" | "baseCheckoutUrl";
280
+ field?: "publicKey" | "orderId" | "subscriptionId" | "baseCheckoutUrl" | "generatedCheckoutUrl";
216
281
  }
217
282
  ```
218
283
 
219
- **Error Types:**
220
- - `validation_error`: Input validation failed (invalid publicKey, orderId, or server/baseCheckoutUrl)
221
- - `device_forbidden`: Device does not meet compliance requirements (LRS checkout is not permitted on compromised/rooted devices per regulatory policies).
284
+ ## Bank Transfer Support
285
+
286
+ When the checkout flow includes a bank transfer option, the user submits transfer details (account number, reference) through the checkout UI. The SDK fires `onBankTransferSubmitted` with a `GlomoBankTransferPayload`:
222
287
 
223
- **Example:**
224
288
  ```tsx
225
- <GlomoLrsCheckout
226
- onSdkError={(errors) => {
227
- errors.forEach((error) => {
228
- console.error(`SDK Error [${error.type}]:`, error.message);
229
- if (error.field) {
230
- console.error(`Field: ${error.field}`);
231
- }
232
- });
233
- // Handle validation errors appropriately
234
- }}
235
- // ... other props
236
- />
289
+ onBankTransferSubmitted={(payload) => {
290
+ // payload may be null/undefined if the checkout page omits it
291
+ console.log("Transfer ref:", payload?.transactionReference);
292
+ }}
237
293
  ```
238
294
 
239
- **Note:** The SDK validates all inputs when `start()` is called. Validation errors are reported through `onSdkError` and `start()` will return `false` if validation fails.
295
+ The checkout status transitions to `bank_transfer_submitted`.
240
296
 
241
- ##### Checkout Status System 📊
297
+ ## Pay via Bank Support
242
298
 
243
- The SDK provides a status system to track the checkout lifecycle. Access the current status using the `getStatus()` method on the component ref:
299
+ The SDK fires `onPayViaBankCompleted` when the pay-via-bank journey completes:
244
300
 
245
301
  ```tsx
246
- const checkoutRef = useRef<GlomoLrsCheckoutRef>(null);
247
- const currentStatus = checkoutRef.current?.getStatus();
302
+ onPayViaBankCompleted={(payload) => {
303
+ // payload.status - e.g. "success", "failed", "unknown"
304
+ console.log("Pay via bank status:", payload.status);
305
+ }}
248
306
  ```
249
307
 
250
- #### Status Values
308
+ The checkout status transitions to `pay_via_bank_completed`. The SDK deduplicates this event internally - the callback fires only once per checkout session.
251
309
 
252
- The `LrsCheckoutStatus` type includes the following values:
310
+ Additionally, `onPayViaBankBankConnectionSuccessful` fires when a bank account is successfully connected when initiating a pay-via-bank checkout, before the actual payment completes. This is informational only - it does not change the checkout status. Can be used to show a "bank connected" confirmation UI if desirable, while the payment continues in the background:
311
+
312
+ ```tsx
313
+ onPayViaBankBankConnectionSuccessful={(payload) => {
314
+ // payload may be null/undefined if the checkout page omits it
315
+ console.log("Connected to:", payload?.bankName);
316
+ console.log("Cooldown:", payload?.cooldownPeriodInMinutes, "minutes");
317
+ }}
318
+ ```
253
319
 
254
- | Status | Description |
255
- |--------|-------------|
256
- | `"ready"` | Checkout is ready to be started |
257
- | `"payment_in_progress"` | Checkout flow is active and ongoing |
258
- | `"payment_successful"` | Payment completed successfully |
259
- | `"payment_failed"` | Payment failed (`glomoLrsCheckoutRef.current?.start()` can be reused with the same `orderId`) |
260
- | `"payment_cancelled"` | User cancelled the checkout midway (`glomoLrsCheckoutRef.current?.start()` can be reused with the same `orderId`) |
320
+ ## Camera Permissions
261
321
 
262
- #### Status Lifecycle
322
+ Some checkout flows may require camera access for bank authentication. The SDK handles permission prompts automatically, but you must declare the permissions in your native project config.
263
323
 
324
+ ### Android
325
+
326
+ Add to `android/app/src/main/AndroidManifest.xml`:
327
+
328
+ ```xml
329
+ <uses-permission android:name="android.permission.CAMERA" />
264
330
  ```
265
- ready → payment_in_progress → payment_successful (order complete)
266
- ↓ ↑ ↑
267
- payment_cancelled (can call start() again to restart) |
268
- ↓ ↑ ↑
269
- payment_failed (can call start() again to retry) → _____⌟
331
+
332
+ ### iOS
333
+
334
+ Add to `ios/<YourApp>/Info.plist`:
335
+
336
+ ```xml
337
+ <key>NSCameraUsageDescription</key>
338
+ <string>Camera access is required for identity verification during checkout</string>
270
339
  ```
271
340
 
272
- ## 📱 Platform-Specific Behavior
341
+ ### Behavior
273
342
 
274
- ### 🍎 iOS
275
- - Checkout appears inside a modal within a `pageSheet`
276
- - Users can dismiss `GlomoLrsCheckout` component by swiping down
277
- - `onPaymentTerminate` is called when modal is dismissed
343
+ - **Android**: SDK prompts the user via a native permission dialog. If denied, checkout closes and `onUserRefusedCameraPermissions` fires.
344
+ - **iOS**: SDK grants the WebView permission request; iOS shows its own system prompt. If the user denies at the system level, the WebView handles the denial.
278
345
 
279
- ### 🤖 Android
280
- - Checkout appears in full-screen mode
281
- - Users can press the hardware back button to close the full-screen `GlomoLrsCheckout` component
282
- - Back button triggers `onPaymentTerminate` and closes checkout
346
+ ## Platform Behavior
283
347
 
284
- ## 🔧 Troubleshooting
348
+ - **iOS**: Checkout opens as a `pageSheet` modal (swipe-down to dismiss). Dismissing fires `onPaymentTerminate`.
349
+ - **Android**: Checkout opens fullscreen. The hardware back button dismisses it and fires `onPaymentTerminate`.
285
350
 
286
- ### Common Issues
351
+ ## Device Security Compliance
287
352
 
288
- #### 1. Checkout not appearing
289
- **Solution**:
290
- - Ensure `start()` is called via ref and check its return value
291
- - If `start()` returns `false`, check the current status using `getStatus()`
292
- - The checkout status must be `"ready"`, `"payment_cancelled"`, or `"payment_failed"` for `start()` to succeed
293
- - The checkout status must NOT be `"payment_successful"` (successful payments cannot be restarted)
294
- - **Device Security Compliance**: If peer dependency `jail-monkey` is installed and the device does not meet compliance requirements (the device is rooted/jailbroken), `start()` will return `false`. Check `onSdkError` callback for `device_forbidden` errors.
295
- - However, if `jail-monkey` has not been installed, security compliance checks will be skipped.
296
- - Check that `orderId` is provided and valid (must start with `order_`)
297
- - Ensure `publicKey` is valid (must start with `live_`)
298
- - Implement `onSdkError` callback to receive validation and device compliance error details
353
+ The SDK optionally integrates with `jail-monkey` to detect rooted (Android) or jailbroken (iOS) devices.
299
354
 
300
- #### 2. Expo Go "Invariant Violation" error
301
- **Solution**:
302
- - Expo Go doesn't support native modules
303
- - Use custom dev client: `npx expo prebuild`
304
- - Or use EAS Build for testing
355
+ - If `jail-monkey` is installed and the device is compromised: `start()` returns `false` and `onSdkError` fires with `type: "device_forbidden"`.
356
+ - If `jail-monkey` is installed and the device is clean: checkout proceeds normally.
357
+ - If `jail-monkey` is not installed: SDK logs a warning and proceeds without checking. This is not recommended for production deployments handling regulated transactions.
305
358
 
359
+ ## Mock Mode
306
360
 
307
- ### Debugging Mode 🛠️
361
+ The SDK infers mock mode from the `publicKey` prefix:
308
362
 
309
- Enable detailed logging:
363
+ | Prefix | Mode | Environment |
364
+ | -------- | ----- | -------------------- |
365
+ | `live_` | Live | Production |
366
+ | `test_` | Mock | Test/sandbox |
367
+ | `mock_` | Mock | Test/sandbox |
310
368
 
311
- ```tsx
312
- <GlomoLrsCheckout
313
- devMode={true}
314
- // ... other props
315
- />
316
- ```
317
- Remember to disable this in production.
369
+ Mock mode keys route to the sandbox backend. No real transactions are created.
318
370
 
319
- ### Mock Mode Testing 🧪
371
+ ## Connection Handling
320
372
 
321
- Mock mode is automatically enabled based on your `publicKey`:
373
+ The SDK detects connection errors from the WebView and fires `onConnectionError`:
322
374
 
323
- - If your `publicKey` starts with `test_` (case-insensitive), mock mode is automatically enabled and the checkout URL will include `mode=mock`
324
- - Otherwise, live mode is used and the checkout URL will include `mode=live`
375
+ - **iOS**: NSURLErrorDomain codes (-1001 timeout, -1003 host not found, -1004 connection refused, -1009 offline)
376
+ - **Android**: ERR_EMPTY_RESPONSE, ERR_CONNECTION_REFUSED, ERR_NAME_NOT_RESOLVED, ERR_INTERNET_DISCONNECTED, ERR_CONNECTION_TIMED_OUT, ERR_NETWORK_CHANGED
325
377
 
326
- **Example:**
327
- ```tsx
328
- // Mock mode (publicKey starts with "test_")
329
- <GlomoLrsCheckout
330
- publicKey="test_abc123..."
331
- // ... other props
332
- />
378
+ The checkout modal is automatically dismissed on connection errors.
333
379
 
334
- // Live mode (publicKey does not start with "test_")
335
- <GlomoLrsCheckout
336
- publicKey="live_xyz789..."
337
- // ... other props
338
- />
339
- ```
380
+ ## Input Validation
340
381
 
341
- Note that `devMode` is separate and only controls console logging, not the payment mode.
382
+ The SDK validates inputs before starting the checkout:
342
383
 
343
- ### Connection Handling 🚨
384
+ | Field | Rule |
385
+ | ---------------- | ----------------------------------------------- |
386
+ | `publicKey` | Must start with `live_`, `mock_`, or `test_`. Min 6 characters. |
387
+ | `orderId` | Must start with `order_`. Min 7 characters. Required when `subscriptionId` is absent. |
388
+ | `subscriptionId` | Must start with `sub_`. Trimmed and checked for emptiness. Required when `orderId` is absent. |
344
389
 
345
- The SDK provides an (optional) `onConnectionError` callback for connection error events. The checkout modal/page will be dismissed/closed, before this callback is triggered.
390
+ Validation failures fire `onSdkError` with `type: "validation_error"` and the relevant `field` name. `start()` returns `false`.
346
391
 
347
- **Scenarios:**
348
- - Connection failures
349
- - Internet unavailability
350
- - DNS resolution failures
392
+ Providing both `orderId` and `subscriptionId` (or neither) also fires `onSdkError`.
351
393
 
352
- **Note:** HTTP `4xx`/`5xx` errors will not be captured as connection errors.
394
+ ## Migration from v2
353
395
 
354
- **Example:**
355
- ```tsx
356
- <GlomoLrsCheckout
357
- onConnectionError={(error) => {
358
- // Handle connection/network errors
359
- // The modal will be automatically closed before this callback is triggered
360
- Alert.alert('Connection Error', 'Unable to connect to the GlomoPay servers. Please check your internet connection.');
361
- }}
362
- // ... other props
363
- />
364
- ```
396
+ v3 replaces the LRS-only `GlomoLrsCheckout` with a unified `GlomoCheckout`.
365
397
 
366
- **Note:** `onConnectionError` is for network/connection errors only. Payment-specific failures should be handled by `onPaymentFailure`.
398
+ ### Renamed Exports
367
399
 
368
- ### Device Security Compliance 🛡️
400
+ | v2 | v3 |
401
+ | -------------------------- | ------------------------- |
402
+ | `GlomoLrsCheckout` | `GlomoCheckout` |
403
+ | `GlomoLrsCheckoutRef` | `GlomoCheckoutRef` |
404
+ | `GlomoLrsCheckoutProps` | `GlomoCheckoutProps` |
405
+ | `GlomoLrsCheckoutPayload` | `GlomoCheckoutPayload` |
406
+ | `GlomoLrsServer` | `GlomoServer` |
369
407
 
370
- **⚠️ Important:** The SDK provides automatic device security compliance checking via the `jail-monkey` library. For enhanced security compliance and to meet regulatory requirements, we **strongly recommend** installing the optional peer dependency `jail-monkey`.
408
+ ### Breaking Changes
371
409
 
372
- #### Installation
410
+ - **`start()` is now async**: Returns `Promise<boolean>` instead of `boolean`. Update call sites to `await ref.current?.start()`.
411
+ - **New statuses**: `bank_transfer_submitted` and `pay_via_bank_completed` are new additions to `CheckoutStatus`.
412
+ - **New callbacks**: `onBankTransferSubmitted`, `onPayViaBankCompleted`, and `onUserRefusedCameraPermissions` are available.
373
413
 
374
- ```bash
375
- npm install jail-monkey
376
- ```
414
+ See MIGRATION.md included in this package for a standalone migration guide with before/after code examples.
377
415
 
378
- #### How It Works
416
+ ## Troubleshooting
379
417
 
380
- - **With `jail-monkey` installed:** The SDK automatically performs device security compliance checks before allowing an LRS checkout to start. Rooted (Android) or jailbroken (iOS) devices are prevented from starting checkouts.
381
- - **Without `jail-monkey`:** The SDK skips automatic compliance checks, and allows checkout to proceed normally. Regulatory compliance would have to be enforced manually.
418
+ ### `start()` returns `false`
382
419
 
383
- #### Features
420
+ Check `onSdkError` for details. Common causes:
421
+ - Invalid `publicKey` format (must start with `live_`, `mock_`, or `test_`)
422
+ - Invalid `orderId` format (must start with `order_`)
423
+ - Invalid `subscriptionId` format (must start with `sub_`, non-empty after trimming)
424
+ - Both `orderId` and `subscriptionId` provided (or neither)
425
+ - Device is rooted/jailbroken (when `jail-monkey` is installed)
384
426
 
385
- An automatic device security compliance check:
386
- - Runs synchronously as the **first validation step** in the `start()` method
387
- - Blocks checkout on non-compliant devices to meet regulatory requirements
388
- - Works on both iOS and Android platforms
389
- - Triggers the `onSdkError` callback with a `device_forbidden` error if a non-compliant device is detected
427
+ ### Checkout opens but shows a blank screen
390
428
 
391
- **Example:**
392
- ```tsx
393
- <GlomoLrsCheckout
394
- onSdkError={(errors) => {
395
- errors.forEach((error) => {
396
- if (error.type === 'device_forbidden') {
397
- Alert.alert(
398
- 'Device Unsafe',
399
- 'LRS checkout is not permitted on rooted or jailbroken devices per regulatory compliance requirements.'
400
- );
401
- }
402
- });
403
- }}
404
- // ... other props
405
- />
406
- ```
429
+ - Verify network connectivity
430
+ - Check that the `publicKey` and `orderId` are valid
407
431
 
432
+ ### Camera permission denied
408
433
 
409
- ### Input Validation 🔍
434
+ - Ensure `AndroidManifest.xml` and `Info.plist` include camera permission declarations
435
+ - The `onUserRefusedCameraPermissions` callback will fire when the user denies
410
436
 
411
- The SDK automatically validates all inputs:
437
+ ### `onPayViaBankCompleted` not firing
412
438
 
413
- - **`publicKey`**: Must start with `live_` and have a minimum length of 6 characters
414
- - **`orderId`**: Must start with `order_` and have a minimum length of 7 characters
439
+ - Ensure you are passing `onPayViaBankCompleted` as a prop to `GlomoCheckout`
415
440
 
416
- Validation errors are reported through the `onSdkError` callback. The SDK validates inputs when `start()` is called:
417
- - Device security compliance check (first, before any other validation)
418
- - Input validation (publicKey, orderId, and server environment)
419
- - Checkout URL validation (before building the final URL)
441
+ ## Exports
420
442
 
421
- **Example:**
422
- ```tsx
423
- <GlomoLrsCheckout
424
- onSdkError={(errors) => {
425
- if (errors.length > 0) {
426
- // Handle validation errors
427
- Alert.alert(
428
- 'Configuration Error',
429
- errors.map(e => e.message).join('\n')
430
- );
431
- }
432
- }}
433
- // ... other props
434
- />
443
+ ```ts
444
+ // Components
445
+ export { GlomoCheckout } from "@glomopay/react-native-sdk";
446
+
447
+ // Hooks (deprecated - use GlomoCheckout component with ref instead)
448
+ export { useGlomoCheckout } from "@glomopay/react-native-sdk";
449
+
450
+ // Types
451
+ export type {
452
+ GlomoCheckoutRef,
453
+ GlomoCheckoutProps,
454
+ GlomoCheckoutPayload,
455
+ CheckoutStatus,
456
+ GlomoBankTransferPayload,
457
+ GlomoPayViaBankConnectionPayload,
458
+ UseGlomoCheckoutReturn, // deprecated
459
+ SdkError,
460
+ } from "@glomopay/react-native-sdk";
435
461
  ```
436
462
 
437
- ## 💬 Support
463
+ ## Security
464
+
465
+ The SDK loads checkout pages in an isolated WebView. No PAN, CVV, or sensitive payment data passes through the React Native bridge - all sensitive input is handled within the WebView's sandboxed context.
466
+
467
+ Device integrity checking is available via optional `jail-monkey` integration (see [Device Security Compliance](#device-security-compliance)).
468
+
469
+ To report a security vulnerability, email security@glomopay.com. Do not open a public GitHub issue for security reports.
470
+
471
+ ## Contributing
472
+
473
+ This SDK is maintained by GlomoPay. We do not accept external contributions at this time.
438
474
 
439
- ### Documentation
440
- - 📖 API Documentation: https://docs.glomopay.com
441
- - 🎛️ Dashboard: https://dashboard.glomopay.com
475
+ ## Support
442
476
 
443
- ### Contact Us
444
- - ✉️ Email: developer@glomopay.com
445
- - 🎟️ GitHub Issues: https://github.com/glomopay/glomopay-rn-sdk/issues
446
- - 🌐 Website: https://glomopay.com
477
+ - GitHub Issues: https://github.com/glomopay/glomopay-rn-sdk/issues
478
+ - Email: developer@glomopay.com
447
479
 
448
- ## License 📄
480
+ ## License
449
481
 
450
- This project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.
482
+ Apache-2.0. See [LICENSE](LICENSE) for details.