equal-react-native-pfm-sdk 1.0.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.
- package/README.md +271 -0
- package/lib/PFMSDKManager.d.ts +19 -0
- package/lib/PFMSDKManager.d.ts.map +1 -0
- package/lib/PFMSDKManager.js +39 -0
- package/lib/PFMSDKManager.js.map +1 -0
- package/lib/PFMWebView.d.ts +19 -0
- package/lib/PFMWebView.d.ts.map +1 -0
- package/lib/PFMWebView.js +147 -0
- package/lib/PFMWebView.js.map +1 -0
- package/lib/constants.d.ts +19 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +25 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -0
- package/lib/models/EventResponse.d.ts +21 -0
- package/lib/models/EventResponse.d.ts.map +1 -0
- package/lib/models/EventResponse.js +25 -0
- package/lib/models/EventResponse.js.map +1 -0
- package/lib/models/PFMSDKConfig.d.ts +24 -0
- package/lib/models/PFMSDKConfig.d.ts.map +1 -0
- package/lib/models/PFMSDKConfig.js +13 -0
- package/lib/models/PFMSDKConfig.js.map +1 -0
- package/package.json +48 -0
- package/src/PFMSDKManager.ts +43 -0
- package/src/PFMWebView.tsx +215 -0
- package/src/constants.ts +27 -0
- package/src/index.ts +10 -0
- package/src/models/EventResponse.ts +39 -0
- package/src/models/PFMSDKConfig.ts +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# PFM Stack — React Native Integration
|
|
2
|
+
|
|
3
|
+
The PFM Stack provides an embedded React Native SDK for integrating **Personal Finance Management** into your mobile application. End-users can aggregate their financial data through the **Account Aggregator** framework with a minimal-effort integration.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
| Requirement | Minimum Version |
|
|
10
|
+
|------------------------|-----------------|
|
|
11
|
+
| React Native | 0.68+ |
|
|
12
|
+
| React | 17+ |
|
|
13
|
+
| Node.js | 16+ |
|
|
14
|
+
| Android `minSdkVersion`| 21 (Android 5.0)|
|
|
15
|
+
| iOS Deployment Target | 13.0+ |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Step 1: Initialization of SDK API
|
|
20
|
+
|
|
21
|
+
Before the consumer can access PFM features, your **backend service** must initialize the SDK by calling the **SDK Init API**.
|
|
22
|
+
|
|
23
|
+
The Init API returns an `access_token` (referred to as `token` in the SDK). This token is required to launch the PFM interface.
|
|
24
|
+
|
|
25
|
+
> Refer to the [SDK Init API documentation](https://developer.moneyone.in/pfm/sdk-init-api) for complete backend integration steps.
|
|
26
|
+
|
|
27
|
+
**Example Init API request body:**
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"reference_id": "unique_ref_id",
|
|
32
|
+
"exchange_application_id": "pfm.equal.tata_amc_uat",
|
|
33
|
+
"user_profile": {
|
|
34
|
+
"mobile_number": "9876543210",
|
|
35
|
+
"name": "User Name",
|
|
36
|
+
"dob": "18-01-1990",
|
|
37
|
+
"pan": "XXNPS9280W"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The API response contains a `session_token` — pass this value as the `token` parameter when launching the SDK.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Step 2: Add SDK as Dependency
|
|
47
|
+
|
|
48
|
+
### Using npm
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install equal-react-native-pfm-sdk
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Using yarn
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
yarn add equal-react-native-pfm-sdk
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Install peer dependency
|
|
61
|
+
|
|
62
|
+
The SDK requires `react-native-webview`. If not already in your project:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install react-native-webview
|
|
66
|
+
# or
|
|
67
|
+
yarn add react-native-webview
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### iOS — Install CocoaPods
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd ios && pod install && cd ..
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Step 3: Launch PFM SDK
|
|
79
|
+
|
|
80
|
+
### 3a. Android Configuration
|
|
81
|
+
|
|
82
|
+
Add the following provider entry inside the `<application>` tag in your `android/app/src/main/AndroidManifest.xml`. This is required by the WebView component for file handling:
|
|
83
|
+
|
|
84
|
+
```xml
|
|
85
|
+
<application
|
|
86
|
+
...>
|
|
87
|
+
|
|
88
|
+
<!-- Required for PFM SDK WebView file access -->
|
|
89
|
+
<provider
|
|
90
|
+
android:name="androidx.core.content.FileProvider"
|
|
91
|
+
android:authorities="${applicationId}.fileprovider"
|
|
92
|
+
android:exported="false"
|
|
93
|
+
android:grantUriPermissions="true">
|
|
94
|
+
<meta-data
|
|
95
|
+
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
96
|
+
android:resource="@xml/file_paths" />
|
|
97
|
+
</provider>
|
|
98
|
+
|
|
99
|
+
</application>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Ensure internet permission is declared (usually present by default):
|
|
103
|
+
|
|
104
|
+
```xml
|
|
105
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 3b. iOS Configuration
|
|
109
|
+
|
|
110
|
+
Add the following keys to your `ios/<YourApp>/Info.plist` to allow the WebView to load content and open external links:
|
|
111
|
+
|
|
112
|
+
```xml
|
|
113
|
+
<key>NSAppTransportSecurity</key>
|
|
114
|
+
<dict>
|
|
115
|
+
<key>NSAllowsArbitraryLoads</key>
|
|
116
|
+
<true/>
|
|
117
|
+
</dict>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 3c. Usage Example
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import React, { useState } from 'react';
|
|
124
|
+
import { Alert, Button, SafeAreaView, View } from 'react-native';
|
|
125
|
+
import { PFMWebView, EventResponse } from 'equal-react-native-pfm-sdk';
|
|
126
|
+
|
|
127
|
+
export default function App() {
|
|
128
|
+
const [showPFM, setShowPFM] = useState(false);
|
|
129
|
+
|
|
130
|
+
const handleClosed = (data: EventResponse) => {
|
|
131
|
+
console.log('PFM Closed:', data);
|
|
132
|
+
setShowPFM(false);
|
|
133
|
+
Alert.alert('PFM Closed', data.message);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleError = (data: EventResponse) => {
|
|
137
|
+
console.error('PFM Error:', data);
|
|
138
|
+
setShowPFM(false);
|
|
139
|
+
Alert.alert('PFM Error', data.message);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
if (showPFM) {
|
|
143
|
+
return (
|
|
144
|
+
<PFMWebView
|
|
145
|
+
token="#token" // Replace with token from SDK Init API
|
|
146
|
+
env="sandbox" // "sandbox" | "production"
|
|
147
|
+
onClosed={handleClosed}
|
|
148
|
+
onError={handleError}
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
155
|
+
<View style={{ flex: 1, justifyContent: 'center', padding: 24 }}>
|
|
156
|
+
<Button title="Launch PFM" onPress={() => setShowPFM(true)} />
|
|
157
|
+
</View>
|
|
158
|
+
</SafeAreaView>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## SDK Parameters
|
|
166
|
+
|
|
167
|
+
| Parameter | Type | Required | Default | Description |
|
|
168
|
+
|-----------|------------|----------|-------------|-----------------------------------------------------------------------------|
|
|
169
|
+
| `token` | `string` | Yes | — | Access token obtained from the SDK Init API response (`session_token`). |
|
|
170
|
+
| `env` | `string` | No | `"sandbox"` | Environment selector. Use `"production"` for live; any other value routes to UAT. |
|
|
171
|
+
| `onClosed`| `function` | Yes | — | Callback invoked when the user exits the PFM interface. |
|
|
172
|
+
| `onError` | `function` | Yes | — | Callback invoked when the SDK encounters an error. |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## SDK Callback Methods
|
|
177
|
+
|
|
178
|
+
### `onClosed`
|
|
179
|
+
|
|
180
|
+
Triggered when the user explicitly closes or exits the PFM interface. The callback receives an `EventResponse` object:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
interface EventResponse {
|
|
184
|
+
eventType: string; // "PFM_SDK_CALLBACK"
|
|
185
|
+
status: string; // "CLOSED"
|
|
186
|
+
message: string; // Human-readable description
|
|
187
|
+
statusCode?: string; // Optional HTTP-style status code
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Example:**
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
onClosed={(data) => {
|
|
195
|
+
console.log(data);
|
|
196
|
+
// {
|
|
197
|
+
// eventType: "PFM_SDK_CALLBACK",
|
|
198
|
+
// status: "CLOSED",
|
|
199
|
+
// message: "User closed",
|
|
200
|
+
// statusCode: "200"
|
|
201
|
+
// }
|
|
202
|
+
}}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### `onError`
|
|
206
|
+
|
|
207
|
+
Triggered when the PFM UI encounters an error during operation — for example, an expired token, a network failure, or a server-side issue. The callback receives the same `EventResponse` structure:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
onError={(data) => {
|
|
211
|
+
console.error(data);
|
|
212
|
+
// {
|
|
213
|
+
// eventType: "PFM_SDK_CALLBACK",
|
|
214
|
+
// status: "ERROR",
|
|
215
|
+
// message: "Token expired",
|
|
216
|
+
// statusCode: "401"
|
|
217
|
+
// }
|
|
218
|
+
}}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Environment URLs
|
|
224
|
+
|
|
225
|
+
| `env` value | Resolved URL |
|
|
226
|
+
|----------------------------------|-------------------------------------|
|
|
227
|
+
| `"production"` | `https://pfm.equal.in/pfm` |
|
|
228
|
+
| Any other value (e.g. `"sandbox"`, `"pre-prod"`) | `https://uat.pfm.equal.in/pfm` |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Project Structure
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
equal-react-native-pfm-sdk/
|
|
236
|
+
├── src/
|
|
237
|
+
│ ├── index.ts # Barrel export
|
|
238
|
+
│ ├── PFMWebView.tsx # Core WebView component
|
|
239
|
+
│ ├── PFMSDKManager.ts # URL construction logic
|
|
240
|
+
│ ├── constants.ts # Endpoints & config
|
|
241
|
+
│ └── models/
|
|
242
|
+
│ ├── PFMSDKConfig.ts # SDK configuration interface
|
|
243
|
+
│ └── EventResponse.ts # Callback event payload
|
|
244
|
+
├── __tests__/
|
|
245
|
+
│ ├── setup.ts # Jest setup & mocks
|
|
246
|
+
│ ├── models.test.ts # Model unit tests
|
|
247
|
+
│ ├── PFMSDKManager.test.ts # URL logic tests
|
|
248
|
+
│ └── PFMWebView.test.tsx # Component integration tests
|
|
249
|
+
├── example/
|
|
250
|
+
│ └── App.tsx # Example integration
|
|
251
|
+
├── package.json
|
|
252
|
+
├── tsconfig.json
|
|
253
|
+
├── jest.config.js
|
|
254
|
+
└── README.md
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Running Tests
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
npm test
|
|
263
|
+
# or
|
|
264
|
+
yarn test
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Support
|
|
270
|
+
|
|
271
|
+
For integration support, refer to the [Moneyone Developer Portal](https://developer.moneyone.in) or contact the Equal engineering team.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PFMSDKConfig } from './models/PFMSDKConfig';
|
|
2
|
+
import { EventResponse } from './models/EventResponse';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the correct PFM domain based on the environment value.
|
|
5
|
+
*
|
|
6
|
+
* - If `env` contains the substring "production" → production URL.
|
|
7
|
+
* - Otherwise → UAT URL.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getEqualDomain(env: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Builds the full gateway URL that the webview should load.
|
|
12
|
+
*
|
|
13
|
+
* @returns The URL string on success, or `null` if construction fails
|
|
14
|
+
* (in which case `onError` is invoked).
|
|
15
|
+
*
|
|
16
|
+
* URL format: `https://<domain>/pfm?access_token=<token>`
|
|
17
|
+
*/
|
|
18
|
+
export declare function getGatewayURL(config: PFMSDKConfig, onError: (data: EventResponse) => void): string | null;
|
|
19
|
+
//# sourceMappingURL=PFMSDKManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMSDKManager.d.ts","sourceRoot":"","sources":["../src/PFMSDKManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAO7E;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,GACrC,MAAM,GAAG,IAAI,CAaf"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getEqualDomain = getEqualDomain;
|
|
4
|
+
exports.getGatewayURL = getGatewayURL;
|
|
5
|
+
const PFMSDKConfig_1 = require("./models/PFMSDKConfig");
|
|
6
|
+
const EventResponse_1 = require("./models/EventResponse");
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the correct PFM domain based on the environment value.
|
|
10
|
+
*
|
|
11
|
+
* - If `env` contains the substring "production" → production URL.
|
|
12
|
+
* - Otherwise → UAT URL.
|
|
13
|
+
*/
|
|
14
|
+
function getEqualDomain(env) {
|
|
15
|
+
return env.includes('production') ? constants_1.PROD_PFM_APP_URL : constants_1.UAT_PFM_APP_URL;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Builds the full gateway URL that the webview should load.
|
|
19
|
+
*
|
|
20
|
+
* @returns The URL string on success, or `null` if construction fails
|
|
21
|
+
* (in which case `onError` is invoked).
|
|
22
|
+
*
|
|
23
|
+
* URL format: `https://<domain>/pfm?access_token=<token>`
|
|
24
|
+
*/
|
|
25
|
+
function getGatewayURL(config, onError) {
|
|
26
|
+
try {
|
|
27
|
+
const resolved = (0, PFMSDKConfig_1.resolvePFMSDKConfig)(config);
|
|
28
|
+
const domain = getEqualDomain(resolved.env);
|
|
29
|
+
const url = new URL(constants_1.PFM_PATH, domain);
|
|
30
|
+
url.searchParams.set('access_token', resolved.token);
|
|
31
|
+
return url.toString();
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
const message = 'Unable to load the PFM due to a technical error. Please try again.';
|
|
35
|
+
onError(EventResponse_1.EventResponseFactory.error(message));
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=PFMSDKManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMSDKManager.js","sourceRoot":"","sources":["../src/PFMSDKManager.ts"],"names":[],"mappings":";;AAcA,wCAEC;AAUD,sCAgBC;AA1CD,wDAA0E;AAC1E,0DAA6E;AAC7E,2CAIqB;AAErB;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,GAAW;IACxC,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,4BAAgB,CAAC,CAAC,CAAC,2BAAe,CAAC;AACzE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,aAAa,CAC3B,MAAoB,EACpB,OAAsC;IAEtC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAA,kCAAmB,EAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,oBAAQ,EAAE,MAAM,CAAC,CAAC;QACtC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,OAAO,GACX,oEAAoE,CAAC;QACvE,OAAO,CAAC,oCAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EventResponse } from './models/EventResponse';
|
|
3
|
+
export interface PFMWebViewProps {
|
|
4
|
+
/** Access token obtained from the SDK Init API. */
|
|
5
|
+
token: string;
|
|
6
|
+
/**
|
|
7
|
+
* Environment selector.
|
|
8
|
+
* - `"production"` → production endpoint
|
|
9
|
+
* - Any other value → UAT endpoint
|
|
10
|
+
* @default "sandbox"
|
|
11
|
+
*/
|
|
12
|
+
env?: string;
|
|
13
|
+
/** Fired when the user explicitly closes the PFM interface. */
|
|
14
|
+
onClosed: (data: EventResponse) => void;
|
|
15
|
+
/** Fired when the SDK encounters an error. */
|
|
16
|
+
onError: (data: EventResponse) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function PFMWebView({ token, env, onClosed, onError, }: PFMWebViewProps): React.JSX.Element;
|
|
19
|
+
//# sourceMappingURL=PFMWebView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMWebView.d.ts","sourceRoot":"","sources":["../src/PFMWebView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAc5D,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAY7E,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,+DAA+D;IAC/D,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAExC,8CAA8C;IAC9C,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACxC;AA+CD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,GAAe,EACf,QAAQ,EACR,OAAO,GACR,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAyGrC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PFMWebView = PFMWebView;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const react_native_1 = require("react-native");
|
|
39
|
+
const react_native_webview_1 = require("react-native-webview");
|
|
40
|
+
const EventResponse_1 = require("./models/EventResponse");
|
|
41
|
+
const PFMSDKManager_1 = require("./PFMSDKManager");
|
|
42
|
+
const constants_1 = require("./constants");
|
|
43
|
+
/* ------------------------------------------------------------------ */
|
|
44
|
+
/* Helpers */
|
|
45
|
+
/* ------------------------------------------------------------------ */
|
|
46
|
+
/**
|
|
47
|
+
* Returns `true` when the URL matches one of the known external patterns
|
|
48
|
+
* that should be opened in the device's default browser.
|
|
49
|
+
*/
|
|
50
|
+
function isExternalUrl(url) {
|
|
51
|
+
return constants_1.EXTERNAL_URL_PATTERNS.some((pattern) => url.includes(pattern));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parses query-parameters from a `/pfm/close` URL and invokes the
|
|
55
|
+
* appropriate callback (onClosed or onError).
|
|
56
|
+
*/
|
|
57
|
+
function handleSdkEvent(url, onClosed, onError) {
|
|
58
|
+
try {
|
|
59
|
+
const parsed = new URL(url);
|
|
60
|
+
const message = parsed.searchParams.get('message') ?? '';
|
|
61
|
+
const status = parsed.searchParams.get('status') ?? '';
|
|
62
|
+
const statusCode = parsed.searchParams.get('status_code') ?? undefined;
|
|
63
|
+
if (status === 'ERROR') {
|
|
64
|
+
onError(EventResponse_1.EventResponseFactory.error(message, statusCode));
|
|
65
|
+
}
|
|
66
|
+
else if (url.includes('CLOSED')) {
|
|
67
|
+
onClosed(EventResponse_1.EventResponseFactory.closed(message, statusCode));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Fallback — treat any other /close as a normal close.
|
|
71
|
+
onClosed(EventResponse_1.EventResponseFactory.closed(message, statusCode));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
76
|
+
onError(EventResponse_1.EventResponseFactory.error(errorMessage));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/* ------------------------------------------------------------------ */
|
|
80
|
+
/* Component */
|
|
81
|
+
/* ------------------------------------------------------------------ */
|
|
82
|
+
function PFMWebView({ token, env = 'sandbox', onClosed, onError, }) {
|
|
83
|
+
const webViewRef = (0, react_1.useRef)(null);
|
|
84
|
+
/* ---- Build the gateway URL once ---- */
|
|
85
|
+
const gatewayUrl = (0, react_1.useMemo)(() => {
|
|
86
|
+
const config = { token, env };
|
|
87
|
+
return (0, PFMSDKManager_1.getGatewayURL)(config, (err) => onError(err));
|
|
88
|
+
}, [token, env, onError]);
|
|
89
|
+
/* ---- Android hardware-back handling ---- */
|
|
90
|
+
const handleBackPress = (0, react_1.useCallback)(() => {
|
|
91
|
+
react_native_1.Alert.alert('Exit PFM', 'Are you sure you want to exit?', [
|
|
92
|
+
{ text: 'No', style: 'cancel' },
|
|
93
|
+
{
|
|
94
|
+
text: 'Yes',
|
|
95
|
+
onPress: () => onClosed(EventResponse_1.EventResponseFactory.closed('User exited via back button')),
|
|
96
|
+
},
|
|
97
|
+
], { cancelable: true });
|
|
98
|
+
return true;
|
|
99
|
+
}, [onClosed]);
|
|
100
|
+
react_1.default.useEffect(() => {
|
|
101
|
+
if (react_native_1.Platform.OS === 'android') {
|
|
102
|
+
const sub = react_native_1.BackHandler.addEventListener('hardwareBackPress', handleBackPress);
|
|
103
|
+
return () => sub.remove();
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}, [handleBackPress]);
|
|
107
|
+
/* ---- Pre-navigation interception (matches Flutter shouldOverrideUrlLoading) ---- */
|
|
108
|
+
const handleShouldStartLoad = (0, react_1.useCallback)((event) => {
|
|
109
|
+
const { url } = event;
|
|
110
|
+
// External URLs → cancel navigation, open in system browser
|
|
111
|
+
if (isExternalUrl(url)) {
|
|
112
|
+
react_native_1.Linking.openURL(url).catch(() => { });
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// /pfm/close → cancel navigation, fire callbacks
|
|
116
|
+
if (url.includes(constants_1.CLOSE_PATH)) {
|
|
117
|
+
handleSdkEvent(url, onClosed, onError);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
// All other URLs → allow navigation
|
|
121
|
+
return true;
|
|
122
|
+
}, [onClosed, onError]);
|
|
123
|
+
/* ---- Error fallback ---- */
|
|
124
|
+
if (!gatewayUrl) {
|
|
125
|
+
return react_1.default.createElement(react_native_1.View, { style: styles.container });
|
|
126
|
+
}
|
|
127
|
+
/* ---- Render ---- */
|
|
128
|
+
return (react_1.default.createElement(react_native_1.SafeAreaView, { style: styles.container },
|
|
129
|
+
react_1.default.createElement(react_native_1.StatusBar, { barStyle: "dark-content" }),
|
|
130
|
+
react_1.default.createElement(react_native_webview_1.WebView, { ref: webViewRef, testID: "pfm-webview", source: { uri: gatewayUrl }, style: styles.webview, userAgent: constants_1.CUSTOM_USER_AGENT, javaScriptEnabled: true, javaScriptCanOpenWindowsAutomatically: true, domStorageEnabled: true, allowFileAccessFromFileURLs: true, allowUniversalAccessFromFileURLs: true, mediaPlaybackRequiresUserAction: false, allowsBackForwardNavigationGestures: false, scalesPageToFit: false, thirdPartyCookiesEnabled: true, sharedCookiesEnabled: true, cacheEnabled: true, mixedContentMode: "compatibility", setSupportMultipleWindows: false, originWhitelist: ['*'], onShouldStartLoadWithRequest: handleShouldStartLoad, onError: (syntheticEvent) => {
|
|
131
|
+
const { nativeEvent } = syntheticEvent;
|
|
132
|
+
onError(EventResponse_1.EventResponseFactory.error(nativeEvent.description ?? 'WebView failed to load'));
|
|
133
|
+
} })));
|
|
134
|
+
}
|
|
135
|
+
/* ------------------------------------------------------------------ */
|
|
136
|
+
/* Styles */
|
|
137
|
+
/* ------------------------------------------------------------------ */
|
|
138
|
+
const styles = react_native_1.StyleSheet.create({
|
|
139
|
+
container: {
|
|
140
|
+
flex: 1,
|
|
141
|
+
backgroundColor: '#FFFFFF',
|
|
142
|
+
},
|
|
143
|
+
webview: {
|
|
144
|
+
flex: 1,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=PFMWebView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMWebView.js","sourceRoot":"","sources":["../src/PFMWebView.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Production PFM endpoint. */
|
|
2
|
+
export declare const PROD_PFM_APP_URL = "https://pfm.equal.in";
|
|
3
|
+
/** UAT / pre-prod PFM endpoint. */
|
|
4
|
+
export declare const UAT_PFM_APP_URL = "https://uat.pfm.equal.in";
|
|
5
|
+
/** PFM path appended to the base domain. */
|
|
6
|
+
export declare const PFM_PATH = "/pfm";
|
|
7
|
+
/** URL path fragment that signals an SDK close event. */
|
|
8
|
+
export declare const CLOSE_PATH = "/pfm/close";
|
|
9
|
+
/**
|
|
10
|
+
* External URLs that must be opened in the device's default browser
|
|
11
|
+
* rather than inside the embedded webview.
|
|
12
|
+
*/
|
|
13
|
+
export declare const EXTERNAL_URL_PATTERNS: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Custom user-agent string matching the Flutter SDK to ensure
|
|
16
|
+
* identical server-side behaviour.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CUSTOM_USER_AGENT = "Firefox/5.0 (Linux; Android 11; Nokia 8.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36";
|
|
19
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD,mCAAmC;AACnC,eAAO,MAAM,eAAe,6BAA6B,CAAC;AAE1D,4CAA4C;AAC5C,eAAO,MAAM,QAAQ,SAAS,CAAC;AAE/B,yDAAyD;AACzD,eAAO,MAAM,UAAU,eAAe,CAAC;AAEvC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAGzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,gIACiG,CAAC"}
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CUSTOM_USER_AGENT = exports.EXTERNAL_URL_PATTERNS = exports.CLOSE_PATH = exports.PFM_PATH = exports.UAT_PFM_APP_URL = exports.PROD_PFM_APP_URL = void 0;
|
|
4
|
+
/** Production PFM endpoint. */
|
|
5
|
+
exports.PROD_PFM_APP_URL = 'https://pfm.equal.in';
|
|
6
|
+
/** UAT / pre-prod PFM endpoint. */
|
|
7
|
+
exports.UAT_PFM_APP_URL = 'https://uat.pfm.equal.in';
|
|
8
|
+
/** PFM path appended to the base domain. */
|
|
9
|
+
exports.PFM_PATH = '/pfm';
|
|
10
|
+
/** URL path fragment that signals an SDK close event. */
|
|
11
|
+
exports.CLOSE_PATH = '/pfm/close';
|
|
12
|
+
/**
|
|
13
|
+
* External URLs that must be opened in the device's default browser
|
|
14
|
+
* rather than inside the embedded webview.
|
|
15
|
+
*/
|
|
16
|
+
exports.EXTERNAL_URL_PATTERNS = [
|
|
17
|
+
'https://www.tatamutualfund.com/raise-query',
|
|
18
|
+
'https://aa-uat.onemoney.in/',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Custom user-agent string matching the Flutter SDK to ensure
|
|
22
|
+
* identical server-side behaviour.
|
|
23
|
+
*/
|
|
24
|
+
exports.CUSTOM_USER_AGENT = 'Firefox/5.0 (Linux; Android 11; Nokia 8.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36';
|
|
25
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA,+BAA+B;AAClB,QAAA,gBAAgB,GAAG,sBAAsB,CAAC;AAEvD,mCAAmC;AACtB,QAAA,eAAe,GAAG,0BAA0B,CAAC;AAE1D,4CAA4C;AAC/B,QAAA,QAAQ,GAAG,MAAM,CAAC;AAE/B,yDAAyD;AAC5C,QAAA,UAAU,GAAG,YAAY,CAAC;AAEvC;;;GAGG;AACU,QAAA,qBAAqB,GAAa;IAC7C,4CAA4C;IAC5C,6BAA6B;CAC9B,CAAC;AAEF;;;GAGG;AACU,QAAA,iBAAiB,GAC5B,6HAA6H,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { PFMWebView } from './PFMWebView';
|
|
2
|
+
export type { PFMWebViewProps } from './PFMWebView';
|
|
3
|
+
export type { PFMSDKConfig } from './models/PFMSDKConfig';
|
|
4
|
+
export { resolvePFMSDKConfig } from './models/PFMSDKConfig';
|
|
5
|
+
export type { EventResponse } from './models/EventResponse';
|
|
6
|
+
export { EventResponseFactory } from './models/EventResponse';
|
|
7
|
+
export { getGatewayURL, getEqualDomain } from './PFMSDKManager';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getEqualDomain = exports.getGatewayURL = exports.EventResponseFactory = exports.resolvePFMSDKConfig = exports.PFMWebView = void 0;
|
|
4
|
+
var PFMWebView_1 = require("./PFMWebView");
|
|
5
|
+
Object.defineProperty(exports, "PFMWebView", { enumerable: true, get: function () { return PFMWebView_1.PFMWebView; } });
|
|
6
|
+
var PFMSDKConfig_1 = require("./models/PFMSDKConfig");
|
|
7
|
+
Object.defineProperty(exports, "resolvePFMSDKConfig", { enumerable: true, get: function () { return PFMSDKConfig_1.resolvePFMSDKConfig; } });
|
|
8
|
+
var EventResponse_1 = require("./models/EventResponse");
|
|
9
|
+
Object.defineProperty(exports, "EventResponseFactory", { enumerable: true, get: function () { return EventResponse_1.EventResponseFactory; } });
|
|
10
|
+
var PFMSDKManager_1 = require("./PFMSDKManager");
|
|
11
|
+
Object.defineProperty(exports, "getGatewayURL", { enumerable: true, get: function () { return PFMSDKManager_1.getGatewayURL; } });
|
|
12
|
+
Object.defineProperty(exports, "getEqualDomain", { enumerable: true, get: function () { return PFMSDKManager_1.getEqualDomain; } });
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AAInB,sDAA4D;AAAnD,mHAAA,mBAAmB,OAAA;AAG5B,wDAA8D;AAArD,qHAAA,oBAAoB,OAAA;AAE7B,iDAAgE;AAAvD,8GAAA,aAAa,OAAA;AAAE,+GAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured event payload returned through SDK callbacks.
|
|
3
|
+
*/
|
|
4
|
+
export interface EventResponse {
|
|
5
|
+
/** Discriminator for the event origin. */
|
|
6
|
+
eventType: string;
|
|
7
|
+
/** High-level outcome — e.g. "ERROR", "CLOSED". */
|
|
8
|
+
status: string;
|
|
9
|
+
/** Human-readable description of the event. */
|
|
10
|
+
message: string;
|
|
11
|
+
/** Optional status code echoed from the PFM backend. */
|
|
12
|
+
statusCode?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Factory helpers for building well-typed EventResponse objects.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EventResponseFactory: {
|
|
18
|
+
closed(message: string, statusCode?: string): EventResponse;
|
|
19
|
+
error(message: string, statusCode?: string): EventResponse;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=EventResponse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventResponse.d.ts","sourceRoot":"","sources":["../../src/models/EventResponse.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IAEf,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAEhB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;oBACf,MAAM,eAAe,MAAM,GAAG,aAAa;mBAS5C,MAAM,eAAe,MAAM,GAAG,aAAa;CAQ3D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventResponseFactory = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Factory helpers for building well-typed EventResponse objects.
|
|
6
|
+
*/
|
|
7
|
+
exports.EventResponseFactory = {
|
|
8
|
+
closed(message, statusCode) {
|
|
9
|
+
return {
|
|
10
|
+
eventType: 'PFM_SDK_CALLBACK',
|
|
11
|
+
status: 'CLOSED',
|
|
12
|
+
message,
|
|
13
|
+
statusCode,
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
error(message, statusCode) {
|
|
17
|
+
return {
|
|
18
|
+
eventType: 'PFM_SDK_CALLBACK',
|
|
19
|
+
status: 'ERROR',
|
|
20
|
+
message,
|
|
21
|
+
statusCode,
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=EventResponse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventResponse.js","sourceRoot":"","sources":["../../src/models/EventResponse.ts"],"names":[],"mappings":";;;AAiBA;;GAEG;AACU,QAAA,oBAAoB,GAAG;IAClC,MAAM,CAAC,OAAe,EAAE,UAAmB;QACzC,OAAO;YACL,SAAS,EAAE,kBAAkB;YAC7B,MAAM,EAAE,QAAQ;YAChB,OAAO;YACP,UAAU;SACX,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,UAAmB;QACxC,OAAO;YACL,SAAS,EAAE,kBAAkB;YAC7B,MAAM,EAAE,OAAO;YACf,OAAO;YACP,UAAU;SACX,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the PFM SDK.
|
|
3
|
+
*
|
|
4
|
+
* @param token - Access token obtained from the SDK Init API (required).
|
|
5
|
+
* @param env - Target environment. Use "production" for live,
|
|
6
|
+
* any other value (e.g. "pre-prod", "sandbox") routes to UAT.
|
|
7
|
+
* Defaults to "sandbox".
|
|
8
|
+
*/
|
|
9
|
+
export interface PFMSDKConfig {
|
|
10
|
+
/** Access token returned by the SDK Init API. */
|
|
11
|
+
token: string;
|
|
12
|
+
/**
|
|
13
|
+
* Environment selector.
|
|
14
|
+
* - `"production"` → production endpoint
|
|
15
|
+
* - Any other value → UAT endpoint
|
|
16
|
+
* @default "sandbox"
|
|
17
|
+
*/
|
|
18
|
+
env?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build a PFMSDKConfig with defaults applied.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolvePFMSDKConfig(config: PFMSDKConfig): Required<PFMSDKConfig>;
|
|
24
|
+
//# sourceMappingURL=PFMSDKConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMSDKConfig.d.ts","sourceRoot":"","sources":["../../src/models/PFMSDKConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,CAKhF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvePFMSDKConfig = resolvePFMSDKConfig;
|
|
4
|
+
/**
|
|
5
|
+
* Build a PFMSDKConfig with defaults applied.
|
|
6
|
+
*/
|
|
7
|
+
function resolvePFMSDKConfig(config) {
|
|
8
|
+
return {
|
|
9
|
+
token: config.token,
|
|
10
|
+
env: config.env ?? 'sandbox',
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=PFMSDKConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PFMSDKConfig.js","sourceRoot":"","sources":["../../src/models/PFMSDKConfig.ts"],"names":[],"mappings":";;AAwBA,kDAKC;AARD;;GAEG;AACH,SAAgB,mBAAmB,CAAC,MAAoB;IACtD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,SAAS;KAC7B,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "equal-react-native-pfm-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Equal PFM React Native SDK",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"react-native": "src/index.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib/",
|
|
10
|
+
"src/",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepare": "tsc",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"test:coverage": "jest --coverage",
|
|
18
|
+
"lint": "eslint src/ --ext .ts,.tsx",
|
|
19
|
+
"publish-npm": "npm publish --access public"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"pfm",
|
|
23
|
+
"sdk",
|
|
24
|
+
"react-native",
|
|
25
|
+
"equal"
|
|
26
|
+
],
|
|
27
|
+
"author": "One Equal PFM",
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"homepage": "https://www.npmjs.com/package/equal-react-native-pfm-sdk",
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": ">=17.0.0",
|
|
32
|
+
"react-native": ">=0.68.0",
|
|
33
|
+
"react-native-webview": ">=11.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@testing-library/react-native": "^12.4.0",
|
|
37
|
+
"@types/jest": "^29.5.0",
|
|
38
|
+
"@types/react": "^18.2.0",
|
|
39
|
+
"@types/react-native": "^0.72.0",
|
|
40
|
+
"jest": "^29.7.0",
|
|
41
|
+
"react": "^18.2.0",
|
|
42
|
+
"react-native": "^0.73.0",
|
|
43
|
+
"react-native-webview": "^13.6.0",
|
|
44
|
+
"react-test-renderer": "^18.2.0",
|
|
45
|
+
"typescript": "^5.3.0",
|
|
46
|
+
"@testing-library/jest-native": "^5.4.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { PFMSDKConfig, resolvePFMSDKConfig } from './models/PFMSDKConfig';
|
|
2
|
+
import { EventResponse, EventResponseFactory } from './models/EventResponse';
|
|
3
|
+
import {
|
|
4
|
+
PROD_PFM_APP_URL,
|
|
5
|
+
UAT_PFM_APP_URL,
|
|
6
|
+
PFM_PATH,
|
|
7
|
+
} from './constants';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the correct PFM domain based on the environment value.
|
|
11
|
+
*
|
|
12
|
+
* - If `env` contains the substring "production" → production URL.
|
|
13
|
+
* - Otherwise → UAT URL.
|
|
14
|
+
*/
|
|
15
|
+
export function getEqualDomain(env: string): string {
|
|
16
|
+
return env.includes('production') ? PROD_PFM_APP_URL : UAT_PFM_APP_URL;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds the full gateway URL that the webview should load.
|
|
21
|
+
*
|
|
22
|
+
* @returns The URL string on success, or `null` if construction fails
|
|
23
|
+
* (in which case `onError` is invoked).
|
|
24
|
+
*
|
|
25
|
+
* URL format: `https://<domain>/pfm?access_token=<token>`
|
|
26
|
+
*/
|
|
27
|
+
export function getGatewayURL(
|
|
28
|
+
config: PFMSDKConfig,
|
|
29
|
+
onError: (data: EventResponse) => void,
|
|
30
|
+
): string | null {
|
|
31
|
+
try {
|
|
32
|
+
const resolved = resolvePFMSDKConfig(config);
|
|
33
|
+
const domain = getEqualDomain(resolved.env);
|
|
34
|
+
const url = new URL(PFM_PATH, domain);
|
|
35
|
+
url.searchParams.set('access_token', resolved.token);
|
|
36
|
+
return url.toString();
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const message =
|
|
39
|
+
'Unable to load the PFM due to a technical error. Please try again.';
|
|
40
|
+
onError(EventResponseFactory.error(message));
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import React, { useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Alert,
|
|
4
|
+
BackHandler,
|
|
5
|
+
Linking,
|
|
6
|
+
Platform,
|
|
7
|
+
SafeAreaView,
|
|
8
|
+
StatusBar,
|
|
9
|
+
StyleSheet,
|
|
10
|
+
View,
|
|
11
|
+
} from 'react-native';
|
|
12
|
+
import { WebView } from 'react-native-webview';
|
|
13
|
+
|
|
14
|
+
import { PFMSDKConfig } from './models/PFMSDKConfig';
|
|
15
|
+
import { EventResponse, EventResponseFactory } from './models/EventResponse';
|
|
16
|
+
import { getGatewayURL } from './PFMSDKManager';
|
|
17
|
+
import {
|
|
18
|
+
CLOSE_PATH,
|
|
19
|
+
CUSTOM_USER_AGENT,
|
|
20
|
+
EXTERNAL_URL_PATTERNS,
|
|
21
|
+
} from './constants';
|
|
22
|
+
|
|
23
|
+
/* ------------------------------------------------------------------ */
|
|
24
|
+
/* Public prop types */
|
|
25
|
+
/* ------------------------------------------------------------------ */
|
|
26
|
+
|
|
27
|
+
export interface PFMWebViewProps {
|
|
28
|
+
/** Access token obtained from the SDK Init API. */
|
|
29
|
+
token: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Environment selector.
|
|
33
|
+
* - `"production"` → production endpoint
|
|
34
|
+
* - Any other value → UAT endpoint
|
|
35
|
+
* @default "sandbox"
|
|
36
|
+
*/
|
|
37
|
+
env?: string;
|
|
38
|
+
|
|
39
|
+
/** Fired when the user explicitly closes the PFM interface. */
|
|
40
|
+
onClosed: (data: EventResponse) => void;
|
|
41
|
+
|
|
42
|
+
/** Fired when the SDK encounters an error. */
|
|
43
|
+
onError: (data: EventResponse) => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ------------------------------------------------------------------ */
|
|
47
|
+
/* Helpers */
|
|
48
|
+
/* ------------------------------------------------------------------ */
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns `true` when the URL matches one of the known external patterns
|
|
52
|
+
* that should be opened in the device's default browser.
|
|
53
|
+
*/
|
|
54
|
+
function isExternalUrl(url: string): boolean {
|
|
55
|
+
return EXTERNAL_URL_PATTERNS.some((pattern) => url.includes(pattern));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parses query-parameters from a `/pfm/close` URL and invokes the
|
|
60
|
+
* appropriate callback (onClosed or onError).
|
|
61
|
+
*/
|
|
62
|
+
function handleSdkEvent(
|
|
63
|
+
url: string,
|
|
64
|
+
onClosed: (data: EventResponse) => void,
|
|
65
|
+
onError: (data: EventResponse) => void,
|
|
66
|
+
): void {
|
|
67
|
+
try {
|
|
68
|
+
const parsed = new URL(url);
|
|
69
|
+
const message = parsed.searchParams.get('message') ?? '';
|
|
70
|
+
const status = parsed.searchParams.get('status') ?? '';
|
|
71
|
+
const statusCode = parsed.searchParams.get('status_code') ?? undefined;
|
|
72
|
+
|
|
73
|
+
if (status === 'ERROR') {
|
|
74
|
+
onError(EventResponseFactory.error(message, statusCode));
|
|
75
|
+
} else if (url.includes('CLOSED')) {
|
|
76
|
+
onClosed(EventResponseFactory.closed(message, statusCode));
|
|
77
|
+
} else {
|
|
78
|
+
// Fallback — treat any other /close as a normal close.
|
|
79
|
+
onClosed(EventResponseFactory.closed(message, statusCode));
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
83
|
+
onError(EventResponseFactory.error(errorMessage));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* ------------------------------------------------------------------ */
|
|
88
|
+
/* Component */
|
|
89
|
+
/* ------------------------------------------------------------------ */
|
|
90
|
+
|
|
91
|
+
export function PFMWebView({
|
|
92
|
+
token,
|
|
93
|
+
env = 'sandbox',
|
|
94
|
+
onClosed,
|
|
95
|
+
onError,
|
|
96
|
+
}: PFMWebViewProps): React.JSX.Element {
|
|
97
|
+
const webViewRef = useRef<WebView>(null);
|
|
98
|
+
|
|
99
|
+
/* ---- Build the gateway URL once ---- */
|
|
100
|
+
const gatewayUrl = useMemo(() => {
|
|
101
|
+
const config: PFMSDKConfig = { token, env };
|
|
102
|
+
return getGatewayURL(config, (err) => onError(err));
|
|
103
|
+
}, [token, env, onError]);
|
|
104
|
+
|
|
105
|
+
/* ---- Android hardware-back handling ---- */
|
|
106
|
+
const handleBackPress = useCallback(() => {
|
|
107
|
+
Alert.alert(
|
|
108
|
+
'Exit PFM',
|
|
109
|
+
'Are you sure you want to exit?',
|
|
110
|
+
[
|
|
111
|
+
{ text: 'No', style: 'cancel' },
|
|
112
|
+
{
|
|
113
|
+
text: 'Yes',
|
|
114
|
+
onPress: () =>
|
|
115
|
+
onClosed(
|
|
116
|
+
EventResponseFactory.closed('User exited via back button'),
|
|
117
|
+
),
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
{ cancelable: true },
|
|
121
|
+
);
|
|
122
|
+
return true;
|
|
123
|
+
}, [onClosed]);
|
|
124
|
+
|
|
125
|
+
React.useEffect(() => {
|
|
126
|
+
if (Platform.OS === 'android') {
|
|
127
|
+
const sub = BackHandler.addEventListener(
|
|
128
|
+
'hardwareBackPress',
|
|
129
|
+
handleBackPress,
|
|
130
|
+
);
|
|
131
|
+
return () => sub.remove();
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}, [handleBackPress]);
|
|
135
|
+
|
|
136
|
+
/* ---- Pre-navigation interception (matches Flutter shouldOverrideUrlLoading) ---- */
|
|
137
|
+
const handleShouldStartLoad = useCallback(
|
|
138
|
+
(event: { url: string }): boolean => {
|
|
139
|
+
const { url } = event;
|
|
140
|
+
|
|
141
|
+
// External URLs → cancel navigation, open in system browser
|
|
142
|
+
if (isExternalUrl(url)) {
|
|
143
|
+
Linking.openURL(url).catch(() => {});
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// /pfm/close → cancel navigation, fire callbacks
|
|
148
|
+
if (url.includes(CLOSE_PATH)) {
|
|
149
|
+
handleSdkEvent(url, onClosed, onError);
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// All other URLs → allow navigation
|
|
154
|
+
return true;
|
|
155
|
+
},
|
|
156
|
+
[onClosed, onError],
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/* ---- Error fallback ---- */
|
|
160
|
+
if (!gatewayUrl) {
|
|
161
|
+
return <View style={styles.container} />;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ---- Render ---- */
|
|
165
|
+
return (
|
|
166
|
+
<SafeAreaView style={styles.container}>
|
|
167
|
+
<StatusBar barStyle="dark-content" />
|
|
168
|
+
|
|
169
|
+
<WebView
|
|
170
|
+
ref={webViewRef}
|
|
171
|
+
testID="pfm-webview"
|
|
172
|
+
source={{ uri: gatewayUrl }}
|
|
173
|
+
style={styles.webview}
|
|
174
|
+
userAgent={CUSTOM_USER_AGENT}
|
|
175
|
+
javaScriptEnabled
|
|
176
|
+
javaScriptCanOpenWindowsAutomatically
|
|
177
|
+
domStorageEnabled
|
|
178
|
+
allowFileAccessFromFileURLs
|
|
179
|
+
allowUniversalAccessFromFileURLs
|
|
180
|
+
mediaPlaybackRequiresUserAction={false}
|
|
181
|
+
allowsBackForwardNavigationGestures={false}
|
|
182
|
+
scalesPageToFit={false}
|
|
183
|
+
thirdPartyCookiesEnabled={true}
|
|
184
|
+
sharedCookiesEnabled={true}
|
|
185
|
+
cacheEnabled={true}
|
|
186
|
+
mixedContentMode="compatibility"
|
|
187
|
+
setSupportMultipleWindows={false}
|
|
188
|
+
originWhitelist={['*']}
|
|
189
|
+
onShouldStartLoadWithRequest={handleShouldStartLoad}
|
|
190
|
+
onError={(syntheticEvent) => {
|
|
191
|
+
const { nativeEvent } = syntheticEvent;
|
|
192
|
+
onError(
|
|
193
|
+
EventResponseFactory.error(
|
|
194
|
+
nativeEvent.description ?? 'WebView failed to load',
|
|
195
|
+
),
|
|
196
|
+
);
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
</SafeAreaView>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* ------------------------------------------------------------------ */
|
|
204
|
+
/* Styles */
|
|
205
|
+
/* ------------------------------------------------------------------ */
|
|
206
|
+
|
|
207
|
+
const styles = StyleSheet.create({
|
|
208
|
+
container: {
|
|
209
|
+
flex: 1,
|
|
210
|
+
backgroundColor: '#FFFFFF',
|
|
211
|
+
},
|
|
212
|
+
webview: {
|
|
213
|
+
flex: 1,
|
|
214
|
+
},
|
|
215
|
+
});
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Production PFM endpoint. */
|
|
2
|
+
export const PROD_PFM_APP_URL = 'https://pfm.equal.in';
|
|
3
|
+
|
|
4
|
+
/** UAT / pre-prod PFM endpoint. */
|
|
5
|
+
export const UAT_PFM_APP_URL = 'https://uat.pfm.equal.in';
|
|
6
|
+
|
|
7
|
+
/** PFM path appended to the base domain. */
|
|
8
|
+
export const PFM_PATH = '/pfm';
|
|
9
|
+
|
|
10
|
+
/** URL path fragment that signals an SDK close event. */
|
|
11
|
+
export const CLOSE_PATH = '/pfm/close';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* External URLs that must be opened in the device's default browser
|
|
15
|
+
* rather than inside the embedded webview.
|
|
16
|
+
*/
|
|
17
|
+
export const EXTERNAL_URL_PATTERNS: string[] = [
|
|
18
|
+
'https://www.tatamutualfund.com/raise-query',
|
|
19
|
+
'https://aa-uat.onemoney.in/',
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Custom user-agent string matching the Flutter SDK to ensure
|
|
24
|
+
* identical server-side behaviour.
|
|
25
|
+
*/
|
|
26
|
+
export const CUSTOM_USER_AGENT =
|
|
27
|
+
'Firefox/5.0 (Linux; Android 11; Nokia 8.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { PFMWebView } from './PFMWebView';
|
|
2
|
+
export type { PFMWebViewProps } from './PFMWebView';
|
|
3
|
+
|
|
4
|
+
export type { PFMSDKConfig } from './models/PFMSDKConfig';
|
|
5
|
+
export { resolvePFMSDKConfig } from './models/PFMSDKConfig';
|
|
6
|
+
|
|
7
|
+
export type { EventResponse } from './models/EventResponse';
|
|
8
|
+
export { EventResponseFactory } from './models/EventResponse';
|
|
9
|
+
|
|
10
|
+
export { getGatewayURL, getEqualDomain } from './PFMSDKManager';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured event payload returned through SDK callbacks.
|
|
3
|
+
*/
|
|
4
|
+
export interface EventResponse {
|
|
5
|
+
/** Discriminator for the event origin. */
|
|
6
|
+
eventType: string;
|
|
7
|
+
|
|
8
|
+
/** High-level outcome — e.g. "ERROR", "CLOSED". */
|
|
9
|
+
status: string;
|
|
10
|
+
|
|
11
|
+
/** Human-readable description of the event. */
|
|
12
|
+
message: string;
|
|
13
|
+
|
|
14
|
+
/** Optional status code echoed from the PFM backend. */
|
|
15
|
+
statusCode?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Factory helpers for building well-typed EventResponse objects.
|
|
20
|
+
*/
|
|
21
|
+
export const EventResponseFactory = {
|
|
22
|
+
closed(message: string, statusCode?: string): EventResponse {
|
|
23
|
+
return {
|
|
24
|
+
eventType: 'PFM_SDK_CALLBACK',
|
|
25
|
+
status: 'CLOSED',
|
|
26
|
+
message,
|
|
27
|
+
statusCode,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
error(message: string, statusCode?: string): EventResponse {
|
|
32
|
+
return {
|
|
33
|
+
eventType: 'PFM_SDK_CALLBACK',
|
|
34
|
+
status: 'ERROR',
|
|
35
|
+
message,
|
|
36
|
+
statusCode,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the PFM SDK.
|
|
3
|
+
*
|
|
4
|
+
* @param token - Access token obtained from the SDK Init API (required).
|
|
5
|
+
* @param env - Target environment. Use "production" for live,
|
|
6
|
+
* any other value (e.g. "pre-prod", "sandbox") routes to UAT.
|
|
7
|
+
* Defaults to "sandbox".
|
|
8
|
+
*/
|
|
9
|
+
export interface PFMSDKConfig {
|
|
10
|
+
/** Access token returned by the SDK Init API. */
|
|
11
|
+
token: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Environment selector.
|
|
15
|
+
* - `"production"` → production endpoint
|
|
16
|
+
* - Any other value → UAT endpoint
|
|
17
|
+
* @default "sandbox"
|
|
18
|
+
*/
|
|
19
|
+
env?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build a PFMSDKConfig with defaults applied.
|
|
24
|
+
*/
|
|
25
|
+
export function resolvePFMSDKConfig(config: PFMSDKConfig): Required<PFMSDKConfig> {
|
|
26
|
+
return {
|
|
27
|
+
token: config.token,
|
|
28
|
+
env: config.env ?? 'sandbox',
|
|
29
|
+
};
|
|
30
|
+
}
|