@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.
@@ -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, _g, _h;
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: ((_b = (_a = result.meta) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.status) || 200,
396
- statusText: ((_d = (_c = result.meta) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.statusText) || 'OK',
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 status = ((_f = (_e = result.meta) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.status) || 200;
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, ((_h = (_g = result.meta) === null || _g === void 0 ? void 0 : _g.response) === null || _h === void 0 ? void 0 : _h.statusText) || 'OK');
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;
@@ -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
- return response;
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
  }),
@@ -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({}, requestBody), { workflowInstanceId: workflowInstanceId }),
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
- // 2. Create XMLHttpRequest
46
- const xhr = new XMLHttpRequest();
47
- xhrRef.current = xhr;
48
- xhr.open('GET', url);
49
- // 3. Set headers (same headers your baseApi interceptor uses)
50
- 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']) || '';
51
- if (apiKey) {
52
- xhr.setRequestHeader('x-api-key', apiKey);
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
- xhr.setRequestHeader('Accept', 'text/event-stream');
55
- xhr.setRequestHeader('Cache-Control', 'no-cache');
56
- // 4. Handle incoming data
57
- xhr.onprogress = () => {
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
- // responseText contains ALL text received so far
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
- // Parse new text into SSE events
66
- const events = (0, sseParser_1.parseSSEBuffer)(bufferRef.current, newText);
67
- // Handle each event
68
- for (const { eventType, data } of events) {
69
- if (eventType === 'fd_payment_status') {
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(data);
72
- const status = ((_a = parsed.paymentStatus) !== null && _a !== void 0 ? _a : '').toUpperCase();
73
- callbacks.onPaymentStatus(status, parsed);
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
- // 5. Handle successful connection
84
- xhr.onreadystatechange = () => {
85
- var _a, _b;
86
- if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
87
- if (xhr.status === 200) {
88
- (_a = callbacks.onConnected) === null || _a === void 0 ? void 0 : _a.call(callbacks);
89
- if (__DEV__) {
90
- console.log('[usePaymentSSE] Connected to SSE stream');
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
- else {
94
- if (__DEV__) {
95
- console.error('[usePaymentSSE] Bad status:', xhr.status);
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
- // 6. Handle errors
102
- xhr.onerror = () => {
103
- var _a;
104
- if (__DEV__) {
105
- console.error('[usePaymentSSE] Connection error');
106
- }
107
- (_a = callbacks.onError) === null || _a === void 0 ? void 0 : _a.call(callbacks, new Error('SSE connection failed'));
108
- };
109
- // 7. Handle timeout
110
- xhr.ontimeout = () => {
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.error('[usePaymentSSE] Connection timed out');
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
- // 8. Send the request (connection stays open)
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
- targetTaskId: workflowConstants_1.WORKFLOW_TASKS.VALIDATE_OTP,
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
- targetTaskId: workflowConstants_1.WORKFLOW_TASKS.RESEND_OTP,
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({