@finspringinnovations/fdsdk 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/baseApi.js +17 -6
- package/lib/api/masterDataApi.js +21 -1
- package/lib/api/workflowApi.js +46 -1
- package/lib/config/appDataConfig.d.ts +5 -0
- package/lib/hooks/usePaymentSSE.d.ts +7 -1
- package/lib/hooks/usePaymentSSE.js +287 -63
- package/lib/navigation/RootNavigator.js +10 -2
- package/lib/screens/AadhaarVerification.js +2 -2
- package/lib/screens/FDCalculator.js +6 -2
- package/lib/screens/FDList.js +37 -64
- package/lib/screens/Payment.js +159 -27
- package/lib/screens/PaymentStatus.js +139 -25
- package/lib/screens/ReviewKYC.js +45 -97
- package/lib/utils/sseParser.js +19 -3
- package/package.json +1 -1
- package/src/api/baseApi.ts +19 -6
- package/src/api/masterDataApi.ts +21 -3
- package/src/api/workflowApi.ts +50 -1
- package/src/config/appDataConfig.ts +5 -0
- package/src/hooks/usePaymentSSE.ts +307 -66
- package/src/navigation/RootNavigator.tsx +8 -2
- package/src/screens/AadhaarVerification.tsx +2 -2
- package/src/screens/FDCalculator.tsx +7 -2
- package/src/screens/FDList.tsx +37 -76
- package/src/screens/Payment.tsx +181 -38
- package/src/screens/PaymentStatus.tsx +158 -43
- package/src/screens/ReviewKYC.tsx +94 -170
- package/src/utils/sseParser.ts +20 -4
package/lib/api/baseApi.js
CHANGED
|
@@ -237,7 +237,7 @@ const generateRequestId = () => (0, uuid_1.v4)();
|
|
|
237
237
|
// Custom Base Query with Encryption
|
|
238
238
|
// ------------------------------
|
|
239
239
|
const baseQueryWithEncryption = async (args, api, extraOptions) => {
|
|
240
|
-
var _a, _b, _c, _d, _e, _f
|
|
240
|
+
var _a, _b, _c, _d, _e, _f;
|
|
241
241
|
const apiConfig = ensureApiConfig(); // 👈 Load config before first API call
|
|
242
242
|
const encryptionConfig = (0, encryptionConfig_1.getEncryptionConfig)();
|
|
243
243
|
const requestId = generateRequestId();
|
|
@@ -295,6 +295,10 @@ const baseQueryWithEncryption = async (args, api, extraOptions) => {
|
|
|
295
295
|
timeout: apiConfig.timeout,
|
|
296
296
|
prepareHeaders: (headers, { getState }) => {
|
|
297
297
|
var _a, _b;
|
|
298
|
+
// Disable HTTP-level caching for all SDK API calls
|
|
299
|
+
headers.set('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
300
|
+
headers.set('Pragma', 'no-cache');
|
|
301
|
+
headers.set('Expires', '0');
|
|
298
302
|
const token = (_b = (_a = getState()) === null || _a === void 0 ? void 0 : _a.auth) === null || _b === void 0 ? void 0 : _b.token;
|
|
299
303
|
if (token)
|
|
300
304
|
headers.set('authorization', `Bearer ${token}`);
|
|
@@ -391,9 +395,13 @@ const baseQueryWithEncryption = async (args, api, extraOptions) => {
|
|
|
391
395
|
}
|
|
392
396
|
// Log response
|
|
393
397
|
const duration = Date.now() - timestamp;
|
|
398
|
+
const statusFromMeta = (_b = (_a = result.meta) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.status;
|
|
399
|
+
const statusFromError = typeof ((_c = result.error) === null || _c === void 0 ? void 0 : _c.status) === 'number' ? result.error.status : undefined;
|
|
400
|
+
const status = (_d = statusFromMeta !== null && statusFromMeta !== void 0 ? statusFromMeta : statusFromError) !== null && _d !== void 0 ? _d : (result.error ? 0 : 200);
|
|
401
|
+
const statusText = ((_f = (_e = result.meta) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.statusText) || (result.error ? 'ERROR' : 'OK');
|
|
394
402
|
const responseLogData = {
|
|
395
|
-
status
|
|
396
|
-
statusText
|
|
403
|
+
status,
|
|
404
|
+
statusText,
|
|
397
405
|
headers: {},
|
|
398
406
|
data: result.data,
|
|
399
407
|
timestamp: Date.now(),
|
|
@@ -405,8 +413,7 @@ const baseQueryWithEncryption = async (args, api, extraOptions) => {
|
|
|
405
413
|
apiLogger_1.apiLogger.logResponse(responseLogData);
|
|
406
414
|
// Log response details in DEV mode (AFTER decryption)
|
|
407
415
|
if (__DEV__) {
|
|
408
|
-
const
|
|
409
|
-
const isSuccess = status >= 200 && status < 300;
|
|
416
|
+
const isSuccess = !result.error && status >= 200 && status < 300;
|
|
410
417
|
console.log('═══════════════════════════════════════════════════════════════');
|
|
411
418
|
console.log(isSuccess ? '✅ [ShriramSDK] API RESPONSE - SUCCESS' : '❌ [ShriramSDK] API RESPONSE - ERROR');
|
|
412
419
|
console.log('───────────────────────────────────────────────────────────────');
|
|
@@ -414,7 +421,7 @@ const baseQueryWithEncryption = async (args, api, extraOptions) => {
|
|
|
414
421
|
console.log('🔗 Endpoint:', url);
|
|
415
422
|
console.log('📌 Full URL:', `${apiConfig.baseUrl}${url}`);
|
|
416
423
|
console.log('🔧 Method:', method);
|
|
417
|
-
console.log('📊 Status:', status,
|
|
424
|
+
console.log('📊 Status:', status, statusText);
|
|
418
425
|
console.log('⏱️ Duration:', `${duration}ms`);
|
|
419
426
|
console.log('🔐 Encryption:', currentEncryptionState ? 'Enabled' : 'Disabled');
|
|
420
427
|
console.log('🆔 Request ID:', requestId);
|
|
@@ -451,6 +458,10 @@ exports.baseApi = (0, react_1.createApi)({
|
|
|
451
458
|
baseQuery: baseQueryWithEncryption,
|
|
452
459
|
tagTypes: ['InterestRate'],
|
|
453
460
|
endpoints: () => ({}),
|
|
461
|
+
keepUnusedDataFor: 0,
|
|
462
|
+
refetchOnMountOrArgChange: true,
|
|
463
|
+
refetchOnFocus: true,
|
|
464
|
+
refetchOnReconnect: true,
|
|
454
465
|
});
|
|
455
466
|
// Export hooks
|
|
456
467
|
exports.usePrefetch = exports.baseApi.usePrefetch;
|
package/lib/api/masterDataApi.js
CHANGED
|
@@ -13,17 +13,37 @@ exports.masterDataApi = baseApi_1.baseApi.injectEndpoints({
|
|
|
13
13
|
const request = {
|
|
14
14
|
url: 'masterdata',
|
|
15
15
|
method: 'GET',
|
|
16
|
+
cache: 'no-store',
|
|
16
17
|
headers: {
|
|
17
18
|
workflowInstanceId: '{{workflowInstanceId}}',
|
|
18
19
|
'x-api-key': '{{X-API-KEY}}',
|
|
19
20
|
encryptdecrypt: 'false',
|
|
21
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
22
|
+
Pragma: 'no-cache',
|
|
23
|
+
Expires: '0',
|
|
20
24
|
provider: providerId || '{{shriramprovider}}',
|
|
21
25
|
},
|
|
22
26
|
};
|
|
23
27
|
return request;
|
|
24
28
|
},
|
|
25
29
|
transformResponse: (response) => {
|
|
26
|
-
|
|
30
|
+
if (response == null)
|
|
31
|
+
return response;
|
|
32
|
+
// If API returns a JSON string, parse it
|
|
33
|
+
let data = response;
|
|
34
|
+
if (typeof response === 'string') {
|
|
35
|
+
try {
|
|
36
|
+
data = JSON.parse(response);
|
|
37
|
+
}
|
|
38
|
+
catch (_a) {
|
|
39
|
+
return response;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Unwrap { data: ... } so consumers get a consistent shape
|
|
43
|
+
if (typeof data === 'object' && data !== null && 'data' in data && Object.keys(data).length === 1) {
|
|
44
|
+
return data.data;
|
|
45
|
+
}
|
|
46
|
+
return data;
|
|
27
47
|
},
|
|
28
48
|
}),
|
|
29
49
|
}),
|
package/lib/api/workflowApi.js
CHANGED
|
@@ -13,6 +13,37 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.usePreviousStateMutation = exports.useUpdateStateMutation = exports.useUpdateTaskMutation = exports.useTerminateWorkflowMutation = exports.workflowApi = void 0;
|
|
15
15
|
const baseApi_1 = require("./baseApi");
|
|
16
|
+
const TASK_ID_TO_CAPTION = {
|
|
17
|
+
'11042': 'SHRIRAM_V1_S1_T1_START',
|
|
18
|
+
'11043': 'SHRIRAM_V1_S1_T2_GET_PERSONAL_DETAILS_AND_BASIC_FD_INFO',
|
|
19
|
+
'11044': 'SHRIRAM_V1_S1_T3_END',
|
|
20
|
+
'11050': 'SHRIRAM_V1_S2_T1_KYC_START',
|
|
21
|
+
'11051': 'SHRIRAM_V1_S2_T2_CHECK_FOR_PAN_RAPID_STATUS',
|
|
22
|
+
'11052': 'SHRIRAM_V1_S2_T3_CHECK_IF_AADHAAR_ALREADY_VERIFIED',
|
|
23
|
+
'11045': 'SHRIRAM_V1_S2_T4_SEND_AADHAR_OTP',
|
|
24
|
+
'11046': 'SHRIRAM_V1_S2_T5_CHECK_FOR_OTP',
|
|
25
|
+
'11047': 'SHRIRAM_V1_S2_T6_VALIDATE_AADHAR_OTP',
|
|
26
|
+
'11053': 'SHRIRAM_V1_S2_T7_AADHAAR_VERIFIED',
|
|
27
|
+
'11049': 'SHRIRAM_V1_S2_T8_TERMINATE_TASK_AND_WORKFLOW_AFTER_KYC_RETRIES',
|
|
28
|
+
'11048': 'SHRIRAM_V1_S2_T9_KYC_END',
|
|
29
|
+
'11054': 'SHRIRAM_V1_S3_T1_OCCUPATION_START',
|
|
30
|
+
'11055': 'SHRIRAM_V1_S3_T2_CAPTURE_OCCUPATION_DETAILS',
|
|
31
|
+
'11056': 'SHRIRAM_V1_S3_T3_OCCUPATION_END',
|
|
32
|
+
'11057': 'SHRIRAM_V1_S4_T1_NOMINEE_START',
|
|
33
|
+
'11058': 'SHRIRAM_V1_S4_T2_CAPTURE_NOMINEE_DETAILS',
|
|
34
|
+
'11059': 'SHRIRAM_V1_S4_T3_NOMINEE_END',
|
|
35
|
+
'11060': 'SHRIRAM_V1_S5_T1_BANK_DETAILS_START',
|
|
36
|
+
'11061': 'SHRIRAM_V1_S5_T2_CAPTURE_BANK_DETAILS',
|
|
37
|
+
'11062': 'SHRIRAM_V1_S5_T3_BANK_DETAILS_END',
|
|
38
|
+
'11063': 'SHRIRAM_V1_S6_T1_FD_CREATION_START',
|
|
39
|
+
'11064': 'SHRIRAM_V1_S6_T2_CREATE_FD',
|
|
40
|
+
'11065': 'SHRIRAM_V1_S6_T3_FD_CREATION_END',
|
|
41
|
+
'11069': 'SHRIRAM_V1_S7_T1_PAYMENT_START',
|
|
42
|
+
'11068': 'SHRIRAM_V1_S7_T2_PAYMENT',
|
|
43
|
+
'11067': 'SHRIRAM_V1_S7_T3_CHECK_FOR_PAYMENT_STATUS',
|
|
44
|
+
'11070': 'SHRIRAM_V1_S7_T4_TERMINATE_TASK_AND_WORKFLOW_AFTER_PAYMENT_RETRIES',
|
|
45
|
+
'11066': 'SHRIRAM_V1_S7_T5_PAYMENT_END',
|
|
46
|
+
};
|
|
16
47
|
exports.workflowApi = baseApi_1.baseApi.injectEndpoints({
|
|
17
48
|
endpoints: (builder) => ({
|
|
18
49
|
terminateWorkflow: builder.mutation({
|
|
@@ -37,10 +68,24 @@ exports.workflowApi = baseApi_1.baseApi.injectEndpoints({
|
|
|
37
68
|
updateTask: builder.mutation({
|
|
38
69
|
query: (body) => {
|
|
39
70
|
const { providerId, workflowInstanceId, userreferenceid, applicationid, entityid } = body, requestBody = __rest(body, ["providerId", "workflowInstanceId", "userreferenceid", "applicationid", "entityid"]);
|
|
71
|
+
const normalizedRequestBody = Object.assign({}, requestBody);
|
|
72
|
+
// Backend now expects caption-based field name.
|
|
73
|
+
// Keep compatibility if any caller still passes targetTaskId.
|
|
74
|
+
if (!normalizedRequestBody.targetTaskCaption && normalizedRequestBody.targetTaskId) {
|
|
75
|
+
normalizedRequestBody.targetTaskCaption = normalizedRequestBody.targetTaskId;
|
|
76
|
+
delete normalizedRequestBody.targetTaskId;
|
|
77
|
+
}
|
|
78
|
+
// Normalize numeric task IDs to caption values if provided.
|
|
79
|
+
if (normalizedRequestBody.targetTaskCaption !== undefined && normalizedRequestBody.targetTaskCaption !== null) {
|
|
80
|
+
const key = String(normalizedRequestBody.targetTaskCaption).trim();
|
|
81
|
+
if (TASK_ID_TO_CAPTION[key]) {
|
|
82
|
+
normalizedRequestBody.targetTaskCaption = TASK_ID_TO_CAPTION[key];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
40
85
|
return {
|
|
41
86
|
url: 'taskflow/update',
|
|
42
87
|
method: 'POST',
|
|
43
|
-
body: Object.assign(Object.assign({},
|
|
88
|
+
body: Object.assign(Object.assign({}, normalizedRequestBody), { workflowInstanceId: workflowInstanceId }),
|
|
44
89
|
headers: {
|
|
45
90
|
provider: providerId || '{{shriramprovider}}',
|
|
46
91
|
workflowInstanceId: workflowInstanceId || '{{workflowInstanceId}}',
|
|
@@ -4,6 +4,11 @@ export interface EnvironmentData {
|
|
|
4
4
|
apiKey?: string;
|
|
5
5
|
encryptionKey?: string;
|
|
6
6
|
enableLogging?: boolean;
|
|
7
|
+
sseMinimalLogs?: boolean;
|
|
8
|
+
enableVerboseSSELogging?: boolean;
|
|
9
|
+
sseReconnectAttempts?: number;
|
|
10
|
+
sseReconnectDelayMs?: number;
|
|
11
|
+
sseConnectTimeoutMs?: number;
|
|
7
12
|
}
|
|
8
13
|
/**
|
|
9
14
|
* Custom color overrides that can be passed during SDK initialization.
|
|
@@ -17,8 +17,14 @@ interface UsePaymentSSECallbacks {
|
|
|
17
17
|
onError?: (error: any) => void;
|
|
18
18
|
onConnected?: () => void;
|
|
19
19
|
}
|
|
20
|
+
export interface PaymentSSEExtraHeaders {
|
|
21
|
+
workflowInstanceId?: string;
|
|
22
|
+
applicationId?: string;
|
|
23
|
+
entityid?: string;
|
|
24
|
+
providerId?: string;
|
|
25
|
+
}
|
|
20
26
|
export declare function usePaymentSSE(): {
|
|
21
|
-
start: (applicationId: string, callbacks: UsePaymentSSECallbacks) => void;
|
|
27
|
+
start: (applicationId: string, callbacks: UsePaymentSSECallbacks, extraHeaders?: PaymentSSEExtraHeaders) => void;
|
|
22
28
|
stop: () => void;
|
|
23
29
|
};
|
|
24
30
|
export {};
|
|
@@ -16,111 +16,335 @@
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.usePaymentSSE = usePaymentSSE;
|
|
18
18
|
const react_1 = require("react");
|
|
19
|
+
const react_native_1 = require("react-native");
|
|
19
20
|
const sseParser_1 = require("../utils/sseParser");
|
|
20
21
|
const appDataConfig_1 = require("../config/appDataConfig");
|
|
21
22
|
const apiConfig_1 = require("../config/apiConfig");
|
|
23
|
+
const encryption_1 = require("../utils/encryption");
|
|
24
|
+
const encryptionConfig_1 = require("../config/encryptionConfig");
|
|
22
25
|
// -- Hook --
|
|
23
26
|
function usePaymentSSE() {
|
|
24
27
|
// Store the XMLHttpRequest so we can abort it later
|
|
25
28
|
const xhrRef = (0, react_1.useRef)(null);
|
|
29
|
+
const reconnectTimerRef = (0, react_1.useRef)(null);
|
|
30
|
+
const connectWatchdogTimerRef = (0, react_1.useRef)(null);
|
|
31
|
+
const stopRequestedRef = (0, react_1.useRef)(false);
|
|
32
|
+
const connectionIdRef = (0, react_1.useRef)(0);
|
|
26
33
|
// Track how much of responseText we've already parsed
|
|
27
34
|
const lastIndexRef = (0, react_1.useRef)(0);
|
|
28
35
|
// SSE text buffer (persists across onprogress calls)
|
|
29
36
|
const bufferRef = (0, react_1.useRef)({ value: '' });
|
|
30
|
-
const start = (0, react_1.useCallback)((applicationId, callbacks) => {
|
|
31
|
-
var _a;
|
|
37
|
+
const start = (0, react_1.useCallback)((applicationId, callbacks, extraHeaders) => {
|
|
38
|
+
var _a, _b, _c;
|
|
39
|
+
connectionIdRef.current += 1;
|
|
40
|
+
const connectionId = connectionIdRef.current;
|
|
41
|
+
stopRequestedRef.current = false;
|
|
32
42
|
// Clean up any existing connection first
|
|
33
43
|
if (xhrRef.current) {
|
|
34
44
|
xhrRef.current.abort();
|
|
35
45
|
xhrRef.current = null;
|
|
36
46
|
}
|
|
47
|
+
if (reconnectTimerRef.current) {
|
|
48
|
+
clearTimeout(reconnectTimerRef.current);
|
|
49
|
+
reconnectTimerRef.current = null;
|
|
50
|
+
}
|
|
51
|
+
if (connectWatchdogTimerRef.current) {
|
|
52
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
53
|
+
connectWatchdogTimerRef.current = null;
|
|
54
|
+
}
|
|
37
55
|
// Reset parsing state
|
|
38
56
|
lastIndexRef.current = 0;
|
|
39
57
|
bufferRef.current = { value: '' };
|
|
40
58
|
// 1. Build the SSE endpoint URL
|
|
41
59
|
const envData = (0, appDataConfig_1.getEnvironmentData)();
|
|
42
60
|
const apiConfig = (0, apiConfig_1.getApiConfig)();
|
|
43
|
-
const baseUrl = (envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '';
|
|
44
|
-
const url = `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
const baseUrl = ((envData === null || envData === void 0 ? void 0 : envData.apiBaseUrl) || (apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.baseUrl) || '').replace(/\/$/, '');
|
|
62
|
+
const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
|
|
63
|
+
const minimalLogs = (envData === null || envData === void 0 ? void 0 : envData.sseMinimalLogs) === true;
|
|
64
|
+
const verboseSSE = (envData === null || envData === void 0 ? void 0 : envData.enableVerboseSSELogging) !== false;
|
|
65
|
+
const maxReconnectAttempts = Number((_a = envData === null || envData === void 0 ? void 0 : envData.sseReconnectAttempts) !== null && _a !== void 0 ? _a : 4);
|
|
66
|
+
const reconnectDelayMs = Number((_b = envData === null || envData === void 0 ? void 0 : envData.sseReconnectDelayMs) !== null && _b !== void 0 ? _b : 2000);
|
|
67
|
+
const connectWatchdogMs = Number((_c = envData === null || envData === void 0 ? void 0 : envData.sseConnectTimeoutMs) !== null && _c !== void 0 ? _c : 15000);
|
|
68
|
+
const rnVersion = (() => {
|
|
69
|
+
var _a;
|
|
70
|
+
const v = (_a = react_native_1.Platform === null || react_native_1.Platform === void 0 ? void 0 : react_native_1.Platform.constants) === null || _a === void 0 ? void 0 : _a.reactNativeVersion;
|
|
71
|
+
return v ? `${v.major}.${v.minor}.${v.patch}` : 'unknown';
|
|
72
|
+
})();
|
|
73
|
+
const jsEngine = (global === null || global === void 0 ? void 0 : global.HermesInternal) ? 'hermes' : 'jsc/other';
|
|
74
|
+
let reconnectAttempts = 0;
|
|
75
|
+
let connected = false;
|
|
76
|
+
if (!url) {
|
|
77
|
+
if (__DEV__ && verboseSSE)
|
|
78
|
+
console.warn('[usePaymentSSE] No base URL, skipping SSE');
|
|
79
|
+
return;
|
|
53
80
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
81
|
+
const scheduleReconnect = (reason) => {
|
|
82
|
+
var _a;
|
|
83
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
84
|
+
return;
|
|
85
|
+
if (connectWatchdogTimerRef.current) {
|
|
86
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
87
|
+
connectWatchdogTimerRef.current = null;
|
|
88
|
+
}
|
|
89
|
+
if (reconnectAttempts >= maxReconnectAttempts) {
|
|
90
|
+
(_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error(reason));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
reconnectAttempts += 1;
|
|
94
|
+
const delay = reconnectDelayMs * reconnectAttempts;
|
|
95
|
+
if (__DEV__ && !minimalLogs) {
|
|
96
|
+
console.warn(`[usePaymentSSE] Reconnecting (${reconnectAttempts}/${maxReconnectAttempts}) in ${delay}ms`);
|
|
97
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
98
|
+
reason,
|
|
99
|
+
platform: react_native_1.Platform.OS,
|
|
100
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
101
|
+
rnVersion,
|
|
102
|
+
jsEngine,
|
|
103
|
+
applicationId,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (reconnectTimerRef.current) {
|
|
107
|
+
clearTimeout(reconnectTimerRef.current);
|
|
108
|
+
}
|
|
109
|
+
reconnectTimerRef.current = setTimeout(() => {
|
|
110
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
111
|
+
return;
|
|
112
|
+
openConnection();
|
|
113
|
+
}, delay);
|
|
114
|
+
};
|
|
115
|
+
const openConnection = () => {
|
|
58
116
|
var _a;
|
|
59
|
-
|
|
60
|
-
// Only parse the NEW text since last call
|
|
61
|
-
const newText = xhr.responseText.slice(lastIndexRef.current);
|
|
62
|
-
lastIndexRef.current = xhr.responseText.length;
|
|
63
|
-
if (!newText)
|
|
117
|
+
if (stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
64
118
|
return;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
119
|
+
connected = false;
|
|
120
|
+
// 2. Create XMLHttpRequest
|
|
121
|
+
const xhr = new XMLHttpRequest();
|
|
122
|
+
xhrRef.current = xhr;
|
|
123
|
+
xhr.open('GET', url);
|
|
124
|
+
// 3. Set headers (same headers your baseApi interceptor uses)
|
|
125
|
+
const apiKey = (envData === null || envData === void 0 ? void 0 : envData.apiKey) || ((_a = apiConfig === null || apiConfig === void 0 ? void 0 : apiConfig.headers) === null || _a === void 0 ? void 0 : _a['X-API-Key']) || '';
|
|
126
|
+
if (apiKey) {
|
|
127
|
+
xhr.setRequestHeader('x-api-key', apiKey);
|
|
128
|
+
xhr.setRequestHeader('X-API-Key', apiKey);
|
|
129
|
+
}
|
|
130
|
+
// Add secure headers (Content-Type, User-Agent, etc.)
|
|
131
|
+
const secureHeaders = (0, apiConfig_1.getSecureHeaders)();
|
|
132
|
+
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
133
|
+
if (key.toLowerCase() !== 'content-type') {
|
|
134
|
+
xhr.setRequestHeader(key, value);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// SSE-specific headers
|
|
138
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
139
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
140
|
+
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
141
|
+
xhr.setRequestHeader('Expires', '0');
|
|
142
|
+
// Add userreferenceid header (required for authentication) - both cases
|
|
143
|
+
try {
|
|
144
|
+
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
145
|
+
const userRefId = (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id);
|
|
146
|
+
if (userRefId) {
|
|
147
|
+
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
148
|
+
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (_b) {
|
|
152
|
+
if (__DEV__ && verboseSSE)
|
|
153
|
+
console.warn('[usePaymentSSE] Could not get userReferenceId');
|
|
154
|
+
}
|
|
155
|
+
// Add provider header variants
|
|
156
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.providerId) {
|
|
157
|
+
xhr.setRequestHeader('provider', extraHeaders.providerId);
|
|
158
|
+
xhr.setRequestHeader('providerid', extraHeaders.providerId);
|
|
159
|
+
xhr.setRequestHeader('providerId', extraHeaders.providerId);
|
|
160
|
+
}
|
|
161
|
+
// Add onboarding headers - both camelCase and lowercase variants
|
|
162
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.workflowInstanceId) {
|
|
163
|
+
xhr.setRequestHeader('workflowInstanceId', extraHeaders.workflowInstanceId);
|
|
164
|
+
xhr.setRequestHeader('workflowinstanceid', extraHeaders.workflowInstanceId);
|
|
165
|
+
}
|
|
166
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.applicationId) {
|
|
167
|
+
xhr.setRequestHeader('applicationId', extraHeaders.applicationId);
|
|
168
|
+
xhr.setRequestHeader('applicationid', extraHeaders.applicationId);
|
|
169
|
+
}
|
|
170
|
+
if (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.entityid) {
|
|
171
|
+
xhr.setRequestHeader('entityid', extraHeaders.entityid);
|
|
172
|
+
xhr.setRequestHeader('entityId', extraHeaders.entityid);
|
|
173
|
+
}
|
|
174
|
+
const markConnected = (path) => {
|
|
175
|
+
var _a;
|
|
176
|
+
if (connected)
|
|
177
|
+
return;
|
|
178
|
+
connected = true;
|
|
179
|
+
reconnectAttempts = 0;
|
|
180
|
+
if (connectWatchdogTimerRef.current) {
|
|
181
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
182
|
+
connectWatchdogTimerRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
(_a = callbacks.onConnected) === null || _a === void 0 ? void 0 : _a.call(callbacks);
|
|
185
|
+
if (__DEV__ && !minimalLogs) {
|
|
186
|
+
console.log('[usePaymentSSE] Connected to SSE stream');
|
|
187
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
188
|
+
path,
|
|
189
|
+
platform: react_native_1.Platform.OS,
|
|
190
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
191
|
+
rnVersion,
|
|
192
|
+
jsEngine,
|
|
193
|
+
applicationId,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
// 4. Handle incoming data
|
|
198
|
+
xhr.onprogress = () => {
|
|
199
|
+
if (xhr.responseText && xhr.responseText.length > 0) {
|
|
200
|
+
markConnected('progress');
|
|
201
|
+
}
|
|
202
|
+
// responseText contains ALL text received so far
|
|
203
|
+
// Only parse the NEW text since last call
|
|
204
|
+
const newText = xhr.responseText.slice(lastIndexRef.current);
|
|
205
|
+
lastIndexRef.current = xhr.responseText.length;
|
|
206
|
+
if (!newText)
|
|
207
|
+
return;
|
|
208
|
+
// Parse new text into SSE events
|
|
209
|
+
const events = (0, sseParser_1.parseSSEBuffer)(bufferRef.current, newText);
|
|
210
|
+
// Handle each event (support encrypted payload like web)
|
|
211
|
+
const handleEventData = async (rawData) => {
|
|
212
|
+
var _a, _b, _c, _d;
|
|
70
213
|
try {
|
|
71
|
-
const parsed = JSON.parse(
|
|
72
|
-
|
|
73
|
-
|
|
214
|
+
const parsed = JSON.parse(rawData || '{}');
|
|
215
|
+
let payload = parsed;
|
|
216
|
+
if (typeof (parsed === null || parsed === void 0 ? void 0 : parsed.encryptedResponse) === 'string' && parsed.encryptedResponse) {
|
|
217
|
+
try {
|
|
218
|
+
const config = (0, encryptionConfig_1.getEncryptionConfig)();
|
|
219
|
+
const decrypted = await (0, encryption_1.decryptResponse)({ encryptedResponse: parsed.encryptedResponse }, config);
|
|
220
|
+
payload = (decrypted || {});
|
|
221
|
+
}
|
|
222
|
+
catch (_e) {
|
|
223
|
+
if (__DEV__ && verboseSSE)
|
|
224
|
+
console.warn('[usePaymentSSE] Decrypt failed, using raw');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const payloadData = (payload === null || payload === void 0 ? void 0 : payload.data) || {};
|
|
228
|
+
const status = String((_d = (_c = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.paymentStatus) !== null && _a !== void 0 ? _a : payload === null || payload === void 0 ? void 0 : payload.payment_status) !== null && _b !== void 0 ? _b : payloadData === null || payloadData === void 0 ? void 0 : payloadData.paymentStatus) !== null && _c !== void 0 ? _c : payloadData === null || payloadData === void 0 ? void 0 : payloadData.payment_status) !== null && _d !== void 0 ? _d : '').toUpperCase();
|
|
229
|
+
if (status)
|
|
230
|
+
callbacks.onPaymentStatus(status, payload);
|
|
74
231
|
}
|
|
75
232
|
catch (parseError) {
|
|
76
|
-
if (__DEV__)
|
|
233
|
+
if (__DEV__ && verboseSSE)
|
|
77
234
|
console.error('[usePaymentSSE] Failed to parse event data:', parseError);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
for (const { eventType, data } of events) {
|
|
238
|
+
if (!data)
|
|
239
|
+
continue;
|
|
240
|
+
const normalizedEventType = String(eventType || '').trim().toLowerCase();
|
|
241
|
+
if (normalizedEventType === 'fd_payment_status') {
|
|
242
|
+
handleEventData(data);
|
|
243
|
+
}
|
|
244
|
+
else if (normalizedEventType === 'message') {
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(data);
|
|
247
|
+
const embeddedEvent = String((parsed === null || parsed === void 0 ? void 0 : parsed.event) || '').trim().toLowerCase();
|
|
248
|
+
if (embeddedEvent === 'fd_payment_status')
|
|
249
|
+
handleEventData(data);
|
|
250
|
+
}
|
|
251
|
+
catch (_a) {
|
|
252
|
+
// ignore
|
|
78
253
|
}
|
|
79
254
|
}
|
|
80
255
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
256
|
+
};
|
|
257
|
+
// 5. Handle connection status
|
|
258
|
+
xhr.onreadystatechange = () => {
|
|
259
|
+
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED || xhr.readyState === XMLHttpRequest.LOADING) {
|
|
260
|
+
if (xhr.status === 200) {
|
|
261
|
+
markConnected('headers');
|
|
262
|
+
}
|
|
263
|
+
else if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED && xhr.status > 0) {
|
|
264
|
+
if (__DEV__) {
|
|
265
|
+
console.error('[usePaymentSSE] Bad status:', xhr.status);
|
|
266
|
+
}
|
|
267
|
+
scheduleReconnect(`SSE response status: ${xhr.status}`);
|
|
91
268
|
}
|
|
92
269
|
}
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
270
|
+
if (xhr.readyState === XMLHttpRequest.DONE && !stopRequestedRef.current && connectionIdRef.current === connectionId) {
|
|
271
|
+
if (xhr.status !== 200) {
|
|
272
|
+
scheduleReconnect(`SSE closed with status: ${xhr.status}`);
|
|
96
273
|
}
|
|
97
|
-
(_b = callbacks.onError) === null || _b === void 0 ? void 0 : _b.call(callbacks, new Error(`SSE response status: ${xhr.status}`));
|
|
98
274
|
}
|
|
275
|
+
};
|
|
276
|
+
// 6. Handle errors
|
|
277
|
+
xhr.onerror = () => {
|
|
278
|
+
if (__DEV__ && verboseSSE) {
|
|
279
|
+
console.error('[usePaymentSSE] Connection error');
|
|
280
|
+
}
|
|
281
|
+
scheduleReconnect('SSE connection failed');
|
|
282
|
+
};
|
|
283
|
+
// 7. Handle timeout
|
|
284
|
+
xhr.ontimeout = () => {
|
|
285
|
+
if (__DEV__) {
|
|
286
|
+
console.error('[usePaymentSSE] Connection timed out');
|
|
287
|
+
}
|
|
288
|
+
scheduleReconnect('SSE connection timed out');
|
|
289
|
+
};
|
|
290
|
+
// 8. Send the request (connection stays open)
|
|
291
|
+
xhr.send();
|
|
292
|
+
// If we never get connected callback/progress, restart connection.
|
|
293
|
+
if (connectWatchdogTimerRef.current) {
|
|
294
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
99
295
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
var _a;
|
|
296
|
+
connectWatchdogTimerRef.current = setTimeout(() => {
|
|
297
|
+
if (connected || stopRequestedRef.current || connectionIdRef.current !== connectionId)
|
|
298
|
+
return;
|
|
299
|
+
try {
|
|
300
|
+
xhr.abort();
|
|
301
|
+
}
|
|
302
|
+
catch (_a) {
|
|
303
|
+
// ignore
|
|
304
|
+
}
|
|
305
|
+
scheduleReconnect('SSE connect watchdog timeout');
|
|
306
|
+
}, connectWatchdogMs);
|
|
112
307
|
if (__DEV__) {
|
|
113
|
-
console.
|
|
308
|
+
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
309
|
+
console.log('[usePaymentSSE][runtime]', {
|
|
310
|
+
phase: 'start',
|
|
311
|
+
platform: react_native_1.Platform.OS,
|
|
312
|
+
osVersion: String(react_native_1.Platform.Version),
|
|
313
|
+
rnVersion,
|
|
314
|
+
jsEngine,
|
|
315
|
+
applicationId,
|
|
316
|
+
});
|
|
317
|
+
console.log('[usePaymentSSE] Headers:', {
|
|
318
|
+
'x-api-key': apiKey ? '***' : 'missing',
|
|
319
|
+
'userreferenceid': (() => {
|
|
320
|
+
try {
|
|
321
|
+
const userInfo = (0, appDataConfig_1.getUserInfoForAPI)();
|
|
322
|
+
return (userInfo === null || userInfo === void 0 ? void 0 : userInfo.userReferenceId) || (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) || 'missing';
|
|
323
|
+
}
|
|
324
|
+
catch (_a) {
|
|
325
|
+
return 'missing';
|
|
326
|
+
}
|
|
327
|
+
})(),
|
|
328
|
+
'provider': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.providerId) || 'missing',
|
|
329
|
+
'workflowInstanceId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.workflowInstanceId) || 'missing',
|
|
330
|
+
'applicationId': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.applicationId) || 'missing',
|
|
331
|
+
'entityid': (extraHeaders === null || extraHeaders === void 0 ? void 0 : extraHeaders.entityid) || 'missing',
|
|
332
|
+
});
|
|
114
333
|
}
|
|
115
|
-
(_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error('SSE connection timed out'));
|
|
116
334
|
};
|
|
117
|
-
|
|
118
|
-
xhr.send();
|
|
119
|
-
if (__DEV__) {
|
|
120
|
-
console.log('[usePaymentSSE] Starting SSE connection to:', url);
|
|
121
|
-
}
|
|
335
|
+
openConnection();
|
|
122
336
|
}, []);
|
|
123
337
|
const stop = (0, react_1.useCallback)(() => {
|
|
338
|
+
stopRequestedRef.current = true;
|
|
339
|
+
connectionIdRef.current += 1;
|
|
340
|
+
if (reconnectTimerRef.current) {
|
|
341
|
+
clearTimeout(reconnectTimerRef.current);
|
|
342
|
+
reconnectTimerRef.current = null;
|
|
343
|
+
}
|
|
344
|
+
if (connectWatchdogTimerRef.current) {
|
|
345
|
+
clearTimeout(connectWatchdogTimerRef.current);
|
|
346
|
+
connectWatchdogTimerRef.current = null;
|
|
347
|
+
}
|
|
124
348
|
if (xhrRef.current) {
|
|
125
349
|
xhrRef.current.abort();
|
|
126
350
|
xhrRef.current = null;
|
|
@@ -181,14 +181,22 @@ const RootNavigator = ({ config = {}, onExit, onPanRequired, }) => {
|
|
|
181
181
|
}, fdData: (_a = props.route.params) === null || _a === void 0 ? void 0 : _a.fdData }, props)));
|
|
182
182
|
}),
|
|
183
183
|
react_1.default.createElement(Stack.Screen, { name: "Payment", options: { title: 'Payment' } }, (props) => (react_1.default.createElement(Payment_1.default, Object.assign({ onGoBack: () => (0, helpers_2.goBack)(), paymentUrl: ((0, paymentSession_1.getPaymentSession)().paymentUrl) || '', onPaymentSuccess: (data) => {
|
|
184
|
+
var _a, _b;
|
|
185
|
+
const payload = data && typeof data === 'object' ? data : {};
|
|
186
|
+
const transactionId = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.transactionId) !== null && _a !== void 0 ? _a : payload === null || payload === void 0 ? void 0 : payload.transaction_id) !== null && _b !== void 0 ? _b : payload === null || payload === void 0 ? void 0 : payload.TransactionId;
|
|
184
187
|
(0, helpers_2.navigate)('PaymentStatus', {
|
|
185
188
|
status: 'success',
|
|
186
|
-
paymentData: data
|
|
189
|
+
paymentData: data,
|
|
190
|
+
transactionId,
|
|
187
191
|
});
|
|
188
192
|
}, onPaymentFailure: (error) => {
|
|
193
|
+
var _a, _b;
|
|
194
|
+
const payload = error && typeof error === 'object' ? error : {};
|
|
195
|
+
const transactionId = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.transactionId) !== null && _a !== void 0 ? _a : payload === null || payload === void 0 ? void 0 : payload.transaction_id) !== null && _b !== void 0 ? _b : payload === null || payload === void 0 ? void 0 : payload.TransactionId;
|
|
189
196
|
(0, helpers_2.navigate)('PaymentStatus', {
|
|
190
197
|
status: 'failed',
|
|
191
|
-
paymentData: error
|
|
198
|
+
paymentData: error,
|
|
199
|
+
transactionId,
|
|
192
200
|
});
|
|
193
201
|
}, onPaymentPending: (info) => {
|
|
194
202
|
(0, helpers_2.navigate)('PaymentStatus', {
|
|
@@ -297,7 +297,7 @@ const AadhaarVerification = ({ onGoBack, onVerificationComplete, }) => {
|
|
|
297
297
|
applicationid: applicationId,
|
|
298
298
|
entityid: entityId,
|
|
299
299
|
// Request params/body
|
|
300
|
-
|
|
300
|
+
targetTaskCaption: workflowConstants_1.WORKFLOW_TASKS.VALIDATE_OTP,
|
|
301
301
|
}).unwrap();
|
|
302
302
|
setIsValidateOtpTaskCalled(true);
|
|
303
303
|
}
|
|
@@ -355,7 +355,7 @@ const AadhaarVerification = ({ onGoBack, onVerificationComplete, }) => {
|
|
|
355
355
|
applicationid: applicationId,
|
|
356
356
|
entityid: entityId,
|
|
357
357
|
// Request params/body
|
|
358
|
-
|
|
358
|
+
targetTaskCaption: workflowConstants_1.WORKFLOW_TASKS.RESEND_OTP,
|
|
359
359
|
}).unwrap();
|
|
360
360
|
// 2) Then call OTP API with the updateTask response
|
|
361
361
|
const response = await sendOtp({
|