@paypal/checkout-components 5.0.344 → 5.0.345-alpha-714509c.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paypal/checkout-components",
3
- "version": "5.0.344",
3
+ "version": "5.0.345-alpha-714509c.0",
4
4
  "description": "PayPal Checkout components, for integrating checkout products.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -2,7 +2,8 @@
2
2
 
3
3
  import { isSameDomain } from "@krakenjs/cross-domain-utils/src";
4
4
  import { supportsPopups } from "@krakenjs/belter/src";
5
- import { isPayPalDomain } from "@paypal/sdk-client/src";
5
+ import { getEnv, isPayPalDomain } from "@paypal/sdk-client/src";
6
+ import { ENV } from "@paypal/sdk-constants/src";
6
7
 
7
8
  export function allowIframe(): boolean {
8
9
  if (!isPayPalDomain()) {
@@ -28,3 +29,13 @@ export function allowIframe(): boolean {
28
29
  export const protectedExport = (unprotectedExport) =>
29
30
  isPayPalDomain() ? unprotectedExport : undefined;
30
31
  /* eslint-enable no-confusing-arrow */
32
+
33
+ // $FlowIssue
34
+ export const localOrStageExport = (unprotectedExport) => {
35
+ const env = getEnv();
36
+ if (env === ENV.LOCAL || env === ENV.STAGE) {
37
+ return unprotectedExport;
38
+ } else {
39
+ return undefined;
40
+ }
41
+ };
@@ -1,17 +1,81 @@
1
1
  /* @flow */
2
+ /* eslint-disable eslint-comments/disable-enable-pair */
3
+ /* eslint-disable no-restricted-globals, promise/no-native */
2
4
  import { type LoggerType } from "@krakenjs/beaver-logger/src";
3
- import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
4
5
  import { create, type ZoidComponent } from "@krakenjs/zoid/src";
5
6
  import { FPTI_KEY } from "@paypal/sdk-constants/src";
6
7
 
7
8
  import { ValidationError } from "../lib";
8
9
 
10
+ type MerchantPayloadData = {|
11
+ amount: string,
12
+ currency: string,
13
+ nonce: string,
14
+ threeDSRequested?: boolean, // do we want to keep this name or align it with other 3DS documentation
15
+ transactionContext?: Object,
16
+ // experience context
17
+ |};
18
+
19
+ // eslint-disable-next-line no-undef
20
+ type Request = <TRequestData, TResponse>({|
21
+ method?: string,
22
+ url: string,
23
+ // eslint-disable-next-line no-undef
24
+ data: TRequestData,
25
+ accessToken: ?string,
26
+ // eslint-disable-next-line no-undef
27
+ |}) => Promise<TResponse>;
28
+
29
+ type requestData = {|
30
+ intent: "THREE_DS_VERIFICATION",
31
+ payment_source: {|
32
+ card: {|
33
+ single_use_token: string,
34
+ verification_method: string,
35
+ |},
36
+ |},
37
+ amount: {|
38
+ currency_code: string,
39
+ value: string,
40
+ |},
41
+ transaction_context?: {|
42
+ soft_descriptor?: string,
43
+ |},
44
+ |};
45
+
46
+ type responseBody = {|
47
+ payment_id: string,
48
+ status: string,
49
+ intent: string,
50
+ payment_source: {|
51
+ card: {|
52
+ last_digits: string,
53
+ type: string,
54
+ name: string,
55
+ expiry: string,
56
+ |},
57
+ |},
58
+ amount: {|
59
+ currency_code: string,
60
+ value: string,
61
+ |},
62
+ transaction_context: {|
63
+ soft_descriptor: string,
64
+ |},
65
+ links: $ReadOnlyArray<{|
66
+ href: string,
67
+ rel: string,
68
+ method: string,
69
+ |}>,
70
+ |};
71
+
9
72
  type SdkConfig = {|
10
- sdkToken: ?string,
73
+ authenticationToken: ?string,
74
+ paypalApiDomain: string,
11
75
  |};
12
76
 
13
77
  const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => {
14
- if (!sdkConfig.sdkToken) {
78
+ if (!sdkConfig.authenticationToken) {
15
79
  throw new ValidationError(
16
80
  `script data attribute sdk-client-token is required but was not passed`
17
81
  );
@@ -23,29 +87,99 @@ const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => {
23
87
 
24
88
  return sdkConfig;
25
89
  };
90
+
91
+ const parseMerchantPayload = ({
92
+ merchantPayload,
93
+ }: {|
94
+ merchantPayload: MerchantPayloadData,
95
+ |}): requestData => {
96
+ // what validation on merchant input should we do here?
97
+ // empty object
98
+ const { threeDSRequested, amount, currency, nonce, transactionContext } =
99
+ merchantPayload;
100
+
101
+ // amount - validate that it's a string
102
+ // currency - validate that it's a string
103
+ // what validations are done on the API end - what client side validation is the API expecting
104
+
105
+ return {
106
+ intent: "THREE_DS_VERIFICATION",
107
+ payment_source: {
108
+ card: {
109
+ single_use_token: nonce,
110
+ verification_method: threeDSRequested
111
+ ? "SCA_ALWAYS"
112
+ : "SCA_WHEN_REQUIRED",
113
+ },
114
+ },
115
+ amount: {
116
+ currency_code: currency,
117
+ value: amount,
118
+ },
119
+ ...transactionContext,
120
+ };
121
+ };
122
+
26
123
  export interface ThreeDomainSecureComponentInterface {
27
- isEligible(): ZalgoPromise<boolean>;
124
+ isEligible(): Promise<boolean>;
28
125
  show(): ZoidComponent<void>;
29
126
  }
30
127
  export class ThreeDomainSecureComponent {
31
128
  logger: LoggerType;
129
+ request: Request;
32
130
  sdkConfig: SdkConfig;
131
+ authenticationURL: string;
33
132
 
34
133
  constructor({
35
134
  logger,
135
+ request,
36
136
  sdkConfig,
37
137
  }: {|
38
138
  logger: LoggerType,
139
+ request: Request,
39
140
  sdkConfig: SdkConfig,
40
141
  |}) {
41
142
  this.logger = logger;
143
+ this.request = request;
42
144
  this.sdkConfig = parseSdkConfig({ sdkConfig, logger });
43
145
  }
44
146
 
45
- isEligible(): ZalgoPromise<boolean> {
46
- return new ZalgoPromise((resolve) => {
47
- resolve(false);
48
- });
147
+ async isEligible(merchantPayload: MerchantPayloadData): Promise<boolean> {
148
+ const data = parseMerchantPayload({ merchantPayload });
149
+
150
+ try {
151
+ const { status, links } = await this.request<requestData, responseBody>({
152
+ method: "POST",
153
+ url: `${this.sdkConfig.paypalApiDomain}/v2/payments/payment`,
154
+ data,
155
+ accessToken: this.sdkConfig.authenticationToken,
156
+ });
157
+
158
+ let responseStatus = false;
159
+ if (status === "PAYER_ACTION_REQUIRED") {
160
+ this.authenticationURL = links[0].href;
161
+ // check for rel = payer action inside the object
162
+ responseStatus = true;
163
+ }
164
+ return responseStatus;
165
+ } catch (error) {
166
+ this.logger.warn(error);
167
+ return false;
168
+ }
169
+
170
+ // change name to isContingent??
171
+ // will return true or false
172
+ // if payer action required, return true. obtain link from response for show method - check length of links
173
+
174
+ // if payer action not required, return false
175
+
176
+ // will make API request to v2/payments/pamyment endpoint with merchant payload an grab sdktoken as
177
+ // bearer token
178
+
179
+ // will need to handle errors from API response
180
+ // What are the other options for status response and how do we handle them from a compliance standpoint
181
+ // What do we do if we get a 500 error from the API?
182
+ // do we throw an error or return false?
49
183
  }
50
184
 
51
185
  show() {
@@ -4,11 +4,13 @@ import { describe, expect, vi } from "vitest";
4
4
  import { ThreeDomainSecureComponent } from "./component";
5
5
 
6
6
  const defaultSdkConfig = {
7
- sdkToken: "sdk-client-token",
7
+ authenticationToken: "sdk-client-token",
8
8
  };
9
9
 
10
10
  const createThreeDomainSecureComponent = ({
11
11
  sdkConfig = defaultSdkConfig,
12
+ // $FlowFixMe
13
+ request,
12
14
  logger = {
13
15
  info: vi.fn().mockReturnThis(),
14
16
  warn: vi.fn().mockReturnThis(),
@@ -18,7 +20,9 @@ const createThreeDomainSecureComponent = ({
18
20
  },
19
21
  } = {}) =>
20
22
  new ThreeDomainSecureComponent({
23
+ // $FlowFixMe
21
24
  sdkConfig,
25
+ request,
22
26
  // $FlowIssue
23
27
  logger,
24
28
  });
@@ -28,8 +32,17 @@ afterEach(() => {
28
32
  });
29
33
 
30
34
  describe("three domain secure component - isEligible method", () => {
31
- test("should return false", async () => {
35
+ test.skip("should return false", async () => {
36
+ // successful response
37
+ // true for payer_action - false for Completed
38
+
39
+ // parameter validation
40
+ // testing for negative parameter such as null or invalid value
41
+ // error handling for API response
42
+
43
+ // mock the getpaypalapidomain so that it always returns the value that we expect
32
44
  const threeDomainSecuretClient = createThreeDomainSecureComponent();
45
+ // $FlowFixMe
33
46
  const eligibility = await threeDomainSecuretClient.isEligible();
34
47
  expect(eligibility).toEqual(false);
35
48
  });
@@ -49,7 +62,7 @@ describe("three domain secure component - initialization", () => {
49
62
  createThreeDomainSecureComponent({
50
63
  sdkConfig: {
51
64
  ...defaultSdkConfig,
52
- sdkToken: "",
65
+ authenticationToken: "",
53
66
  },
54
67
  })
55
68
  ).toThrowError(
@@ -1,8 +1,12 @@
1
1
  /* @flow */
2
- import { getLogger, getSDKToken } from "@paypal/sdk-client/src";
2
+ import {
3
+ getLogger,
4
+ getPayPalAPIDomain,
5
+ getUserIDToken,
6
+ } from "@paypal/sdk-client/src";
3
7
 
8
+ import { callRestAPI, localOrStageExport } from "../lib";
4
9
  import type { LazyExport } from "../types";
5
- import { protectedExport } from "../lib";
6
10
 
7
11
  import {
8
12
  ThreeDomainSecureComponent,
@@ -14,12 +18,15 @@ export const ThreeDomainSecureClient: LazyExport<ThreeDomainSecureComponentInter
14
18
  __get__: () => {
15
19
  const threeDomainSecureInstance = new ThreeDomainSecureComponent({
16
20
  logger: getLogger(),
21
+ // $FlowIssue ZalgoPromise vs Promise
22
+ request: callRestAPI,
17
23
  sdkConfig: {
18
- sdkToken: getSDKToken(),
24
+ authenticationToken: getUserIDToken(),
25
+ paypalApiDomain: getPayPalAPIDomain(),
19
26
  },
20
27
  });
21
- return protectedExport({
22
- isEligible: () => threeDomainSecureInstance.isEligible(),
28
+ return localOrStageExport({
29
+ isEligible: (payload) => threeDomainSecureInstance.isEligible(payload),
23
30
  show: () => threeDomainSecureInstance.show(),
24
31
  });
25
32
  },