@paypal/checkout-components 5.0.347 → 5.0.348

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.347",
3
+ "version": "5.0.348",
4
4
  "description": "PayPal Checkout components, for integrating checkout products.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,7 +12,7 @@
12
12
  "debug": "cross-env NODE_ENV=debug",
13
13
  "delete-size": "rm dist/size.* dist/report.html",
14
14
  "demo": "serve ./demo -l 1337",
15
- "dev": "npm run check-node-version && babel-node $(npm bin)/webpack-dev-server -- --config webpack.config.dev.js --port 9001 --host localhost.paypal.com --open /index.htm --https --hot=false --static './demo/dev'",
15
+ "dev": "npm run check-node-version && babel-node ./node_modules/.bin/webpack-dev-server -- --config webpack.config.dev.js --port 9001 --host localhost.paypal.com --open /index.htm --https --hot=false --static './demo/dev'",
16
16
  "eslint-find-rules": "eslint-find-rules --current .eslintrc.js --unused --plugin",
17
17
  "flow": "flow",
18
18
  "flow-typed": "rm -rf flow-typed && flow-typed install && rm flow-typed/npm/puppeteer_*",
@@ -21,7 +21,7 @@
21
21
  "jest-e2e": "rm -f ./test/e2e/screenshots/*.png && jest test/e2e",
22
22
  "jest-screenshot": "jest test/screenshot --env=node --no-cache",
23
23
  "jest-ssr": "jest test/ssr --env=node --no-cache --collectCoverage --collectCoverageFrom='src/' --coverageDirectory='coverage/jest'",
24
- "karma": "cross-env NODE_ENV=test babel-node $(npm bin)/karma start",
24
+ "karma": "cross-env NODE_ENV=test babel-node ./node_modules/.bin/karma start",
25
25
  "lint": "eslint --ext .js --ext .jsx src/ test/ *.js",
26
26
  "postversion": "./scripts/postversion.sh",
27
27
  "preversion": "./scripts/preversion.sh",
@@ -34,11 +34,15 @@
34
34
  "typecheck": "npm run flow",
35
35
  "version": "./scripts/version.sh",
36
36
  "vitest": "vitest",
37
- "webpack": "babel-node $(npm bin)/webpack --",
37
+ "webpack": "babel-node ./node_modules/.bin/webpack --",
38
38
  "webpack-size": "npm run webpack -- --config webpack.config.size",
39
39
  "prepare": "husky install",
40
40
  "screenshot-server": "babel-node ./test/percy/server/index.js"
41
41
  },
