@@ -13,11 +13,11 @@ import { ValidationError } from "../lib";
13
13
import type {
14
14
requestData ,
15
15
responseBody ,
16
+ GqlResponse ,
16
17
MerchantPayloadData ,
17
18
SdkConfig ,
18
- threeDSResponse ,
19
+ ThreeDSResponse ,
19
20
TDSProps ,
20
- Update3DSTokenResponse ,
21
21
} from "./types" ;
22
22
import { getFastlaneThreeDS } from "./utils" ;
23
23
import type { GraphQLClient , RestClient } from "./api" ;
@@ -63,7 +63,7 @@ const parseMerchantPayload = ({
63
63
64
64
export interface ThreeDomainSecureComponentInterface {
65
65
isEligible ( payload : MerchantPayloadData ) : Promise < boolean > ;
66
- show ( ) : Promise < threeDSResponse > ;
66
+ show ( ) : Promise < ThreeDSResponse > ;
67
67
}
68
68
69
69
export class ThreeDomainSecureComponent {
@@ -130,64 +130,88 @@ export class ThreeDomainSecureComponent {
130
130
throw error ;
131
131
}
132
132
}
133
-
134
- async show ( ) : Promise < threeDSResponse > {
133
+ // eslint-disable-next-line require-await
134
+ async show ( ) : Promise < ThreeDSResponse > {
135
135
if ( ! this . threeDSIframe ) {
136
- throw new ValidationError ( `Ineligible for three domain secure` ) ;
136
+ return Promise . reject (
137
+ new ValidationError ( `Ineligible for three domain secure` )
138
+ ) ;
137
139
}
138
- const promise = new ZalgoPromise ( ) ;
139
- const cancelThreeDS = ( ) => {
140
- return ZalgoPromise . try ( ( ) => {
141
- this . logger . warn ( "3DS Cancelled" ) ;
142
- } ) . then ( ( ) => {
143
- // eslint-disable-next-line no-use-before-define
140
+ // eslint-disable-next-line compat/compat
141
+ return new Promise ( ( resolve , reject ) => {
142
+ let authenticationState ,
143
+ liabilityShift = "false" ;
144
+ const cancelThreeDS = ( ) => {
145
+ return ZalgoPromise . try ( ( ) => {
146
+ this . logger . warn ( "3DS Cancelled" ) ;
147
+ } ) . then ( ( ) => {
148
+ resolve ( {
149
+ authenticationState : "cancelled" ,
150
+ liabilityShift : "false" ,
151
+ nonce : this . fastlaneNonce ,
152
+ } ) ;
153
+ // eslint-disable-next-line no-use-before-define
154
+ instance . close ( ) ;
155
+ } ) ;
156
+ } ;
157
+
158
+ const instance = this . threeDSIframe ( {
159
+ payerActionUrl : this . authenticationURL ,
160
+ onSuccess : async ( res ) => {
161
+ const { reference_id, liability_shift, success } = res ;
162
+ let enrichedNonce ;
163
+ // Helios returns a boolen parameter: "success"
164
+ // It will be true for all cases where liability is shifted to merchant
165
+ // and false for downstream failures and errors
166
+ authenticationState = success ? "success" : "errored" ;
167
+ liabilityShift = liability_shift ? liability_shift : "false" ;
168
+
169
+ // call BT mutation to update fastlaneNonce with 3ds data
170
+ // reference_id will be available for all usecases(success/failure)
171
+ if ( reference_id ) {
172
+ const gqlResponse = await this . updateNonceWith3dsData ( reference_id ) ;
173
+ const { data, errors } = gqlResponse ;
174
+ if ( data ) {
175
+ enrichedNonce =
176
+ data . updateTokenizedCreditCardWithExternalThreeDSecure
177
+ . paymentMethod . id ;
178
+ } else if ( errors && errors [ 0 ] ) {
179
+ // $FlowFixMe incompatible type payload
180
+ this . logger . warn (
181
+ "Errors returned when updating nonce" ,
182
+ JSON . stringify ( errors [ 0 ] )
183
+ ) ;
184
+ }
185
+ }
186
+
187
+ // Resolve the parent promise with enriched nonce if available
188
+ // else, return the original nonce that the merchant sent
189
+ resolve ( {
190
+ authenticationState,
191
+ liabilityShift,
192
+ nonce : enrichedNonce || this . fastlaneNonce ,
193
+ } ) ;
194
+ } ,
195
+ onCancel : cancelThreeDS ,
196
+ onError : ( err ) => {
197
+ instance . close ( ) ;
198
+ reject (
199
+ new Error (
200
+ `Error with obtaining 3DS auth response: ${ JSON . stringify ( err ) } `
201
+ )
202
+ ) ;
203
+ } ,
204
+ } ) ;
205
+
206
+ // Render the iframe
207
+ instance . render ( "body" ) . catch ( ( ) => {
144
208
instance . close ( ) ;
145
209
} ) ;
146
- } ;
147
- // $FlowFixMe
148
- const instance = await this . threeDSIframe ( {
149
- payerActionUrl : this . authenticationURL ,
150
- onSuccess : async ( res ) => {
151
- const { reference_id, authentication_status, liability_shift } = res ;
152
- let enrichedNonce , response ;
153
-
154
- if ( reference_id ) {
155
- // $FlowFixMe ZalgoPromise not recognized
156
- response = await this . updateNonceWith3dsData ( reference_id ) ;
157
- }
158
- // $FlowIssue
159
- const { data, errors } = response ;
160
- if ( data ) {
161
- enrichedNonce =
162
- data ?. updateTokenizedCreditCardWithExternalThreeDSecure
163
- . paymentMethod . id ;
164
- } else if ( errors ) {
165
- return promise . resolve ( {
166
- authenticationStatus : authentication_status ,
167
- liabilityShift : liability_shift ,
168
- nonce : enrichedNonce ,
169
- } ) ;
170
- }
171
- } ,
172
- onCancel : cancelThreeDS ,
173
- onError : ( err ) => {
174
- return ZalgoPromise . reject (
175
- new Error (
176
- `Error with obtaining 3DS auth response, ${ JSON . stringify ( err ) } `
177
- )
178
- ) ;
179
- } ,
180
210
} ) ;
181
-
182
- return instance
183
- . render ( "body" )
184
- . then ( ( ) => promise )
185
- . finally ( instance . close ) ;
186
211
}
187
212
188
- updateNonceWith3dsData (
189
- threeDSRefID : string
190
- ) : ZalgoPromise < Update3DSTokenResponse > {
213
+ updateNonceWith3dsData ( threeDSRefID : string ) : Promise < GqlResponse > {
214
+ // $FlowFixMe Zalgopromise not recognized
191
215
return this . graphQLClient . request ( {
192
216
headers : {
193
217
"Braintree-Version" : "2023-09-28" ,
0 commit comments