@finspringinnovations/fdsdk 0.0.5 → 0.0.7
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/components/InterestRateCard.d.ts +4 -0
- package/lib/components/InterestRateCard.js +13 -3
- package/lib/config/appDataConfig.d.ts +5 -0
- package/lib/hooks/usePaymentSSE.js +277 -142
- package/lib/screens/FDCalculator.js +25 -1
- package/lib/screens/Payment.js +138 -20
- package/lib/screens/PaymentStatus.js +129 -13
- package/lib/utils/sseParser.js +19 -3
- package/package.json +1 -1
- package/src/components/InterestRateCard.tsx +33 -5
- package/src/config/appDataConfig.ts +5 -0
- package/src/hooks/usePaymentSSE.ts +283 -136
- package/src/screens/FDCalculator.tsx +23 -1
- package/src/screens/Payment.tsx +163 -30
- package/src/screens/PaymentStatus.tsx +146 -16
- package/src/utils/sseParser.ts +20 -4
package/src/screens/Payment.tsx
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import React, { useRef, useState, useEffect } from 'react';
|
|
1
|
+
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { View, StyleSheet, ActivityIndicator, BackHandler, Platform, StatusBar } from 'react-native';
|
|
3
3
|
import { WebView } from 'react-native-webview';
|
|
4
4
|
import SafeAreaWrapper from '../components/SafeAreaWrapper';
|
|
5
5
|
import { useColors } from '../theme/ThemeContext';
|
|
6
6
|
import { decryptResponse } from '../utils/encryption';
|
|
7
|
+
import { parseSSEBuffer } from '../utils/sseParser';
|
|
7
8
|
import { getEncryptionConfig } from '../config/encryptionConfig';
|
|
9
|
+
import { getEnvironmentData, getUserInfoForAPI } from '../config/appDataConfig';
|
|
10
|
+
import { getApiConfig, getSecureHeaders } from '../config/apiConfig';
|
|
8
11
|
import { useAppSelector } from '../store';
|
|
9
|
-
import { usePaymentSSE } from '../hooks/usePaymentSSE';
|
|
10
12
|
|
|
11
13
|
export interface PaymentProps {
|
|
12
14
|
onGoBack?: () => void;
|
|
@@ -36,14 +38,22 @@ const Payment: React.FC<PaymentProps> = ({
|
|
|
36
38
|
const workflowInstanceId = useAppSelector((state: any) => state?.onboarding?.workflowInstanceId);
|
|
37
39
|
const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
|
|
38
40
|
const providerId = useAppSelector((state: any) => state?.onboarding?.providerId);
|
|
39
|
-
const
|
|
41
|
+
const sseXhrRef = useRef<XMLHttpRequest | null>(null);
|
|
42
|
+
const sseLastIndexRef = useRef<number>(0);
|
|
43
|
+
const sseBufferRef = useRef<{ value: string }>({ value: '' });
|
|
40
44
|
const onSuccessRef = useRef(onPaymentSuccess);
|
|
41
45
|
const onFailureRef = useRef(onPaymentFailure);
|
|
42
46
|
onSuccessRef.current = onPaymentSuccess;
|
|
43
47
|
onFailureRef.current = onPaymentFailure;
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
const stopPaymentSSE = useCallback(() => {
|
|
50
|
+
if (sseXhrRef.current) {
|
|
51
|
+
sseXhrRef.current.abort();
|
|
52
|
+
sseXhrRef.current = null;
|
|
53
|
+
}
|
|
54
|
+
sseLastIndexRef.current = 0;
|
|
55
|
+
sseBufferRef.current = { value: '' };
|
|
56
|
+
}, []);
|
|
47
57
|
|
|
48
58
|
const handleNavigationStateChange = async (navState: any) => {
|
|
49
59
|
const { url } = navState;
|
|
@@ -73,37 +83,160 @@ const Payment: React.FC<PaymentProps> = ({
|
|
|
73
83
|
|
|
74
84
|
// SSE: listen for payment status while user is on Payment WebView (same as web integration)
|
|
75
85
|
useEffect(() => {
|
|
76
|
-
if (!applicationId || !paymentUrl?.trim())
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
if (!applicationId || !paymentUrl?.trim()) {
|
|
87
|
+
stopPaymentSSE();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const envData = getEnvironmentData();
|
|
92
|
+
const apiConfig = getApiConfig();
|
|
93
|
+
const baseUrl = (envData?.apiBaseUrl || apiConfig?.baseUrl || '').replace(/\/$/, '');
|
|
94
|
+
const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
|
|
95
|
+
|
|
96
|
+
if (!url) return;
|
|
97
|
+
|
|
98
|
+
stopPaymentSSE();
|
|
99
|
+
|
|
100
|
+
const xhr = new XMLHttpRequest();
|
|
101
|
+
sseXhrRef.current = xhr;
|
|
102
|
+
xhr.open('GET', url);
|
|
103
|
+
|
|
104
|
+
const apiKey = envData?.apiKey || apiConfig?.headers?.['X-API-Key'] || '';
|
|
105
|
+
if (apiKey) {
|
|
106
|
+
xhr.setRequestHeader('x-api-key', apiKey);
|
|
107
|
+
xhr.setRequestHeader('X-API-Key', apiKey);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const secureHeaders = getSecureHeaders();
|
|
111
|
+
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
112
|
+
if (key.toLowerCase() !== 'content-type') {
|
|
113
|
+
xhr.setRequestHeader(key, value);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
118
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
119
|
+
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
120
|
+
xhr.setRequestHeader('Expires', '0');
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const userInfo = getUserInfoForAPI();
|
|
124
|
+
const userRefId = userInfo?.userReferenceId || userInfo?.id;
|
|
125
|
+
if (userRefId) {
|
|
126
|
+
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
127
|
+
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
// ignore
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (providerId) {
|
|
134
|
+
xhr.setRequestHeader('provider', providerId);
|
|
135
|
+
xhr.setRequestHeader('providerid', providerId);
|
|
136
|
+
xhr.setRequestHeader('providerId', providerId);
|
|
137
|
+
}
|
|
138
|
+
if (workflowInstanceId) {
|
|
139
|
+
xhr.setRequestHeader('workflowInstanceId', workflowInstanceId);
|
|
140
|
+
xhr.setRequestHeader('workflowinstanceid', workflowInstanceId);
|
|
141
|
+
}
|
|
142
|
+
if (applicationId) {
|
|
143
|
+
xhr.setRequestHeader('applicationId', applicationId);
|
|
144
|
+
xhr.setRequestHeader('applicationid', applicationId);
|
|
145
|
+
}
|
|
146
|
+
if (entityId) {
|
|
147
|
+
xhr.setRequestHeader('entityid', entityId);
|
|
148
|
+
xhr.setRequestHeader('entityId', entityId);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const handleEventData = async (rawData: string) => {
|
|
152
|
+
try {
|
|
153
|
+
const parsed = JSON.parse(rawData || '{}') as Record<string, unknown>;
|
|
154
|
+
let payload = parsed;
|
|
155
|
+
if (typeof parsed?.encryptedResponse === 'string' && parsed.encryptedResponse) {
|
|
156
|
+
try {
|
|
157
|
+
const config = getEncryptionConfig();
|
|
158
|
+
const decrypted = await decryptResponse(
|
|
159
|
+
{ encryptedResponse: parsed.encryptedResponse },
|
|
160
|
+
config
|
|
161
|
+
);
|
|
162
|
+
payload = (decrypted || {}) as Record<string, unknown>;
|
|
163
|
+
} catch {
|
|
164
|
+
// ignore and use raw payload
|
|
87
165
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const payloadData = (payload?.data as Record<string, unknown> | undefined) || {};
|
|
169
|
+
const status = String(
|
|
170
|
+
payload?.paymentStatus ??
|
|
171
|
+
payload?.payment_status ??
|
|
172
|
+
payloadData?.paymentStatus ??
|
|
173
|
+
payloadData?.payment_status ??
|
|
174
|
+
''
|
|
175
|
+
).toUpperCase();
|
|
176
|
+
|
|
177
|
+
if (status === 'SUCCESS') {
|
|
178
|
+
stopPaymentSSE();
|
|
179
|
+
onSuccessRef.current?.(payload);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (status === 'FAILED') {
|
|
184
|
+
stopPaymentSSE();
|
|
185
|
+
onFailureRef.current?.(payload);
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
// ignore parse errors
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
xhr.onprogress = () => {
|
|
193
|
+
setLoading(false);
|
|
194
|
+
|
|
195
|
+
const newText = xhr.responseText.slice(sseLastIndexRef.current);
|
|
196
|
+
sseLastIndexRef.current = xhr.responseText.length;
|
|
197
|
+
if (!newText) return;
|
|
198
|
+
|
|
199
|
+
const events = parseSSEBuffer(sseBufferRef.current, newText);
|
|
200
|
+
for (const { eventType, data } of events) {
|
|
201
|
+
if (!data) continue;
|
|
202
|
+
const normalizedEventType = String(eventType || '').trim().toLowerCase();
|
|
203
|
+
if (normalizedEventType === 'fd_payment_status') {
|
|
204
|
+
handleEventData(data);
|
|
205
|
+
} else if (normalizedEventType === 'message') {
|
|
206
|
+
try {
|
|
207
|
+
const parsed = JSON.parse(data) as { event?: string; [k: string]: unknown };
|
|
208
|
+
const embeddedEvent = String(parsed?.event || '').trim().toLowerCase();
|
|
209
|
+
if (embeddedEvent === 'fd_payment_status') {
|
|
210
|
+
handleEventData(data);
|
|
211
|
+
}
|
|
212
|
+
} catch {
|
|
213
|
+
// ignore
|
|
91
214
|
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
xhr.onreadystatechange = () => {
|
|
220
|
+
if (
|
|
221
|
+
(xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED ||
|
|
222
|
+
xhr.readyState === XMLHttpRequest.LOADING) &&
|
|
223
|
+
xhr.status === 200
|
|
224
|
+
) {
|
|
225
|
+
setLoading(false);
|
|
226
|
+
if (__DEV__) console.log('[Payment] SSE connected for payment status');
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
xhr.onerror = () => {
|
|
231
|
+
if (__DEV__) console.warn('[Payment] SSE connection error');
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
xhr.send();
|
|
102
235
|
|
|
103
236
|
return () => {
|
|
104
237
|
stopPaymentSSE();
|
|
105
238
|
};
|
|
106
|
-
}, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId,
|
|
239
|
+
}, [applicationId, paymentUrl, workflowInstanceId, entityId, providerId, stopPaymentSSE]);
|
|
107
240
|
|
|
108
241
|
const handleMessage = async (event: any) => {
|
|
109
242
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
2
|
import { View, Text, StyleSheet, ScrollView, Alert, Image, BackHandler, Platform, StatusBar } from 'react-native';
|
|
3
3
|
import Icon from 'react-native-vector-icons/Ionicons';
|
|
4
4
|
import { base64Images } from '../constants/strings/base64Images';
|
|
@@ -9,13 +9,16 @@ import { useColors, useTypography, useTheme } from '../theme/ThemeContext';
|
|
|
9
9
|
import { usePaymentRetryMutation } from '../api/fdApi';
|
|
10
10
|
import { useGetCustomerApplicationsMutation } from '../api/customerApi';
|
|
11
11
|
import { useAppSelector } from '../store';
|
|
12
|
-
import { getUserInfoForAPI } from '../config/appDataConfig';
|
|
12
|
+
import { getEnvironmentData, getUserInfoForAPI } from '../config/appDataConfig';
|
|
13
|
+
import { getApiConfig, getSecureHeaders } from '../config/apiConfig';
|
|
13
14
|
import { navigate } from '../navigation/helpers';
|
|
14
15
|
import { setPaymentSession, getPaymentSession } from '../state/paymentSession';
|
|
15
16
|
import { useRoute } from '@react-navigation/native';
|
|
16
17
|
import { BANK_STRINGS } from '../constants/strings/bank';
|
|
17
18
|
import { COMMON_STRINGS } from '../constants/strings/common';
|
|
18
|
-
import {
|
|
19
|
+
import { parseSSEBuffer } from '../utils/sseParser';
|
|
20
|
+
import { decryptResponse } from '../utils/encryption';
|
|
21
|
+
import { getEncryptionConfig } from '../config/encryptionConfig';
|
|
19
22
|
|
|
20
23
|
export interface PaymentStatusProps {
|
|
21
24
|
onRetry?: () => void;
|
|
@@ -62,8 +65,9 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
|
|
|
62
65
|
const applicationId = useAppSelector((state: any) => state?.onboarding?.applicationId);
|
|
63
66
|
const entityId = useAppSelector((state: any) => state?.onboarding?.entityid);
|
|
64
67
|
const providerId = useAppSelector((state: any) => state?.onboarding?.providerId);
|
|
65
|
-
|
|
66
|
-
const
|
|
68
|
+
const sseXhrRef = useRef<XMLHttpRequest | null>(null);
|
|
69
|
+
const sseLastIndexRef = useRef<number>(0);
|
|
70
|
+
const sseBufferRef = useRef<{ value: string }>({ value: '' });
|
|
67
71
|
|
|
68
72
|
// Payment Retry API
|
|
69
73
|
const [paymentRetry, {
|
|
@@ -100,34 +104,160 @@ const PaymentStatus: React.FC<PaymentStatusProps> = ({
|
|
|
100
104
|
return amount.toLocaleString('en-IN');
|
|
101
105
|
};
|
|
102
106
|
|
|
107
|
+
const stopPaymentSSE = useCallback(() => {
|
|
108
|
+
if (sseXhrRef.current) {
|
|
109
|
+
sseXhrRef.current.abort();
|
|
110
|
+
sseXhrRef.current = null;
|
|
111
|
+
}
|
|
112
|
+
sseLastIndexRef.current = 0;
|
|
113
|
+
sseBufferRef.current = { value: '' };
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
103
116
|
useEffect(() => {
|
|
104
117
|
if (currentStatus !== 'pending' || !applicationId) {
|
|
105
118
|
stopPaymentSSE();
|
|
106
119
|
return;
|
|
107
120
|
}
|
|
108
121
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
122
|
+
const envData = getEnvironmentData();
|
|
123
|
+
const apiConfig = getApiConfig();
|
|
124
|
+
const baseUrl = (envData?.apiBaseUrl || apiConfig?.baseUrl || '').replace(/\/$/, '');
|
|
125
|
+
const url = baseUrl ? `${baseUrl}/events?applicationId=${encodeURIComponent(applicationId)}` : '';
|
|
126
|
+
|
|
127
|
+
if (!url) return;
|
|
128
|
+
|
|
129
|
+
stopPaymentSSE();
|
|
130
|
+
|
|
131
|
+
const xhr = new XMLHttpRequest();
|
|
132
|
+
sseXhrRef.current = xhr;
|
|
133
|
+
xhr.open('GET', url);
|
|
134
|
+
|
|
135
|
+
const apiKey = envData?.apiKey || apiConfig?.headers?.['X-API-Key'] || '';
|
|
136
|
+
if (apiKey) {
|
|
137
|
+
xhr.setRequestHeader('x-api-key', apiKey);
|
|
138
|
+
xhr.setRequestHeader('X-API-Key', apiKey);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const secureHeaders = getSecureHeaders();
|
|
142
|
+
Object.entries(secureHeaders).forEach(([key, value]) => {
|
|
143
|
+
if (key.toLowerCase() !== 'content-type') {
|
|
144
|
+
xhr.setRequestHeader(key, value);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
149
|
+
xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
150
|
+
xhr.setRequestHeader('Pragma', 'no-cache');
|
|
151
|
+
xhr.setRequestHeader('Expires', '0');
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const userInfo = getUserInfoForAPI();
|
|
155
|
+
const userRefId = userInfo?.userReferenceId || userInfo?.id;
|
|
156
|
+
if (userRefId) {
|
|
157
|
+
xhr.setRequestHeader('userreferenceid', userRefId);
|
|
158
|
+
xhr.setRequestHeader('userReferenceId', userRefId);
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
// ignore
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (providerId) {
|
|
165
|
+
xhr.setRequestHeader('provider', providerId);
|
|
166
|
+
xhr.setRequestHeader('providerid', providerId);
|
|
167
|
+
xhr.setRequestHeader('providerId', providerId);
|
|
168
|
+
}
|
|
169
|
+
if (workflowInstanceId) {
|
|
170
|
+
xhr.setRequestHeader('workflowInstanceId', workflowInstanceId);
|
|
171
|
+
xhr.setRequestHeader('workflowinstanceid', workflowInstanceId);
|
|
172
|
+
}
|
|
173
|
+
if (applicationId) {
|
|
174
|
+
xhr.setRequestHeader('applicationId', applicationId);
|
|
175
|
+
xhr.setRequestHeader('applicationid', applicationId);
|
|
176
|
+
}
|
|
177
|
+
if (entityId) {
|
|
178
|
+
xhr.setRequestHeader('entityid', entityId);
|
|
179
|
+
xhr.setRequestHeader('entityId', entityId);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const handleEventData = async (rawData: string) => {
|
|
183
|
+
try {
|
|
184
|
+
const parsed = JSON.parse(rawData || '{}') as Record<string, unknown>;
|
|
185
|
+
let payload = parsed;
|
|
186
|
+
if (typeof parsed?.encryptedResponse === 'string' && parsed.encryptedResponse) {
|
|
187
|
+
try {
|
|
188
|
+
const config = getEncryptionConfig();
|
|
189
|
+
const decrypted = await decryptResponse(
|
|
190
|
+
{ encryptedResponse: parsed.encryptedResponse },
|
|
191
|
+
config
|
|
192
|
+
);
|
|
193
|
+
payload = (decrypted || {}) as Record<string, unknown>;
|
|
194
|
+
} catch {
|
|
195
|
+
// ignore and use raw payload
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const payloadData = (payload?.data as Record<string, unknown> | undefined) || {};
|
|
200
|
+
const status = String(
|
|
201
|
+
payload?.paymentStatus ??
|
|
202
|
+
payload?.payment_status ??
|
|
203
|
+
payloadData?.paymentStatus ??
|
|
204
|
+
payloadData?.payment_status ??
|
|
205
|
+
''
|
|
206
|
+
).toUpperCase();
|
|
207
|
+
|
|
208
|
+
if (status === 'SUCCESS') {
|
|
113
209
|
setCurrentStatus('success');
|
|
114
210
|
stopPaymentSSE();
|
|
115
211
|
return;
|
|
116
212
|
}
|
|
117
|
-
|
|
213
|
+
|
|
214
|
+
if (status === 'FAILED') {
|
|
118
215
|
setCurrentStatus('failed');
|
|
119
216
|
stopPaymentSSE();
|
|
120
217
|
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
218
|
+
} catch {
|
|
219
|
+
// ignore parse errors
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
xhr.onprogress = () => {
|
|
224
|
+
const newText = xhr.responseText.slice(sseLastIndexRef.current);
|
|
225
|
+
sseLastIndexRef.current = xhr.responseText.length;
|
|
226
|
+
if (!newText) return;
|
|
227
|
+
|
|
228
|
+
const events = parseSSEBuffer(sseBufferRef.current, newText);
|
|
229
|
+
for (const { eventType, data } of events) {
|
|
230
|
+
if (!data) continue;
|
|
231
|
+
const normalizedEventType = String(eventType || '').trim().toLowerCase();
|
|
232
|
+
if (normalizedEventType === 'fd_payment_status') {
|
|
233
|
+
handleEventData(data);
|
|
234
|
+
} else if (normalizedEventType === 'message') {
|
|
235
|
+
try {
|
|
236
|
+
const parsed = JSON.parse(data) as { event?: string; [k: string]: unknown };
|
|
237
|
+
const embeddedEvent = String(parsed?.event || '').trim().toLowerCase();
|
|
238
|
+
if (embeddedEvent === 'fd_payment_status') {
|
|
239
|
+
handleEventData(data);
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
// ignore
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
xhr.send();
|
|
126
249
|
|
|
127
250
|
return () => {
|
|
128
251
|
stopPaymentSSE();
|
|
129
252
|
};
|
|
130
|
-
}, [
|
|
253
|
+
}, [
|
|
254
|
+
applicationId,
|
|
255
|
+
currentStatus,
|
|
256
|
+
entityId,
|
|
257
|
+
providerId,
|
|
258
|
+
stopPaymentSSE,
|
|
259
|
+
workflowInstanceId
|
|
260
|
+
]);
|
|
131
261
|
|
|
132
262
|
// Handle payment retry when status is failed
|
|
133
263
|
const handlePaymentRetry = async () => {
|
package/src/utils/sseParser.ts
CHANGED
|
@@ -11,13 +11,29 @@ export function parseSSEBuffer(
|
|
|
11
11
|
|
|
12
12
|
buffer.value += chunk;
|
|
13
13
|
|
|
14
|
-
let idx
|
|
14
|
+
let idx = -1;
|
|
15
|
+
let delimiterLength = 0;
|
|
16
|
+
const findDelimiter = () => {
|
|
17
|
+
const unixIdx = buffer.value.indexOf('\n\n');
|
|
18
|
+
const windowsIdx = buffer.value.indexOf('\r\n\r\n');
|
|
19
|
+
if (windowsIdx >= 0 && (unixIdx < 0 || windowsIdx < unixIdx)) {
|
|
20
|
+
idx = windowsIdx;
|
|
21
|
+
delimiterLength = 4;
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (unixIdx >= 0) {
|
|
25
|
+
idx = unixIdx;
|
|
26
|
+
delimiterLength = 2;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
15
31
|
|
|
16
|
-
while ((
|
|
32
|
+
while (findDelimiter()) {
|
|
17
33
|
|
|
18
34
|
const block = buffer.value.slice(0, idx);
|
|
19
35
|
|
|
20
|
-
buffer.value = buffer.value.slice(idx +
|
|
36
|
+
buffer.value = buffer.value.slice(idx + delimiterLength);
|
|
21
37
|
|
|
22
38
|
let eventType = 'message';
|
|
23
39
|
|
|
@@ -37,4 +53,4 @@ export function parseSSEBuffer(
|
|
|
37
53
|
}
|
|
38
54
|
}
|
|
39
55
|
return results;
|
|
40
|
-
}
|
|
56
|
+
}
|