Skip to content

Commit

Permalink
wrap show around native promise to make await-able
Browse files Browse the repository at this point in the history
fix types

fix types

typecheck
  • Loading branch information
siddy2181 committed Dec 18, 2024
1 parent 221b120 commit 97d1ca7
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 61 deletions.
1 change: 1 addition & 0 deletions __sdk__.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,6 @@ module.exports = {
},
"three-domain-secure": {
entry: "./src/three-domain-secure/interface",
globals,
},
};
125 changes: 71 additions & 54 deletions src/three-domain-secure/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import { ValidationError } from "../lib";
import type {
requestData,
responseBody,
GqlResponse,
MerchantPayloadData,
SdkConfig,
threeDSResponse,
ThreeDSResponse,
TDSProps,
Update3DSTokenResponse,
} from "./types";
import { getFastlaneThreeDS } from "./utils";
import type { GraphQLClient, RestClient } from "./api";
Expand Down Expand Up @@ -63,7 +63,7 @@ const parseMerchantPayload = ({

export interface ThreeDomainSecureComponentInterface {
isEligible(payload: MerchantPayloadData): Promise<boolean>;
show(): Promise<threeDSResponse>;
show(): Promise<ThreeDSResponse>;
}

export class ThreeDomainSecureComponent {
Expand Down Expand Up @@ -130,64 +130,81 @@ export class ThreeDomainSecureComponent {
throw error;
}
}

async show(): Promise<threeDSResponse> {
// eslint-disable-next-line require-await
async show(): Promise<ThreeDSResponse> {
if (!this.threeDSIframe) {
throw new ValidationError(`Ineligible for three domain secure`);
return Promise.reject(
new ValidationError(`Ineligible for three domain secure`)
);
}
const promise = new ZalgoPromise();
const cancelThreeDS = () => {
return ZalgoPromise.try(() => {
this.logger.warn("3DS Cancelled");
}).then(() => {
// eslint-disable-next-line no-use-before-define
// eslint-disable-next-line compat/compat
return new Promise((resolve, reject) => {
let authenticationState,
liabilityShift = "false";
const cancelThreeDS = () => {
return ZalgoPromise.try(() => {
this.logger.warn("3DS Cancelled");
}).then(() => {
resolve({
authenticationState: "cancelled",
liabilityShift: "false",
nonce: this.fastlaneNonce,
});
// eslint-disable-next-line no-use-before-define
instance.close();
});
};

const instance = this.threeDSIframe({
payerActionUrl: this.authenticationURL,
onSuccess: async (res) => {
const { reference_id, liability_shift, success } = res;
let enrichedNonce;
// Helios returns a boolen parameter: "success"
// It will be true for all cases where liability is shifted to merchant
// and false for downstream failures and errors
authenticationState = success ? "success" : "errored";
liabilityShift = liability_shift ? liability_shift : "false";

// call BT mutation to update fastlaneNonce with 3ds data
// reference_id will be available for all usecases(success/failure)
if (reference_id) {
const gqlResponse = await this.updateNonceWith3dsData(reference_id);
const { data, errors } = gqlResponse;
if (data) {
enrichedNonce =
data.updateTokenizedCreditCardWithExternalThreeDSecure
.paymentMethod.id;
} else if (errors && errors[0]) {
// $FlowFixMe incompatible type payload
this.logger.warn(JSON.stringify(errors[0]));
}
}

// Resolve the parent promise with enriched nonce if available
// else, return the original nonce that the merchant sent
resolve({
authenticationState,
liabilityShift,
nonce: enrichedNonce || this.fastlaneNonce,
});
},
onCancel: cancelThreeDS,
onError: (err) => {
instance.close();
reject(new Error(err));
},
});

// Render the iframe
instance.render("body").catch(() => {
instance.close();
});
};
// $FlowFixMe
const instance = await this.threeDSIframe({
payerActionUrl: this.authenticationURL,
onSuccess: async (res) => {
const { reference_id, authentication_status, liability_shift } = res;
let enrichedNonce, response;

if (reference_id) {
// $FlowFixMe ZalgoPromise not recognized
response = await this.updateNonceWith3dsData(reference_id);
}
// $FlowIssue
const { data, errors } = response;
if (data) {
enrichedNonce =
data?.updateTokenizedCreditCardWithExternalThreeDSecure
.paymentMethod.id;
} else if (errors) {
return promise.resolve({
authenticationStatus: authentication_status,
liabilityShift: liability_shift,
nonce: enrichedNonce,
});
}
},
onCancel: cancelThreeDS,
onError: (err) => {
return ZalgoPromise.reject(
new Error(
`Error with obtaining 3DS auth response, ${JSON.stringify(err)}`
)
);
},
});

return instance
.render("body")
.then(() => promise)
.finally(instance.close);
}

updateNonceWith3dsData(
threeDSRefID: string
): ZalgoPromise<Update3DSTokenResponse> {
updateNonceWith3dsData(threeDSRefID: string): Promise<GqlResponse> {
// $FlowFixMe Zalgopromise not recognized
return this.graphQLClient.request({
headers: {
"Braintree-Version": "2023-09-28",
Expand Down
30 changes: 25 additions & 5 deletions src/three-domain-secure/types.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* @flow */
/* eslint-disable no-restricted-globals, promise/no-native */
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
import { type ZoidComponent } from "@krakenjs/zoid/src";

export type MerchantPayloadData = {|
Expand Down Expand Up @@ -70,27 +71,34 @@ export type SdkConfig = {|
clientID: string,
|};

export type threeDSResponse = {|
export type ThreeDSResponse = {|
liabilityShift: string,
authenticationStatus: string,
authenticationState: string,
nonce?: string,
|};

export type HeliosResponse = {|
liability_shift?: string,
reference_id?: string,
success: boolean,
|};

export type TDSResult = {||};

export type TDSProps = {|
xcomponent?: string,
payerActionUrl: string,
onSuccess: (data: threeDSResponse) => void,
onError: (mixed) => void,
onSuccess: (data: HeliosResponse) => Promise<void>,
onError: () => void,
onCancel: (mixed) => ZalgoPromise<void>,
sdkMeta?: string,
content?: void | {|
windowMessage?: string,
continueMessage?: string,
cancelMessage?: string,
interrogativeMessage?: string,
|},
nonce: string,
nonce?: string,
|};

export type UrlProps = {|
Expand All @@ -107,4 +115,16 @@ export type Update3DSTokenResponse = {|
|},
|};

type ErrorLocation = {|
line: number,
column: number,
|};
export type GQLError = {|
message: string,
locations: $ReadOnlyArray<ErrorLocation>,
|};
export type GqlResponse = {|
data?: Update3DSTokenResponse,
errors?: $ReadOnlyArray<GQLError>,
|};
/* eslint-enable no-restricted-globals, promise/no-native */
3 changes: 2 additions & 1 deletion src/three-domain-secure/utils.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export function getFastlaneThreeDS(): TDSComponent {
return (
<Overlay
context={context}
close={close}
// $FlowFixMe
close={props.onCancel || close}
focus={focus}
event={event}
frame={frame}
Expand Down
2 changes: 1 addition & 1 deletion src/ui/overlay/overlay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type OverlayProps = {|
|},
autoResize?: boolean,
hideCloseButton?: boolean,
nonce: string,
nonce?: string,
fullScreen?: boolean,
|};
export function Overlay({
Expand Down

0 comments on commit 97d1ca7

Please sign in to comment.