Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@paypal/checkout-components

Package Overview
Dependencies
Maintainers
0
Versions
513
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@paypal/checkout-components - npm Package Compare versions

Comparing version 5.0.347-alpha-0f42cd5.0 to 5.0.347-alpha-1d87dc3.0

src/lib/appSwitchResume.js

1

__sdk__.js

@@ -98,4 +98,3 @@ /* @flow */

entry: "./src/three-domain-secure/interface",
globals,
},
};

@@ -26,2 +26,3 @@ /* eslint import/no-commonjs: off, flowtype/require-valid-file-annotation: off, flowtype/require-return-type: off */

__BUTTONS__: "/smart/buttons",
__PIXEL__: "/smart/pixel",
__MENU__: "/smart/menu",

@@ -28,0 +29,0 @@ __QRCODE__: "/smart/qrcode",

{
"name": "@paypal/checkout-components",
"version": "5.0.347-alpha-0f42cd5.0",
"version": "5.0.347-alpha-1d87dc3.0",
"description": "PayPal Checkout components, for integrating checkout products.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -20,1 +20,7 @@ /* @flow */

export const DEFAULT = ("default": "default");
export const APP_SWITCH_RETURN_HASH = {
ONAPPROVE: ("onApprove": "onApprove"),
ONCANCEL: ("onCancel": "onCancel"),
ONERROR: ("onError": "onError"),
};

@@ -11,2 +11,3 @@ /* @flow */

__BUTTONS__: string,
__PIXEL__: string,
__CHECKOUT__: string,

@@ -13,0 +14,0 @@ __CARD_FIELDS__: string,

@@ -36,2 +36,3 @@ /* @flow */

} from "../zoid/modal/component";
import { getPixelComponent, type PixelComponent } from "../zoid/pixel";

@@ -42,2 +43,6 @@ export const Buttons: LazyExport<ButtonsComponent> = {

export const ResumePixel: LazyExport<PixelComponent> = {
__get__: () => getPixelComponent(),
};
export const Checkout: LazyProtectedExport<CheckoutComponent> = {

@@ -98,2 +103,3 @@ __get__: () => protectedExport(getCheckoutComponent()),

getCheckoutComponent();
getPixelComponent();
}

@@ -100,0 +106,0 @@

@@ -8,2 +8,3 @@ /* @flow */

export * from "./session";
export * from "./appSwitchResume";
export * from "./perceived-latency-instrumentation";

@@ -42,4 +42,1 @@ /* @flow */

};
// TODO: Remove after testing
// $FlowIssue
export const payPayDomainRegEx = /\.paypal\.(com|cn)(:\d+)?$/; // eslint-disable-line security/detect-unsafe-regex

@@ -5,19 +5,74 @@ /* @flow */

