Skip to content

Commit 45c51c5

Browse files
committed
wrap show around native promise to make await-able
fix types
1 parent 221b120 commit 45c51c5

File tree

5 files changed

+106
-60
lines changed

5 files changed

+106
-60
lines changed

Diff for: __sdk__.js

+1
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,6 @@ module.exports = {
9595
},
9696
"three-domain-secure": {
9797
entry: "./src/three-domain-secure/interface",
98+
globals,
9899
},
99100
};

Diff for: src/three-domain-secure/component.jsx

+78-54
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import { ValidationError } from "../lib";
1313
import type {
1414
requestData,
1515
responseBody,
16+
GqlResponse,
1617
MerchantPayloadData,
1718
SdkConfig,
18-
threeDSResponse,
19+
ThreeDSResponse,
1920
TDSProps,
20-
Update3DSTokenResponse,
2121
} from "./types";
2222
import { getFastlaneThreeDS } from "./utils";
2323
import type { GraphQLClient, RestClient } from "./api";
@@ -63,7 +63,7 @@ const parseMerchantPayload = ({
6363

6464
export interface ThreeDomainSecureComponentInterface {
6565
isEligible(payload: MerchantPayloadData): Promise<boolean>;
66-
show(): Promise<threeDSResponse>;
66+
show(): Promise<ThreeDSResponse>;
6767
}
6868

6969
export class ThreeDomainSecureComponent {
@@ -130,64 +130,88 @@ export class ThreeDomainSecureComponent {
130130
throw error;
131131
}
132132
}
133-
134-
async show(): Promise<threeDSResponse> {
133+
// eslint-disable-next-line require-await
134+
async show(): Promise<ThreeDSResponse> {
135135
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+
);
137139
}
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(() => {
144208
instance.close();
145209
});
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-
},
180210
});
181-
182-
return instance
183-
.render("body")
184-
.then(() => promise)
185-
.finally(instance.close);
186211
}
187212

188-
updateNonceWith3dsData(
189-
threeDSRefID: string
190-
): ZalgoPromise<Update3DSTokenResponse> {
213+
updateNonceWith3dsData(threeDSRefID: string): Promise<GqlResponse> {
214+
// $FlowFixMe Zalgopromise not recognized
191215
return this.graphQLClient.request({
192216
headers: {
193217
"Braintree-Version": "2023-09-28",

Diff for: src/three-domain-secure/types.js

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @flow */
22
/* eslint-disable no-restricted-globals, promise/no-native */
3+
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
34
import { type ZoidComponent } from "@krakenjs/zoid/src";
45

56
export type MerchantPayloadData = {|
@@ -70,27 +71,34 @@ export type SdkConfig = {|
7071
clientID: string,
7172
|};
7273

73-
export type threeDSResponse = {|
74+
export type ThreeDSResponse = {|
7475
liabilityShift: string,
75-
authenticationStatus: string,
76+
authenticationState: string,
7677
nonce?: string,
7778
|};
7879

80+
export type HeliosResponse = {|
81+
liability_shift?: string,
82+
reference_id?: string,
83+
success: boolean,
84+
|};
85+
7986
export type TDSResult = {||};
8087

8188
export type TDSProps = {|
8289
xcomponent?: string,
8390
payerActionUrl: string,
84-
onSuccess: (data: threeDSResponse) => void,
91+
onSuccess: (data: HeliosResponse) => Promise<void>,
8592
onError: (mixed) => void,
93+
onCancel: (mixed) => ZalgoPromise<void>,
8694
sdkMeta?: string,
8795
content?: void | {|
8896
windowMessage?: string,
8997
continueMessage?: string,
9098
cancelMessage?: string,
9199
interrogativeMessage?: string,
92100
|},
93-
nonce: string,
101+
nonce?: string,
94102
|};
95103

96104
export type UrlProps = {|
@@ -107,4 +115,16 @@ export type Update3DSTokenResponse = {|
107115
|},
108116
|};
109117

118+
type ErrorLocation = {|
119+
line: number,
120+
column: number,
121+
|};
122+
export type GQLError = {|
123+
message: string,
124+
locations: $ReadOnlyArray<ErrorLocation>,
125+
|};
126+
export type GqlResponse = {|
127+
data?: Update3DSTokenResponse,
128+
errors?: Array<GQLError>,
129+
|};
110130
/* eslint-enable no-restricted-globals, promise/no-native */

Diff for: src/three-domain-secure/utils.jsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ export function getFastlaneThreeDS(): TDSComponent {
4343
return (
4444
<Overlay
4545
context={context}
46-
close={close}
46+
// $FlowFixMe
47+
close={props.onCancel || close}
4748
focus={focus}
4849
event={event}
4950
frame={frame}

Diff for: src/ui/overlay/overlay.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export type OverlayProps = {|
3636
|},
3737
autoResize?: boolean,
3838
hideCloseButton?: boolean,
39-
nonce: string,
39+
nonce?: string,
4040
fullScreen?: boolean,
4141
|};
4242
export function Overlay({

0 commit comments

Comments
 (0)