42
+ "engines": {
43
+ "node": "^18",
44
+ "npm": "8"
45
+ },
42
46
  "files": [
43
47
  "src/",
44
48
  "dist/",
@@ -23,19 +23,20 @@ export function getVenmoConfig(): FundingSourceConfig {
23
23
 
24
24
  eligible: ({ experiment, shippingChange, displayOnly, flow }) => {
25
25
  /**
26
- * This could probably be removed if the enableVenmo experiment is
27
- * rolled out to 100%.
26
+ * enableVenmo checks native browser compatibility and ramp
27
+ * ignore above compatibility if forcing to web
28
28
  */
29
- if (experiment && experiment.enableVenmo === false) {
29
+ if (
30
+ experiment &&
31
+ experiment.enableVenmo === false &&
32
+ experiment.venmoWebEnabled !== true &&
33
+ experiment.venmoEnableWebOnNonNativeBrowser !== true
34
+ ) {
30
35
  return false;
31
36
  }
32
37
 
33
38
  /**
34
39
  * Shipping callbacks will not work with Venmo unless venmo web is enabled.
35
- *
36
- * Note that this could cause the Venmo button to not show up on first render
37
- * if a merchant passes a shipping callback but does not have a client ID
38
- * that has Venmo Web enabled.
39
40
  */
40
41
  if (!experiment?.venmoWebEnabled && shippingChange) {
41
42
  return false;
@@ -62,7 +63,8 @@ export function getVenmoConfig(): FundingSourceConfig {
62
63
  if (
63
64
  platform === PLATFORM.MOBILE &&
64
65
  experiment &&
65
- experiment.venmoWebEnabled === false
66
+ experiment.venmoWebEnabled !== true &&
67
+ experiment.venmoEnableWebOnNonNativeBrowser !== true
66
68
  ) {
67
69
  return {
68
70
  native: true,
@@ -13,6 +13,7 @@ describe("Venmo eligibility", () => {
13
13
  fundingEligibility: {},
14
14
  experiment: {
15
15
  venmoWebEnabled: true,
16
+ venmoEnableWebOnNonNativeBrowser: true,
16
17
  },
17
18
  wallet: expect.any,
18
19
  flow: BUTTON_FLOW.PURCHASE,
@@ -74,7 +75,7 @@ describe("Venmo eligibility", () => {
74
75
  expect(isVenmoEligible).toEqual(true);
75
76
  });
76
77
 
77
- test("should not be eligible if a shipping callback is passed & experiment does not include venmoWebEnabled", () => {
78
+ test("should not be eligible if a shipping callback is passed & experiment does not include venmoWebEnabled or venmoEnableWebOnNonNativeBrowser", () => {
78
79
  const isVenmoEligible = venmoConfig.eligible?.({
79
80
  ...baseEligibilityProps,
80
81
  experiment: {},
@@ -84,7 +85,7 @@ describe("Venmo eligibility", () => {
84
85
  expect(isVenmoEligible).toEqual(false);
85
86
  });
86
87
 
87
- test("should be eligible if shipping callback exists & experiment includes venmoWebEnabled", () => {
88
+ test("should be eligible if shipping callback exists & experiment includes venmoWebEnabled or venmoEnableWebOnNonNativeBrowser", () => {
88
89
  const isVenmoEligible = venmoConfig.eligible?.({
89
90
  ...baseEligibilityProps,
90
91
  shippingChange: true,
@@ -1,5 +1,6 @@
1
1
  /* @flow */
2
2
  import { FUNDING } from "@paypal/sdk-constants/src";
3
+ import { parseQuery } from "@krakenjs/belter/src";
3
4
 
4
5
  import { APP_SWITCH_RETURN_HASH } from "../constants";
5
6
 
@@ -16,46 +17,47 @@ export type AppSwitchResumeParams = {|
16
17
  |};
17
18
 
18
19
  export function getAppSwitchResumeParams(): AppSwitchResumeParams | null {
19
- const urlHash = String(window.location.hash).replace("#", "");
20
+ const hashString = window.location.hash && window.location.hash.slice(1);
21
+ const [hash, queryString] = hashString.split("?");
22
+
20
23
  const isPostApprovalAction = [
21
24
  APP_SWITCH_RETURN_HASH.ONAPPROVE,
22
25
  APP_SWITCH_RETURN_HASH.ONCANCEL,
23
26
  APP_SWITCH_RETURN_HASH.ONERROR,
24
- ].includes(urlHash);
27
+ ].includes(hash);
25
28
  if (!isPostApprovalAction) {
26
29
  return null;
27
30
  }
28
- // eslint-disable-next-line compat/compat
29
- const search = new URLSearchParams(window.location.search);
30
- const orderID = search.get("orderID");
31
- const payerID = search.get("payerID");
32
- const buttonSessionID = search.get("buttonSessionID");
33
- const billingToken = search.get("billingToken");
34
- const paymentID = search.get("paymentID");
35
- const subscriptionID = search.get("subscriptionID");
36
- const vaultSetupToken = search.get("vaultSetupToken");
37
- const fundingSource = search.get("fundingSource");
38
- if (buttonSessionID) {
39
- const params: AppSwitchResumeParams = {
40
- orderID,
41
- buttonSessionID,
42
- payerID,
43
- billingToken,
44
- paymentID,
45
- subscriptionID,
46
- // URLSearchParams get returns as string,
47
- // but below code excepts a value from list of string.
48
- // $FlowIgnore[incompatible-type]
49
- fundingSource,
50
- vaultSetupToken,
51
- // the isPostApprovalAction already ensures
52
- // that the function will exit if url hash is not one of supported values.
53
- // $FlowIgnore[incompatible-type]
54
- checkoutState: urlHash,
55
- };
56
- return params;
57
- }
58
- return null;
31
+
32
+ const {
33
+ token,
34
+ PayerID,
35
+ buttonSessionID,
36
+ billingToken,
37
+ paymentID,
38
+ subscriptionID,
39
+ vaultSetupToken,
40
+ fundingSource,
41
+ } = parseQuery(queryString);
42
+
43
+ const params: AppSwitchResumeParams = {
44
+ orderID: token,
45
+ buttonSessionID,
46
+ payerID: PayerID,
47
+ billingToken,
48
+ paymentID,
49
+ subscriptionID,
50
+ // URLSearchParams get returns as string,
51
+ // but below code excepts a value from list of string.
52
+ // $FlowIgnore[incompatible-type]
53
+ fundingSource,
54
+ vaultSetupToken,
55
+ // the isPostApprovalAction already ensures
56
+ // that the function will exit if url hash is not one of supported values.
57
+ // $FlowIgnore[incompatible-type]
58
+ checkoutState: hash,
59
+ };
60
+ return params;
59
61
  }
60
62
 
61
63
  export function isAppSwitchResumeFlow(): boolean {
@@ -26,23 +26,17 @@ describe("app switch resume flow", () => {
26
26
 
27
27
  test("should test fetching resume params when parameters are correctly passed", () => {
28
28
  vi.spyOn(window, "location", "get").mockReturnValue({
29
- hash: "#onApprove",
30
- search: `buttonSessionID=${buttonSessionID}&orderID=${orderID}&fundingSource=${fundingSource}`,
29
+ hash: `#onApprove?buttonSessionID=${buttonSessionID}&token=${orderID}&fundingSource=${fundingSource}`,
31
30
  });
32
31
 
33
32
  const params = getAppSwitchResumeParams();
34
33
 
35
34
  expect.assertions(2);
36
35
  expect(params).toEqual({
37
- billingToken: null,
38
36
  buttonSessionID,
39
37
  checkoutState: "onApprove",
40
38
  fundingSource,
41
39
  orderID,
42
- payerID: null,
43
- paymentID: null,
44
- subscriptionID: null,
45
- vaultSetupToken: null,
46
40
  });
47
41
  expect(isAppSwitchResumeFlow()).toEqual(true);
48
42
  });
@@ -50,7 +44,7 @@ describe("app switch resume flow", () => {
50
44
  test("should test fetching resume params with invalid callback passed", () => {
51
45
  vi.spyOn(window, "location", "get").mockReturnValue({
52
46
  hash: "#Unknown",
53
- search: `buttonSessionID=${buttonSessionID}&orderID=${orderID}&fundingSource=${fundingSource}`,
47
+ search: `buttonSessionID=${buttonSessionID}&token=${orderID}&fundingSource=${fundingSource}`,
54
48
  });
55
49
 
56
50
  const params = getAppSwitchResumeParams();
@@ -62,8 +56,7 @@ describe("app switch resume flow", () => {
62
56
 
63
57
  test("should test null fetching resume params with invalid callback passed", () => {
64
58
  vi.spyOn(window, "location", "get").mockReturnValue({
65
- hash: "#Unknown",
66
- search: `buttonSessionID=${buttonSessionID}&orderID=${orderID}&fundingSource=${fundingSource}`,
59
+ hash: `#Unknown?buttonSessionID=${buttonSessionID}&token=${orderID}&fundingSource=${fundingSource}`,
67
60
  });
68
61
 
69
62
  const params = getAppSwitchResumeParams();
@@ -73,10 +66,9 @@ describe("app switch resume flow", () => {
73
66
  expect(isAppSwitchResumeFlow()).toEqual(false);
74
67
  });
75
68
 
76
- test("should test fetching resume params when parameters are correctly passed", () => {
69
+ test("should test fetching multiple resume params when parameters are correctly passed", () => {
77
70
  vi.spyOn(window, "location", "get").mockReturnValue({
78
- hash: "#onApprove",
79
- search: `buttonSessionID=${buttonSessionID}&orderID=${orderID}&fundingSource=${fundingSource}&billingToken=BA-124&payerID=PP-122&paymentID=PAY-123&subscriptionID=I-1234&vaultSetupToken=VA-3`,
71
+ hash: `#onApprove?buttonSessionID=${buttonSessionID}&token=${orderID}&fundingSource=${fundingSource}&billingToken=BA-124&PayerID=PP-payer-122&paymentID=PAY-123&subscriptionID=I-1234&vaultSetupToken=VA-3`,
80
72
  });
81
73
 
82
74
  const params = getAppSwitchResumeParams();
@@ -88,7 +80,7 @@ describe("app switch resume flow", () => {
88
80
  checkoutState: "onApprove",
89
81
  fundingSource,
90
82
  orderID,
91
- payerID: "PP-122",
83
+ payerID: "PP-payer-122",
92
84
  paymentID: "PAY-123",
93
85
  subscriptionID: "I-1234",
94
86
  vaultSetupToken: "VA-3",
@@ -39,40 +39,15 @@ export class HTTPClient implements HTTPClientType {
39
39
  }
40
40
 
41
41
  export class RestClient extends HTTPClient {
42
- request({ baseURL, ...rest }: HTTPRequestOptions): ZalgoPromise<{ ... }> {
43
- return callRestAPI({
44
- url: baseURL ?? this.baseURL ?? "",
45
- accessToken: this.accessToken,
46
- ...rest,
47
- });
48
- }
49
- authRequest({
42
+ request({
50
43
  baseURL,
51
44
  accessToken,
52
45
  ...rest
53
46
  }: HTTPRequestOptions): ZalgoPromise<{ ... }> {
54
- return request({
55
- method: "post",
47
+ return callRestAPI({
56
48
  url: baseURL ?? this.baseURL ?? "",
57
- headers: {
58
- // $FlowIssue
59
- Authorization: `Basic ${accessToken}`,
60
- },
49
+ accessToken: accessToken ?? this.accessToken,
61
50
  ...rest,
62
- }).then(({ body }) => {
63
- if (body && body.error === "invalid_client") {
64
- throw new Error(
65
- `Auth Api invalid client id: \n\n${JSON.stringify(body, null, 4)}`
66
- );
67
- }
68
-
69
- if (!body || !body.access_token) {
70
- throw new Error(
71
- `Auth Api response error:\n\n${JSON.stringify(body, null, 4)}`
72
- );
73
- }
74
-
75
- return body.access_token;
76
51
  });
77
52
  }
78
53
  }
@@ -3,24 +3,21 @@
3
3
  /* eslint-disable no-restricted-globals, promise/no-native */
4
4
  import { type LoggerType } from "@krakenjs/beaver-logger/src";
5
5
  import { type ZoidComponent } from "@krakenjs/zoid/src";
6
- import { base64encode } from "@krakenjs/belter/src";
7
6
  import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
8
7
  import { FPTI_KEY, CURRENCY } from "@paypal/sdk-constants/src";
9
8
 
10
- import { PAYMENT_3DS_VERIFICATION, AUTH } from "../constants/api";
9
+ import { PAYMENT_3DS_VERIFICATION } from "../constants/api";
11
10
  import { ValidationError } from "../lib";
12
11
 
13
12
  import type {
14
13
  requestData,
15
- responseBody,
16
14
  GqlResponse,
17
15
  MerchantPayloadData,
18
16
  SdkConfig,
19
17
  ThreeDSResponse,
20
18
  TDSProps,
21
- Request,
22
19
  } from "./types";
23
- import { getFastlaneThreeDS } from "./utils";
20
+ import { getThreeDS } from "./utils";
24
21
  import type { GraphQLClient, RestClient } from "./api";
25
22
 
26
23
  const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => {
@@ -99,35 +96,9 @@ export class ThreeDomainSecureComponent {
99
96
  const data = parseMerchantPayload({ merchantPayload });
100
97
  this.fastlaneNonce = merchantPayload.nonce;
101
98
 
102
- try {
103
- const basicAuth = base64encode(`${this.sdkConfig.clientID}:`);
104
- const authData = {
105
- grant_type: `client_credentials`,
106
- };
107
-
108
- if (this.sdkConfig.merchantID?.length) {
109
- // $FlowFixMe invalid error on key assignment
110
- authData.target_subject = this.sdkConfig.merchantID[0];
111
- }
112
- // $FlowFixMe
113
- const accessToken = await this.restClient.authRequest<Request, string>({
114
- baseURL: `${this.sdkConfig.paypalApiDomain}${AUTH}`,
115
- accessToken: `${basicAuth}`,
116
- data: authData,
117
- });
118
- // $FlowIssue confusing ZalgoPromise return type with resolved string value
119
- this.restClient.setAccessToken(accessToken);
120
- } catch (error) {
121
- this.logger.warn(error);
122
- throw error;
123
- }
124
-
125
99
  try {
126
100
  // $FlowFixMe
127
- const { status, links } = await this.restClient.request<
128
- requestData,
129
- responseBody
130
- >({
101
+ const { status, links } = await this.restClient.request({
131
102
  method: "POST",
132
103
  baseURL: `${this.sdkConfig.paypalApiDomain}/${PAYMENT_3DS_VERIFICATION}`,
133
104
  data,
@@ -139,7 +110,7 @@ export class ThreeDomainSecureComponent {
139
110
  (link) => link.rel === "payer-action"
140
111
  ).href;
141
112
  responseStatus = true;
142
- this.threeDSIframe = getFastlaneThreeDS();
113
+ this.threeDSIframe = getThreeDS();
143
114
  }
144
115
  return responseStatus;
145
116
  } catch (error) {
@@ -180,7 +151,7 @@ export class ThreeDomainSecureComponent {
180
151
  // Helios returns a boolen parameter: "success"
181
152
  // It will be true for all cases where liability is shifted to merchant
182
153
  // and false for downstream failures and errors
183
- authenticationState = success ? "success" : "errored";
154
+ authenticationState = success ? "succeeded" : "errored";
184
155
  liabilityShift = liability_shift ? liability_shift : "false";
185
156
 
186
157
  // call BT mutation to update fastlaneNonce with 3ds data
@@ -12,7 +12,7 @@ const defaultSdkConfig = {
12
12
  authenticationToken: "sdk-client-token",
13
13
  };
14
14
  vi.mock("./utils", () => ({
15
- getFastlaneThreeDS: vi.fn(() => {
15
+ getThreeDS: vi.fn(() => {
16
16
  return vi.fn(() => ({
17
17
  render: vi.fn().mockResolvedValue({}),
18
18
  close: vi.fn(),
@@ -45,7 +45,6 @@ const mockRestClient = {
45
45
  },
46
46
  ],
47
47
  }),
48
- authRequest: vi.fn(),
49
48
  };
50
49
 
51
50
  const mockEligibilityRequest = (body = defaultEligibilityResponse) => {
@@ -5,7 +5,6 @@ import {
5
5
  getPayPalAPIDomain,
6
6
  getSDKToken,
7
7
  getClientID,
8
- getMerchantID,
9
8
  } from "@paypal/sdk-client/src";
10
9
  import { destroy as zoidDestroy } from "@krakenjs/zoid/src";
11
10
 
@@ -17,13 +16,13 @@ import {
17
16
  type ThreeDomainSecureComponentInterface,
18
17
  } from "./component";
19
18
  import { GraphQLClient, RestClient } from "./api";
20
- import { getFastlaneThreeDS } from "./utils";
19
+ import { getThreeDS } from "./utils";
21
20
 
22
21
  const BRAINTREE_PROD = "https://payments.braintree-api.com";
23
22
  const BRAINTREE_SANDBOX = "https://payments.sandbox.braintree-api.com";
24
23
 
25
24
  export function setup() {
26
- getFastlaneThreeDS();
25
+ getThreeDS();
27
26
  }
28
27
  export function destroy(err?: mixed) {
29
28
  zoidDestroy(err);
@@ -34,7 +33,7 @@ export const ThreeDomainSecureClient: LazyExport<ThreeDomainSecureComponentInter
34
33
  __get__: () => {
35
34
  const threeDomainSecureInstance = new ThreeDomainSecureComponent({
36
35
  logger: getLogger(),
37
- restClient: new RestClient(),
36
+ restClient: new RestClient({ accessToken: getSDKToken() }),
38
37
  graphQLClient: new GraphQLClient({
39
38
  baseURL:
40
39
  getEnv() === "production" ? BRAINTREE_PROD : BRAINTREE_SANDBOX,
@@ -45,7 +44,6 @@ export const ThreeDomainSecureClient: LazyExport<ThreeDomainSecureComponentInter
45
44
  authenticationToken: getSDKToken(),
46
45
  paypalApiDomain: getPayPalAPIDomain(),
47
46
  clientID: getClientID(),
48
- merchantID: getMerchantID(),
49
47
  },
50
48
  });
51
49
  return devEnvOnlyExport({
@@ -11,7 +11,7 @@ import { destroy as zoidDestroy } from "@krakenjs/zoid/src";
11
11
 
12
12
  import { ThreeDomainSecureComponent } from "./component";
13
13
  import { GraphQLClient, RestClient } from "./api";
14
- import { getFastlaneThreeDS } from "./utils";
14
+ import { getThreeDS } from "./utils";
15
15
  import { setup, destroy, ThreeDomainSecureClient } from "./interface";
16
16
 
17
17
  vi.mock("@paypal/sdk-client/src");
@@ -23,7 +23,7 @@ vi.mock("./utils");
23
23
  describe("ThreeDomainSecure interface", () => {
24
24
  it("should setup and destroy", () => {
25
25
  setup();
26
- expect(getFastlaneThreeDS).toHaveBeenCalledTimes(1);
26
+ expect(getThreeDS).toHaveBeenCalledTimes(1);
27
27
 
28
28
  const err = new Error("test error");
29
29
  destroy(err);
@@ -18,8 +18,8 @@ import type { TDSProps } from "./types";
18
18
 
19
19
  export type TDSComponent = ZoidComponent<TDSProps>;
20
20
 
21
- export function getFastlaneThreeDS(): TDSComponent {
22
- return inlineMemoize(getFastlaneThreeDS, () => {
21
+ export function getThreeDS(): TDSComponent {
22
+ return inlineMemoize(getThreeDS, () => {
23
23
  const component = create({
24
24
  tag: "fastlane-threeds",
25
25
  url: ({ props }) => props.payerActionUrl,
@@ -6,7 +6,7 @@ import { noop } from "@krakenjs/belter/src";
6
6
  import { describe, expect, vi } from "vitest";
7
7
  import { getEnv } from "@paypal/sdk-client/src";
8
8
 
9
- import { getFastlaneThreeDS } from "./utils";
9
+ import { getThreeDS } from "./utils";
10
10
 
11
11
  vi.mock("@paypal/sdk-client/src");
12
12
 
@@ -27,7 +27,7 @@ describe("Three Domain Secure Utils", () => {
27
27
  type: "zoidComponent",
28
28
  }));
29
29
 
30
- const fastlaneComponent = getFastlaneThreeDS();
30
+ const fastlaneComponent = getThreeDS();
31
31
  expect(fastlaneComponent).toBeDefined();
32
32
  // expect(createMock).toHaveBeenCalledTimes(1);
33
33
  });
@@ -43,7 +43,7 @@ describe("Three Domain Secure Utils", () => {
43
43
  type: "zoidComponent",
44
44
  }));
45
45
 
46
- getFastlaneThreeDS();
46
+ getThreeDS();
47
47
 
48
48
  expect(window.xchild).toBeDefined();
49
49
  expect(window.xchild).toEqual({
package/src/types.js CHANGED
@@ -62,6 +62,7 @@ export type Experiment = {|
62
62
  venmoWebEnabled?: boolean,
63
63
  // first render experiments
64
64
  venmoVaultWithoutPurchase?: boolean,
65
+ venmoEnableWebOnNonNativeBrowser?: boolean,
65
66
  |};
66
67
 
67
68
  export type Requires = {|
@@ -42,6 +42,7 @@ import {
42
42
  getSDKAttribute,
43
43
  getJsSdkLibrary,
44
44
  wasShopperInsightsUsed,
45
+ isPayPalTrustedUrl,
45
46
  } from "@paypal/sdk-client/src";
46
47
  import {
47
48
  rememberFunding,
@@ -292,15 +293,24 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
292
293
  },
293
294
 
294
295
  props: {
295
- // App Switch Properties
296
296
  appSwitchWhenAvailable: {
297
- // this value is a string for now while we test the app switch
298
- // feature. Before we give this to a real merchant, we should
299
- // change this to a boolean - Shane 11 Dec 2024
300
- type: "string",
297
+ type: "boolean",
298
+ queryParam: true,
301
299
  required: false,
302
300
  },
303
301
 
302
+ redirect: {
303
+ type: "function",
304
+ sendToChild: true,
305
+ value: () => (url) => {
306
+ if (isPayPalTrustedUrl(url)) {
307
+ location.href = url;
308
+ } else {
309
+ throw new Error(`Unable to redirect to provided url ${url}`);
310
+ }
311
+ },
312
+ },
313
+
304
314
  hashChangeHandler: {
305
315
  type: "function",
306
316
  sendToChild: false,
@@ -77,6 +77,7 @@ type CardFieldsProps = {|
77
77
  fundingEligibility: FundingEligibilityType,
78
78
  disableCard?: $ReadOnlyArray<$Values<typeof CARD>>,
79
79
  currency: $Values<typeof CURRENCY>,
80
+ amount: string,
80
81
  intent: $Values<typeof INTENT>,
81
82
  commit: boolean,
82
83
  vault: boolean,
@@ -297,6 +298,12 @@ export const getCardFieldsComponent: () => CardFieldsComponent = memoize(
297
298
  value: ({ props }) => props.parent.props.locale,
298
299
  },
299
300
 
301
+ amount: {
302
+ type: "object",
303
+ value: ({ props }) => props.parent.props.amount,
304
+ required: false,
305
+ },
306
+
300
307
  onApprove: {
301
308
  type: "function",
302
309
  required: false,
@@ -639,6 +646,11 @@ export const getCardFieldsComponent: () => CardFieldsComponent = memoize(
639
646
  value: getLocale,
640
647
  },
641
648
 
649
+ amount: {
650
+ type: "object",
651
+ required: false,
652
+ },
653
+
642
654
  onApprove: {
643
655
  type: "function",
644
656
  required: false,
@@ -296,6 +296,12 @@ export function getVenmoCheckoutComponent(): VenmoCheckoutComponent {
296
296
  required: false,
297
297
  },
298
298
 
299
+ venmoEnableWebOnNonNativeBrowser: {
300
+ type: "boolean",
301
+ queryParam: true,
302
+ required: false,
303
+ },
304
+
299
305
  venmoVaultEnabled: {
300
306
  type: "boolean",
301
307
  queryParam: true,