import { type LoggerType } from "@krakenjs/beaver-logger/src";
import { type ZoidComponent } from "@krakenjs/zoid/src";
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
import { create, type ZoidComponent } from "@krakenjs/zoid/src";
import { FPTI_KEY } from "@paypal/sdk-constants/src";
import { ValidationError } from "../lib";
import { PAYMENT_3DS_VERIFICATION } from "../constants/api";
import type {
requestData,
responseBody,
MerchantPayloadData,
SdkConfig,
threeDSResponse,
TDSProps,
} from "./types";
import { getFastlaneThreeDS } from "./utils";
import type { GraphQLClient, RestClient } from "./api";
type MerchantPayloadData = {|
amount: string,
currency: string,
nonce: string,
threeDSRequested?: boolean,
transactionContext?: Object,
|};
// eslint-disable-next-line no-undef
type Request = <TRequestData, TResponse>({|
method?: string,
url: string,
// eslint-disable-next-line no-undef
data: TRequestData,
accessToken: ?string,
// eslint-disable-next-line no-undef
|}) => Promise<TResponse>;
type requestData = {|
intent: "THREE_DS_VERIFICATION",
payment_source: {|
card: {|
single_use_token: string,
verification_method: string,
|},
|},
amount: {|
currency_code: string,
value: string,
|},
transaction_context?: {|
soft_descriptor?: string,
|},
|};
type responseBody = {|
payment_id: string,
status: string,
intent: string,
payment_source: {|
card: {|
last_digits: string,
type: string,
name: string,
expiry: string,
|},
|},
amount: {|
currency_code: string,
value: string,
|},
transaction_context: {|
soft_descriptor: string,
|},
links: $ReadOnlyArray<{|
href: string,
rel: string,
method: string,
|}>,
|};
type SdkConfig = {|
authenticationToken: ?string,
paypalApiDomain: string,
|};
const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => {

@@ -44,2 +99,3 @@ if (!sdkConfig.authenticationToken) {

merchantPayload;
return {

@@ -64,65 +120,38 @@ intent: "THREE_DS_VERIFICATION",

export interface ThreeDomainSecureComponentInterface {
isEligible(payload: MerchantPayloadData): Promise<boolean>;
show(): ZalgoPromise<threeDSResponse>;
isEligible(): Promise<boolean>;
show(): ZoidComponent<void>;
}
type Update3DSTokenResponse = {|
updateTokenizedCreditCardWithExternalThreeDSecure: {|
paymentMethod: {|
id: string,
|},
|},
|};
export class ThreeDomainSecureComponent {
fastlaneNonce: string;
logger: LoggerType;
restClient: RestClient;
graphQLClient: GraphQLClient;
request: Request;
sdkConfig: SdkConfig;
authenticationURL: string;
threeDSIframe: ZoidComponent<TDSProps>;
constructor({
logger,
restClient,
graphQLClient,
request,
sdkConfig,
}: {|
logger: LoggerType,
restClient: RestClient,
graphQLClient: GraphQLClient,
request: Request,
sdkConfig: SdkConfig,
|}) {
this.logger = logger;
this.restClient = restClient;
this.graphQLClient = graphQLClient;
this.request = request;
this.sdkConfig = parseSdkConfig({ sdkConfig, logger });
if (this.sdkConfig.authenticationToken) {
this.restClient.setAccessToken(this.sdkConfig.authenticationToken);
}
}
async isEligible(merchantPayload: MerchantPayloadData): Promise<boolean> {
// eslint-disable-next-line no-console
console.log("Entered IsEligible");
const data = parseMerchantPayload({ merchantPayload });
const idToken = merchantPayload.idToken;
this.fastlaneNonce = merchantPayload.nonce;
try {
// $FlowFixMe
const { status, links } = await this.restClient.request<
requestData,
responseBody
>({
const { status, links } = await this.request<requestData, responseBody>({
method: "POST",
baseURL: `${this.sdkConfig.paypalApiDomain}/v2/payments/payment`,
url: `${this.sdkConfig.paypalApiDomain}/${PAYMENT_3DS_VERIFICATION}`,
data,
accessToken: idToken, // this.sdkConfig.authenticationToken,
accessToken: this.sdkConfig.authenticationToken,
});
let responseStatus = false;
if (status === "PAYER_ACTION_REQUIRED") {

@@ -133,3 +162,2 @@ this.authenticationURL = links.find(

responseStatus = true;
this.threeDSIframe = getFastlaneThreeDS(this.authenticationURL);
}

@@ -143,80 +171,5 @@ return responseStatus;

show(): ZalgoPromise<threeDSResponse> {
if (!this.threeDSIframe) {
return ZalgoPromise.reject(
new ValidationError(`Ineligible for three domain secure`)
);
}
const promise = new ZalgoPromise();
const cancelThreeDS = () => {
return ZalgoPromise.try(() => {
// eslint-disable-next-line no-console
console.log("cancelled");
}).then(() => {
// eslint-disable-next-line no-use-before-define
instance.close();
});
};
// $FlowFixMe
const instance = this.threeDSIframe({
onSuccess: async (data) => {
// const { threeDSRefID, authentication_status, liability_shift } = data;
const { threeDSRefID } = data;
// eslint-disable-next-line no-console
console.log("threeDSRefID", threeDSRefID);
let enrichedNonce;
if (threeDSRefID) {
enrichedNonce = await this.updateNonceWith3dsData(threeDSRefID);
}
// eslint-disable-next-line no-console
console.log("Received enriched nonce", enrichedNonce);
return promise.resolve({ ...data, nonce: enrichedNonce });
},
onClose: cancelThreeDS,
onError: (err) => {
return ZalgoPromise.reject(
new Error(
`Error with obtaining 3DS contingency, ${JSON.stringify(err)}`
)
);
},
});
// const TARGET_ELEMENT = {
// BODY: "body",
// };
return instance
.render("body")
.then(() => promise)
.finally(instance.close);
show() {
create({ tag: "", url: "" });
}
updateNonceWith3dsData(
threeDSRefID: string
): ZalgoPromise<Update3DSTokenResponse> {
return this.graphQLClient.request({
headers: {
"Braintree-Version": "2023-09-28",
},
data: {
query: `
mutation Update3DSToken($input: UpdateTokenizedCreditCardWithExternalThreeDSecureInput!) {
updateTokenizedCreditCardWithExternalThreeDSecure(input: $input) {
paymentMethod {
id
}
}
}
`,
variables: {
input: {
paymentMethodId: this.fastlaneNonce,
externalThreeDSecureMetadata: {
externalAuthenticationId: threeDSRefID,
},
},
},
},
});
}
}

@@ -11,8 +11,3 @@ /* @flow */

};
vi.mock("./utils", async () => {
return {
...(await vi.importActual("./utils")),
getThreeDomainSecureComponent: vi.fn(),
};
});
const defaultEligibilityResponse = {

@@ -35,4 +30,3 @@ status: "PAYER_ACTION_REQUIRED",

sdkConfig = defaultSdkConfig,
restClient = mockEligibilityRequest(),
graphQLClient = vi.fn(),
request = mockEligibilityRequest(),
logger = {

@@ -50,6 +44,4 @@ info: vi.fn().mockReturnThis(),

// $FlowIssue
restClient,
request,
// $FlowIssue
graphQLClient,
// $FlowIssue
logger,

@@ -62,3 +54,3 @@ });

describe.skip("three domain secure component - isEligible method", () => {
describe("three domain secure component - isEligible method", () => {
test("should return true if payer action required", async () => {

@@ -74,3 +66,3 @@ const threeDomainSecureClient = createThreeDomainSecureComponent();

const threeDomainSecureClient = createThreeDomainSecureComponent({
restClient: () =>
request: () =>
Promise.resolve({ ...defaultEligibilityResponse, status: "SUCCESS" }),

@@ -86,3 +78,3 @@ });

const threeDomainSecureClient = createThreeDomainSecureComponent({
restClient: () =>
request: () =>
Promise.resolve({

@@ -105,3 +97,3 @@ ...defaultEligibilityResponse,

const threeDomainSecureClient = createThreeDomainSecureComponent({
restClient: mockedRequest,
request: mockedRequest,
});

@@ -130,6 +122,6 @@

test.skip("catch errors from the API", async () => {
test("catch errors from the API", async () => {
const mockRequest = vi.fn().mockRejectedValue(new Error("Error with API"));
const threeDomainSecureClient = createThreeDomainSecureComponent({
restClient: mockRequest,
request: mockRequest,
});

@@ -136,0 +128,0 @@

/* @flow */
import {
getEnv,
getLogger,
getPayPalAPIDomain,
getSDKToken,
getUserIDToken,
} from "@paypal/sdk-client/src";
import { callRestAPI, devEnvOnlyExport } from "../lib";
import type { LazyExport } from "../types";

@@ -15,7 +15,3 @@

} from "./component";
import { GraphQLClient, RestClient } from "./api";
const BRAINTREE_PROD = "https://payments.braintree-api.com";
const BRAINTREE_SANDBOX = "https://payments.sandbox.braintree-api.com";
export const ThreeDomainSecureClient: LazyExport<ThreeDomainSecureComponentInterface> =

@@ -26,19 +22,14 @@ {

logger: getLogger(),
restClient: new RestClient(),
graphQLClient: new GraphQLClient({
baseURL:
getEnv() === "production" ? BRAINTREE_PROD : BRAINTREE_SANDBOX,
accessToken: getSDKToken(),
}),
// $FlowIssue ZalgoPromise vs Promise
request: callRestAPI,
sdkConfig: {
authenticationToken: getSDKToken(),
authenticationToken: getUserIDToken(),
paypalApiDomain: getPayPalAPIDomain(),
},
});
return {
return devEnvOnlyExport({
isEligible: (payload) => threeDomainSecureInstance.isEligible(payload),
show: () => threeDomainSecureInstance.show(),
};
});
},
};

@@ -499,3 +499,17 @@ /* eslint-disable eslint-comments/disable-enable-pair */

export type ButtonExtensions = {|
hasReturned: () => boolean,
resume: () => void,
|};
export type ButtonProps = {|
// app switch properties
appSwitchWhenAvailable: string,
listenForHashChanges: () => void,
removeListenerForHashChanges: () => void,
// Not passed to child iframe
// change any to HashChangeEvent when we move to typescript
// eslint-disable-next-line flowtype/no-weak-types
hashChangeHandler: (event: any) => void,
fundingSource?: ?$Values<typeof FUNDING>,

@@ -502,0 +516,0 @@ intent: $Values<typeof INTENT>,

@@ -53,2 +53,3 @@ /* @flow */

import { create, EVENT, type ZoidComponent } from "@krakenjs/zoid/src";
import { send as postRobotSend } from "@krakenjs/post-robot/src";
import {

@@ -77,2 +78,4 @@ uniqueID,

prepareInstrumentationPayload,
isAppSwitchResumeFlow,
getAppSwitchResumeParams,
} from "../../lib";

@@ -83,4 +86,6 @@ import {

type ButtonProps,
type ButtonExtensions,
} from "../../ui/buttons/props";
import { isFundingEligible } from "../../funding";
import { getPixelComponent } from "../pixel";
import { CLASS } from "../../constants";

@@ -101,6 +106,12 @@

export type ButtonsComponent = ZoidComponent<ButtonProps>;
export type ButtonsComponent = ZoidComponent<
ButtonProps,
void,
void,
ButtonExtensions
>;
export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
const queriedEligibleFunding = [];
return create({

@@ -111,2 +122,37 @@ tag: "paypal-buttons",

domain: getPayPalDomainRegex(),
getExtensions: (parent) => {
return {
hasReturned: () => {
return isAppSwitchResumeFlow();
},
resume: () => {
const resumeFlowParams = getAppSwitchResumeParams();
if (!resumeFlowParams) {
throw new Error("Resume Flow is not supported.");
}
getLogger().metricCounter({
namespace: "resume_flow.init.count",
event: "info",
dimensions: {
orderID: Boolean(resumeFlowParams.orderID),
vaultSessionID: Boolean(resumeFlowParams.vaultSetupToken),
billingToken: Boolean(resumeFlowParams.billingToken),
payerID: Boolean(resumeFlowParams.payerID),
},
});
const resumeComponent = getPixelComponent();
const parentProps = parent.getProps();
resumeComponent({
onApprove: parentProps.onApprove,
// $FlowIgnore[incompatible-call]
onError: parentProps.onError,
// $FlowIgnore[prop-missing] onCancel is incorrectly declared as oncancel in button props
onCancel: parentProps.onCancel,
onClick: parentProps.onClick,
onComplete: parentProps.onComplete,
resumeFlowParams,
}).render("body");
},
};
},

@@ -254,2 +300,59 @@ autoResize: {

props: {
// App Switch Properties
appSwitchWhenAvailable: {
// this value is a string for now while we test the app switch
// feature. Before we give this to a real merchant, we should
// change this to a boolean - Shane 11 Dec 2024
type: "string",
required: false,
},
hashChangeHandler: {
type: "function",
sendToChild: false,
queryParam: false,
required: false,
value: () => (event) => {
const iframes = document.querySelectorAll("iframe");
// I don't understand why but trying to make iframes which is a NodeList
// into an Iterable (so we could do a for..of loop or .forEach) is not
// working. It ends up iterating over itself so instead of looping over the contents
// of the NodeList you loop over the NodeList itself which is extremely unexpected
// for..in works though :shrug: - Shane 11 Dec 2024
for (let i = 0; i < iframes.length; i++) {
if (iframes[i].name.includes("zoid__paypal_buttons")) {
postRobotSend(
iframes[i].contentWindow,
"paypal-hashchange",
{
url: event.newURL,
},
{ domain: getPayPalDomain() }
);
}
}
},
},
listenForHashChanges: {
type: "function",
queryParam: false,
value:
({ props }) =>
() => {
window.addEventListener("hashchange", props.hashChangeHandler);
},
},
removeListenerForHashChanges: {
type: "function",
queryParam: false,
value:
({ props }) =>
() => {
window.removeEventListener("hashchange", props.hashChangeHandler);
},
},
// allowBillingPayments prop is used by Honey Extension to render the one-click button

@@ -256,0 +359,0 @@ // with payment methods & to use the payment methods instead of the Billing Agreement

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc