diff --git a/.changeset/dirty-seas-clean.md b/.changeset/dirty-seas-clean.md new file mode 100644 index 00000000..0fcc2d81 --- /dev/null +++ b/.changeset/dirty-seas-clean.md @@ -0,0 +1,6 @@ +--- +"@paypal/react-paypal-js": minor +"@paypal/paypal-js": minor +--- + +Add V6 instance provider and context hook diff --git a/package-lock.json b/package-lock.json index 8c023c13..1433437e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17651,7 +17651,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -40427,7 +40426,8 @@ "license": "Apache-2.0", "dependencies": { "@paypal/paypal-js": "^9.0.0", - "@paypal/sdk-constants": "^1.0.122" + "@paypal/sdk-constants": "^1.0.122", + "dequal": "^2.0.3" }, "devDependencies": { "@babel/core": "^7.17.5", diff --git a/packages/paypal-js/CHANGELOG.md b/packages/paypal-js/CHANGELOG.md index 6bca404b..4bb38394 100644 --- a/packages/paypal-js/CHANGELOG.md +++ b/packages/paypal-js/CHANGELOG.md @@ -4,126 +4,126 @@ ### Patch Changes -- 53b1f63: Export v6 types for all callbacks +- 53b1f63: Export v6 types for all callbacks ## 9.0.0 ### Major Changes -- 6c83cf1: Added the missing style properties to the type definitions so developers can correctly pass styling options to PayPal card fields or PayPalCardFieldsProvider without TypeScript errors. +- 6c83cf1: Added the missing style properties to the type definitions so developers can correctly pass styling options to PayPal card fields or PayPalCardFieldsProvider without TypeScript errors. ### Minor Changes -- 9b6eecc: Update types for the v6 web sdk +- 9b6eecc: Update types for the v6 web sdk ### Patch Changes -- 0575877: Upgrade to package-lock v3 and fix rollup dependency +- 0575877: Upgrade to package-lock v3 and fix rollup dependency ## 8.4.2 ### Patch Changes -- 9423b3d: fix: use correct type name with v6 script load options -- 415c94e: Fix SdkInstance type definition conditional statements. +- 9423b3d: fix: use correct type name with v6 script load options +- 415c94e: Fix SdkInstance type definition conditional statements. ## 8.4.1 ### Patch Changes -- f97adb4: fix: update type for v6 loader loadCoreSdkScript +- f97adb4: fix: update type for v6 loader loadCoreSdkScript ## 8.4.0 ### Minor Changes -- 4d51a9a: Add new script loader for v6 core sdk script +- 4d51a9a: Add new script loader for v6 core sdk script ### Patch Changes -- d3851e4: Adds types for v5 Direct App Switch +- d3851e4: Adds types for v5 Direct App Switch ## 8.3.1 ### Patch Changes -- c22489a: Update tsconfig location for paypal-js package +- c22489a: Update tsconfig location for paypal-js package ## 8.3.0 ### Minor Changes -- f594d7e: Update rollup config and add V6 types +- f594d7e: Update rollup config and add V6 types ## 8.2.0 ### Minor Changes -- 6f339f6: Adding test for card-fields.test.ts +- 6f339f6: Adding test for card-fields.test.ts ## 8.1.3 ### Patch Changes -- b2253cc: Prevent option paremeter being modified by processOptions() +- b2253cc: Prevent option paremeter being modified by processOptions() ## 8.1.2 ### Patch Changes -- a83971e: Allows button message amount type to be string +- a83971e: Allows button message amount type to be string ## 8.1.1 ### Patch Changes -- d36e386: add the shape: "sharp" in style -- 638e8e6: remove .nvmrc and lint-staged.config.js in react-paypal-js -- 638e8e6: remove the prettier dependency from each packages, update the prettier root version, fixed build error, update note version to 18 -- 543fa08: Add button style borderRadius type -- 22f23ab: Split up each props into its own type to export +- d36e386: add the shape: "sharp" in style +- 638e8e6: remove .nvmrc and lint-staged.config.js in react-paypal-js +- 638e8e6: remove the prettier dependency from each packages, update the prettier root version, fixed build error, update note version to 18 +- 543fa08: Add button style borderRadius type +- 22f23ab: Split up each props into its own type to export ## 8.1.0 ### Minor Changes -- c0badf3: Support env param in loadScript options object +- c0badf3: Support env param in loadScript options object ### Patch Changes -- 5adf3b6: updates PayPalButtonComponentOptions to add message +- 5adf3b6: updates PayPalButtonComponentOptions to add message ## 8.0.5 ### Patch Changes -- 81faf35: Exported the card field types. They were previously defined but not exported. -- b3da231: Adjust card-field types. -- a33a65f: Updated the type for the card fields onApprove parameter. +- 81faf35: Exported the card field types. They were previously defined but not exported. +- b3da231: Adjust card-field types. +- a33a65f: Updated the type for the card fields onApprove parameter. ## 8.0.4 ### Patch Changes -- 076881a: Add dataJsSdkLibrary to PayPalScriptDataAttributes +- 076881a: Add dataJsSdkLibrary to PayPalScriptDataAttributes ## 8.0.3 ### Patch Changes -- 99822f5: Set default data-js-sdk-library value +- 99822f5: Set default data-js-sdk-library value ## 8.0.2 ### Patch Changes -- a59d626: Ensure publish config is set to public +- a59d626: Ensure publish config is set to public ## 8.0.1 ### Patch Changes -- 082bd2f: move to monorepo +- 082bd2f: move to monorepo NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. Starting from 8.0.1, changesets is being used to generate changelog @@ -131,86 +131,86 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### ⚠ BREAKING CHANGES -- **types:** The TypeScript types for the PayPal APIs have changed. - Now they are auto generated based on the Open API 3.0 specs. +- **types:** The TypeScript types for the PayPal APIs have changed. + Now they are auto generated based on the Open API 3.0 specs. ### Features -- **types:** auto generate api types with openapi specs ([#443](https://github.com/paypal/paypal-js/issues/443)) ([efb26f8](https://github.com/paypal/paypal-js/commit/efb26f867da604a4ca043c070e51caa460cb5a26)) +- **types:** auto generate api types with openapi specs ([#443](https://github.com/paypal/paypal-js/issues/443)) ([efb26f8](https://github.com/paypal/paypal-js/commit/efb26f867da604a4ca043c070e51caa460cb5a26)) ### Bug Fixes -- use bundler module resoluion ts strategy ([3bceb9e](https://github.com/paypal/paypal-js/commit/3bceb9e692a1fbc7c53bbcab86b6e042abcbded1)) +- use bundler module resoluion ts strategy ([3bceb9e](https://github.com/paypal/paypal-js/commit/3bceb9e692a1fbc7c53bbcab86b6e042abcbded1)) ### [7.1.1](https://github.com/paypal/paypal-js/compare/v7.1.0...v7.1.1) (2023-11-27) ### Bug Fixes -- **types:** add type definition for createVaultSetupToken ([#439](https://github.com/paypal/paypal-js/issues/439)) ([a5e9424](https://github.com/paypal/paypal-js/commit/a5e94245d98e1e052484443be002df7ef4b121e0)) +- **types:** add type definition for createVaultSetupToken ([#439](https://github.com/paypal/paypal-js/issues/439)) ([a5e9424](https://github.com/paypal/paypal-js/commit/a5e94245d98e1e052484443be002df7ef4b121e0)) ## [7.1.0](https://github.com/paypal/paypal-js/compare/v7.0.3...v7.1.0) (2023-11-13) ### Features -- add support for crossorigin attribute ([#435](https://github.com/paypal/paypal-js/issues/435)) ([d504cc7](https://github.com/paypal/paypal-js/commit/d504cc755b497616aff455d0c376378cda3ae3e8)) +- add support for crossorigin attribute ([#435](https://github.com/paypal/paypal-js/issues/435)) ([d504cc7](https://github.com/paypal/paypal-js/commit/d504cc755b497616aff455d0c376378cda3ae3e8)) ### Bug Fixes -- **types:** add displayOnly option for Buttons ([#431](https://github.com/paypal/paypal-js/issues/431)) ([1acba3f](https://github.com/paypal/paypal-js/commit/1acba3f869ed14cd867d3ea33e6657df3d2b820f)) +- **types:** add displayOnly option for Buttons ([#431](https://github.com/paypal/paypal-js/issues/431)) ([1acba3f](https://github.com/paypal/paypal-js/commit/1acba3f869ed14cd867d3ea33e6657df3d2b820f)) ### [7.0.3](https://github.com/paypal/paypal-js/compare/v7.0.2...v7.0.3) (2023-09-19) ### Bug Fixes -- **types:** add new disableMaxWidth style option ([#423](https://github.com/paypal/paypal-js/issues/423)) ([aa10eff](https://github.com/paypal/paypal-js/commit/aa10eff7be5b7cad8d3bd0b446ceec29fcfd736a)) -- **types:** add types for new shipping callbacks ([#427](https://github.com/paypal/paypal-js/issues/427)) ([0602040](https://github.com/paypal/paypal-js/commit/060204076aa2387c98fd544e69e76b1dc884e70f)) +- **types:** add new disableMaxWidth style option ([#423](https://github.com/paypal/paypal-js/issues/423)) ([aa10eff](https://github.com/paypal/paypal-js/commit/aa10eff7be5b7cad8d3bd0b446ceec29fcfd736a)) +- **types:** add types for new shipping callbacks ([#427](https://github.com/paypal/paypal-js/issues/427)) ([0602040](https://github.com/paypal/paypal-js/commit/060204076aa2387c98fd544e69e76b1dc884e70f)) ### [7.0.2](https://github.com/paypal/paypal-js/compare/v7.0.1...v7.0.2) (2023-08-26) ### Bug Fixes -- **types:** query params as an array or string ([#420](https://github.com/paypal/paypal-js/issues/420)) ([f829bb8](https://github.com/paypal/paypal-js/commit/f829bb8a2a9cfda3b1abfd07ecb6a8170af5624b)) +- **types:** query params as an array or string ([#420](https://github.com/paypal/paypal-js/issues/420)) ([f829bb8](https://github.com/paypal/paypal-js/commit/f829bb8a2a9cfda3b1abfd07ecb6a8170af5624b)) ### [7.0.1](https://github.com/paypal/paypal-js/compare/v7.0.0...v7.0.1) (2023-08-26) ### Bug Fixes -- **tests:** update e2e test mock url ([#414](https://github.com/paypal/paypal-js/issues/414)) ([240e9fe](https://github.com/paypal/paypal-js/commit/240e9fef08f1599a61952160b29324293753e536)) -- **types:** update ScriptOptions to support array or string values ([380d04e](https://github.com/paypal/paypal-js/commit/380d04ecc5547f72e51df2c736d2a43856fc8bae)) +- **tests:** update e2e test mock url ([#414](https://github.com/paypal/paypal-js/issues/414)) ([240e9fe](https://github.com/paypal/paypal-js/commit/240e9fef08f1599a61952160b29324293753e536)) +- **types:** update ScriptOptions to support array or string values ([380d04e](https://github.com/paypal/paypal-js/commit/380d04ecc5547f72e51df2c736d2a43856fc8bae)) ## [7.0.0](https://github.com/paypal/paypal-js/compare/v6.0.1...v7.0.0) (2023-08-16) ### ⚠ BREAKING CHANGES -- The logic for fetching and parsing the plain text error - message for the JS SDK script is being removed. We replaced this - logic with a general error message recommending the developer - check the http response to learn why the JS SDK failed to load. +- The logic for fetching and parsing the plain text error + message for the JS SDK script is being removed. We replaced this + logic with a general error message recommending the developer + check the http response to learn why the JS SDK failed to load. ### Bug Fixes -- remove custom fetch error parsing ([#412](https://github.com/paypal/paypal-js/issues/412)) ([48b1820](https://github.com/paypal/paypal-js/commit/48b1820cb27172858dddb2d8d9bf3d2df1db6946)) +- remove custom fetch error parsing ([#412](https://github.com/paypal/paypal-js/issues/412)) ([48b1820](https://github.com/paypal/paypal-js/commit/48b1820cb27172858dddb2d8d9bf3d2df1db6946)) ### [6.0.1](https://github.com/paypal/paypal-js/compare/v6.0.0...v6.0.1) (2023-07-19) ### Bug Fixes -- **types:** add types for payment_source with order creation ([#402](https://github.com/paypal/paypal-js/issues/402)) ([f27b895](https://github.com/paypal/paypal-js/commit/f27b8955b0b6e77efd09dc1df17b67f45e97d243)) +- **types:** add types for payment_source with order creation ([#402](https://github.com/paypal/paypal-js/issues/402)) ([f27b895](https://github.com/paypal/paypal-js/commit/f27b8955b0b6e77efd09dc1df17b67f45e97d243)) ## [6.0.0](https://github.com/paypal/paypal-js/compare/v5.1.6...v6.0.0) (2023-06-02) ### ⚠ BREAKING CHANGES -- this is a breaking change for the TypeScript types. +- this is a breaking change for the TypeScript types. ### Features -- camelCase instead of kebab-case for params ([#375](https://github.com/paypal/paypal-js/issues/375)) ([f73df41](https://github.com/paypal/paypal-js/commit/f73df412c8a1ef65d3b3db132e50e79566a341fe)) +- camelCase instead of kebab-case for params ([#375](https://github.com/paypal/paypal-js/issues/375)) ([f73df41](https://github.com/paypal/paypal-js/commit/f73df412c8a1ef65d3b3db132e50e79566a341fe)) ### Bug Fixes -- **types:** remove deprecated disable-card param ([#379](https://github.com/paypal/paypal-js/issues/379)) ([a4abfc2](https://github.com/paypal/paypal-js/commit/a4abfc246df9fee9525ea894e0501d626b555052)) -- **types:** update patch request body for order actions ([#360](https://github.com/paypal/paypal-js/issues/360)) ([6b45244](https://github.com/paypal/paypal-js/commit/6b45244f94564117b3ba66918b6d979faad43edf)) +- **types:** remove deprecated disable-card param ([#379](https://github.com/paypal/paypal-js/issues/379)) ([a4abfc2](https://github.com/paypal/paypal-js/commit/a4abfc246df9fee9525ea894e0501d626b555052)) +- **types:** update patch request body for order actions ([#360](https://github.com/paypal/paypal-js/issues/360)) ([6b45244](https://github.com/paypal/paypal-js/commit/6b45244f94564117b3ba66918b6d979faad43edf)) ### [5.1.6](https://github.com/paypal/paypal-js/compare/v5.1.5...v5.1.6) (2023-03-27) @@ -218,47 +218,47 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** add optional data-uid script attribute ([#346](https://github.com/paypal/paypal-js/issues/346)) ([c845035](https://github.com/paypal/paypal-js/commit/c845035dbc923b9da005aad1956869ce025a2686)) -- **types:** add type for minimal response from orders api ([#347](https://github.com/paypal/paypal-js/issues/347)) ([562a5fc](https://github.com/paypal/paypal-js/commit/562a5fc72302604d6bb26d0a36a5fba9bee6d520)) -- **types:** update response type for actions.order.patch() ([#333](https://github.com/paypal/paypal-js/issues/333)) ([7eebb58](https://github.com/paypal/paypal-js/commit/7eebb586a775e07618d4f9df87012b1c691e4eef)) -- update load-script.js ([a195e79](https://github.com/paypal/paypal-js/commit/a195e79278f65fada5a8fb7c4ff4aa19ab5a63b4)) +- **types:** add optional data-uid script attribute ([#346](https://github.com/paypal/paypal-js/issues/346)) ([c845035](https://github.com/paypal/paypal-js/commit/c845035dbc923b9da005aad1956869ce025a2686)) +- **types:** add type for minimal response from orders api ([#347](https://github.com/paypal/paypal-js/issues/347)) ([562a5fc](https://github.com/paypal/paypal-js/commit/562a5fc72302604d6bb26d0a36a5fba9bee6d520)) +- **types:** update response type for actions.order.patch() ([#333](https://github.com/paypal/paypal-js/issues/333)) ([7eebb58](https://github.com/paypal/paypal-js/commit/7eebb586a775e07618d4f9df87012b1c691e4eef)) +- update load-script.js ([a195e79](https://github.com/paypal/paypal-js/commit/a195e79278f65fada5a8fb7c4ff4aa19ab5a63b4)) ### [5.1.4](https://github.com/paypal/paypal-js/compare/v5.1.3...v5.1.4) (2022-11-29) ### Bug Fixes -- **types:** fix type for hosted fields getState function ([#320](https://github.com/paypal/paypal-js/issues/320)) ([1ec2691](https://github.com/paypal/paypal-js/commit/1ec26918dec4a5549f72c33b09382122fef5f9b5)) +- **types:** fix type for hosted fields getState function ([#320](https://github.com/paypal/paypal-js/issues/320)) ([1ec2691](https://github.com/paypal/paypal-js/commit/1ec26918dec4a5549f72c33b09382122fef5f9b5)) ### [5.1.3](https://github.com/paypal/paypal-js/compare/v5.1.2...v5.1.3) (2022-11-29) ### Bug Fixes -- **types:** add missing action for revising a subscription ([#318](https://github.com/paypal/paypal-js/issues/318)) ([48e720e](https://github.com/paypal/paypal-js/commit/48e720e10be9cb77b83a35f85de376e78fccdb89)) +- **types:** add missing action for revising a subscription ([#318](https://github.com/paypal/paypal-js/issues/318)) ([48e720e](https://github.com/paypal/paypal-js/commit/48e720e10be9cb77b83a35f85de376e78fccdb89)) ### [5.1.2](https://github.com/paypal/paypal-js/compare/v5.1.1...v5.1.2) (2022-11-11) ### Bug Fixes -- **types:** add missing on and off events for hostedFields ([#299](https://github.com/paypal/paypal-js/issues/299)) ([216356e](https://github.com/paypal/paypal-js/commit/216356e5ab1337dc14346170ee7a7589e549f5d3)) +- **types:** add missing on and off events for hostedFields ([#299](https://github.com/paypal/paypal-js/issues/299)) ([216356e](https://github.com/paypal/paypal-js/commit/216356e5ab1337dc14346170ee7a7589e549f5d3)) ### [5.1.1](https://github.com/paypal/paypal-js/compare/v5.1.0...v5.1.1) (2022-08-03) ### Bug Fixes -- **types:** add missing types for messaging component ([#274](https://github.com/paypal/paypal-js/issues/274)) ([dd6bc48](https://github.com/paypal/paypal-js/commit/dd6bc48d0755efcd5ad529e92322cd1ec051d84c)) -- **types:** update order shipping options to match spec ([#276](https://github.com/paypal/paypal-js/issues/276)) ([e23c7d2](https://github.com/paypal/paypal-js/commit/e23c7d2c48a677ad64de97e9de2b1e954e06c192)) +- **types:** add missing types for messaging component ([#274](https://github.com/paypal/paypal-js/issues/274)) ([dd6bc48](https://github.com/paypal/paypal-js/commit/dd6bc48d0755efcd5ad529e92322cd1ec051d84c)) +- **types:** update order shipping options to match spec ([#276](https://github.com/paypal/paypal-js/issues/276)) ([e23c7d2](https://github.com/paypal/paypal-js/commit/e23c7d2c48a677ad64de97e9de2b1e954e06c192)) ## [5.1.0](https://github.com/paypal/paypal-js/compare/v5.0.6...v5.1.0) (2022-06-30) ### Features -- **types:** add types for funding source options ([#258](https://github.com/paypal/paypal-js/issues/258)) ([65ebaab](https://github.com/paypal/paypal-js/commit/65ebaabfd5bddeb2178976b183f419ad5552c892)) +- **types:** add types for funding source options ([#258](https://github.com/paypal/paypal-js/issues/258)) ([65ebaab](https://github.com/paypal/paypal-js/commit/65ebaabfd5bddeb2178976b183f419ad5552c892)) ### [5.0.6](https://github.com/paypal/paypal-js/compare/v5.0.5...v5.0.6) (2022-05-17) ### Bug Fixes -- **types:** add types for installments for HostedFields ([#239](https://github.com/paypal/paypal-js/issues/239)) ([3b89277](https://github.com/paypal/paypal-js/commit/3b892779d169851fcf2037b23473b0e853ec9049)) +- **types:** add types for installments for HostedFields ([#239](https://github.com/paypal/paypal-js/issues/239)) ([3b89277](https://github.com/paypal/paypal-js/commit/3b892779d169851fcf2037b23473b0e853ec9049)) ### [5.0.5](https://github.com/paypal/paypal-js/compare/v5.0.4...v5.0.5) (2022-04-21) @@ -266,7 +266,7 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** add missing types for orders ([#217](https://github.com/paypal/paypal-js/issues/217)) ([8393506](https://github.com/paypal/paypal-js/commit/83935066164598da653ab24706bc65ff533ef977)) +- **types:** add missing types for orders ([#217](https://github.com/paypal/paypal-js/issues/217)) ([8393506](https://github.com/paypal/paypal-js/commit/83935066164598da653ab24706bc65ff533ef977)) ### [5.0.3](https://github.com/paypal/paypal-js/compare/v5.0.2...v5.0.3) (2022-03-25) @@ -274,57 +274,57 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** add missing style props for messages ([#167](https://github.com/paypal/paypal-js/issues/167)) ([e969f9a](https://github.com/paypal/paypal-js/commit/e969f9a65269a97645adc0dab685257f7f38ce96)) +- **types:** add missing style props for messages ([#167](https://github.com/paypal/paypal-js/issues/167)) ([e969f9a](https://github.com/paypal/paypal-js/commit/e969f9a65269a97645adc0dab685257f7f38ce96)) ### [5.0.1](https://github.com/paypal/paypal-js/compare/v5.0.0...v5.0.1) (2022-01-11) ### Bug Fixes -- **types:** export type PayPalScriptOptions ([#147](https://github.com/paypal/paypal-js/issues/147)) ([8d36446](https://github.com/paypal/paypal-js/commit/8d36446cd3aee468511869a75b6503bc6d16846d)) +- **types:** export type PayPalScriptOptions ([#147](https://github.com/paypal/paypal-js/issues/147)) ([8d36446](https://github.com/paypal/paypal-js/commit/8d36446cd3aee468511869a75b6503bc6d16846d)) ## [5.0.0](https://github.com/paypal/paypal-js/compare/v4.2.2...v5.0.0) (2022-01-10) ### ⚠ BREAKING CHANGES -- **types:** update `OnApproveActions` to support subscriptions (#140) +- **types:** update `OnApproveActions` to support subscriptions (#140) ### Features -- **types:** export all types ([#143](https://github.com/paypal/paypal-js/issues/143)) ([0542336](https://github.com/paypal/paypal-js/commit/054233643fcaa5628530d40ed04303be804cc7c9)) -- **types:** remove deprecated order type ([#145](https://github.com/paypal/paypal-js/issues/145)) ([355ebaa](https://github.com/paypal/paypal-js/commit/355ebaac31c762cea2736f06daebf50d5233242a)) +- **types:** export all types ([#143](https://github.com/paypal/paypal-js/issues/143)) ([0542336](https://github.com/paypal/paypal-js/commit/054233643fcaa5628530d40ed04303be804cc7c9)) +- **types:** remove deprecated order type ([#145](https://github.com/paypal/paypal-js/issues/145)) ([355ebaa](https://github.com/paypal/paypal-js/commit/355ebaac31c762cea2736f06daebf50d5233242a)) ### Bug Fixes -- **types:** update `OnApproveActions` to support subscriptions ([#140](https://github.com/paypal/paypal-js/issues/140)) ([3bdaaa2](https://github.com/paypal/paypal-js/commit/3bdaaa2cb8baaa7a1c677c9bac231950b311016d)) +- **types:** update `OnApproveActions` to support subscriptions ([#140](https://github.com/paypal/paypal-js/issues/140)) ([3bdaaa2](https://github.com/paypal/paypal-js/commit/3bdaaa2cb8baaa7a1c677c9bac231950b311016d)) ### [4.2.2](https://github.com/paypal/paypal-js/compare/v4.2.1...v4.2.2) (2021-12-17) ### Bug Fixes -- **types:** add additional sdk attributes ([48abf67](https://github.com/paypal/paypal-js/commit/48abf672dd7ad6759d46116ee315da8735450e82)) -- **types:** remove unused CreateOrderActions type for hostedFields ([#137](https://github.com/paypal/paypal-js/issues/137)) ([63b675c](https://github.com/paypal/paypal-js/commit/63b675c1da2017974f097f5bf2da077dbf6ff49a)) +- **types:** add additional sdk attributes ([48abf67](https://github.com/paypal/paypal-js/commit/48abf672dd7ad6759d46116ee315da8735450e82)) +- **types:** remove unused CreateOrderActions type for hostedFields ([#137](https://github.com/paypal/paypal-js/issues/137)) ([63b675c](https://github.com/paypal/paypal-js/commit/63b675c1da2017974f097f5bf2da077dbf6ff49a)) ### [4.2.1](https://github.com/paypal/paypal-js/compare/v4.2.0...v4.2.1) (2021-11-24) ### Bug Fixes -- add types for onShippingChange callback ([#135](https://github.com/paypal/paypal-js/issues/135)) ([65c5302](https://github.com/paypal/paypal-js/commit/65c5302276925a920ae2bec19aa7aebef8d0aaae)) +- add types for onShippingChange callback ([#135](https://github.com/paypal/paypal-js/issues/135)) ([65c5302](https://github.com/paypal/paypal-js/commit/65c5302276925a920ae2bec19aa7aebef8d0aaae)) ## [4.2.0](https://github.com/paypal/paypal-js/compare/v4.1.0...v4.2.0) (2021-11-17) ### Features -- useful error message for failed script loads ([#128](https://github.com/paypal/paypal-js/issues/128)) ([a64945b](https://github.com/paypal/paypal-js/commit/a64945b58595b450045726e304a252881b149379)) +- useful error message for failed script loads ([#128](https://github.com/paypal/paypal-js/issues/128)) ([a64945b](https://github.com/paypal/paypal-js/commit/a64945b58595b450045726e304a252881b149379)) ### Bug Fixes -- **ie11:** remove usage on Object.assign ([76509ca](https://github.com/paypal/paypal-js/commit/76509ca0c4166c93428444b746aaf8f4bfd15dae)) +- **ie11:** remove usage on Object.assign ([76509ca](https://github.com/paypal/paypal-js/commit/76509ca0c4166c93428444b746aaf8f4bfd15dae)) ## [4.1.0](https://github.com/paypal/paypal-js/compare/v4.0.12...v4.1.0) (2021-10-06) ### Features -- **types:** enhance the hostedFields type ([#124](https://github.com/paypal/paypal-js/issues/124)) ([9f3a025](https://github.com/paypal/paypal-js/commit/9f3a025edde9eeb35c88e7859d2c7f6836baccd1)) +- **types:** enhance the hostedFields type ([#124](https://github.com/paypal/paypal-js/issues/124)) ([9f3a025](https://github.com/paypal/paypal-js/commit/9f3a025edde9eeb35c88e7859d2c7f6836baccd1)) ### [4.0.12](https://github.com/paypal/paypal-js/compare/v4.0.11...v4.0.12) (2021-09-29) @@ -332,7 +332,7 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** update submit response for hosted fields ([#117](https://github.com/paypal/paypal-js/issues/117)) ([31ac8b4](https://github.com/paypal/paypal-js/commit/31ac8b4bfa526f7b06dd9ec7fbb9f2b42b94c62c)) +- **types:** update submit response for hosted fields ([#117](https://github.com/paypal/paypal-js/issues/117)) ([31ac8b4](https://github.com/paypal/paypal-js/commit/31ac8b4bfa526f7b06dd9ec7fbb9f2b42b94c62c)) ### [4.0.10](https://github.com/paypal/paypal-js/compare/v4.0.9...v4.0.10) (2021-09-04) @@ -340,21 +340,21 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** remove unsupported data-order-id attribute ([3ddc963](https://github.com/paypal/paypal-js/commit/3ddc9637c2a8a65247dd06bb135c355cddc9633a)) -- **types:** update createOrder for HostedFields ([#116](https://github.com/paypal/paypal-js/issues/116)) ([62fb2b1](https://github.com/paypal/paypal-js/commit/62fb2b1f9d024b96225195dd6b1332be8a3ef0b6)) +- **types:** remove unsupported data-order-id attribute ([3ddc963](https://github.com/paypal/paypal-js/commit/3ddc9637c2a8a65247dd06bb135c355cddc9633a)) +- **types:** update createOrder for HostedFields ([#116](https://github.com/paypal/paypal-js/issues/116)) ([62fb2b1](https://github.com/paypal/paypal-js/commit/62fb2b1f9d024b96225195dd6b1332be8a3ef0b6)) ### [4.0.8](https://github.com/paypal/paypal-js/compare/v4.0.7...v4.0.8) (2021-08-20) ### Bug Fixes -- **types:** move restart() and redirect() onApprove actions ([#113](https://github.com/paypal/paypal-js/issues/113)) ([51bb788](https://github.com/paypal/paypal-js/commit/51bb788722f566647973b7d7abe7a8f82d4e225b)) +- **types:** move restart() and redirect() onApprove actions ([#113](https://github.com/paypal/paypal-js/issues/113)) ([51bb788](https://github.com/paypal/paypal-js/commit/51bb788722f566647973b7d7abe7a8f82d4e225b)) ### [4.0.7](https://github.com/paypal/paypal-js/compare/v4.0.6...v4.0.7) (2021-08-11) ### Bug Fixes -- **types:** add sdk-integration-source script attribute ([d8b0c09](https://github.com/paypal/paypal-js/commit/d8b0c09872d3eb6dfafba3149a56e83e66df0c6f)) -- **types:** support authorizing payments ([b24b5fb](https://github.com/paypal/paypal-js/commit/b24b5fbc157ad9ebf9a7406ff696b4c9f61a4ff0)) +- **types:** add sdk-integration-source script attribute ([d8b0c09](https://github.com/paypal/paypal-js/commit/d8b0c09872d3eb6dfafba3149a56e83e66df0c6f)) +- **types:** support authorizing payments ([b24b5fb](https://github.com/paypal/paypal-js/commit/b24b5fbc157ad9ebf9a7406ff696b4c9f61a4ff0)) ### [4.0.6](https://github.com/paypal/paypal-js/compare/v4.0.5...v4.0.6) (2021-07-09) @@ -366,31 +366,31 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** add new category for donation ([3241f46](https://github.com/paypal/paypal-js/commit/3241f4670a0ae3d9748c3413d9c08ecd9983769b)) -- **types:** add support for donations ([b4eb180](https://github.com/paypal/paypal-js/commit/b4eb180446f4423ec293efdd42ee9977b96414d4)) -- **types:** update sku and category to be optional ([0e0b129](https://github.com/paypal/paypal-js/commit/0e0b129a3ddb4e998626b840bc8faad41daa11dc)) +- **types:** add new category for donation ([3241f46](https://github.com/paypal/paypal-js/commit/3241f4670a0ae3d9748c3413d9c08ecd9983769b)) +- **types:** add support for donations ([b4eb180](https://github.com/paypal/paypal-js/commit/b4eb180446f4423ec293efdd42ee9977b96414d4)) +- **types:** update sku and category to be optional ([0e0b129](https://github.com/paypal/paypal-js/commit/0e0b129a3ddb4e998626b840bc8faad41daa11dc)) ### [4.0.2](https://github.com/paypal/paypal-js/compare/v4.0.1...v4.0.2) (2021-07-05) ### Bug Fixes -- **types:** add labels 'subscribe' and 'donate' ([8550a0a](https://github.com/paypal/paypal-js/commit/8550a0a162834876f3173192943810dc08145b04)) +- **types:** add labels 'subscribe' and 'donate' ([8550a0a](https://github.com/paypal/paypal-js/commit/8550a0a162834876f3173192943810dc08145b04)) ### [4.0.1](https://github.com/paypal/paypal-js/compare/v4.0.0...v4.0.1) (2021-06-26) ### Bug Fixes -- **types:** add type for authorize() ([#96](https://github.com/paypal/paypal-js/issues/96)) ([b30bf77](https://github.com/paypal/paypal-js/commit/b30bf77835743db707177e396158454b61212723)) +- **types:** add type for authorize() ([#96](https://github.com/paypal/paypal-js/issues/96)) ([b30bf77](https://github.com/paypal/paypal-js/commit/b30bf77835743db707177e396158454b61212723)) ## [4.0.0](https://github.com/paypal/paypal-js/compare/v3.1.11...v4.0.0) (2021-06-04) ### ⚠ BREAKING CHANGES -- new urls for the dist files hosted on unpkg.com +- new urls for the dist files hosted on unpkg.com ### Features -- improve dist folder structure ([16053a0](https://github.com/paypal/paypal-js/commit/16053a0d559ca056ec89a05346edf0d705820fef)) +- improve dist folder structure ([16053a0](https://github.com/paypal/paypal-js/commit/16053a0d559ca056ec89a05346edf0d705820fef)) ### [3.1.11](https://github.com/paypal/paypal-js/compare/v3.1.10...v3.1.11) (2021-06-03) @@ -398,7 +398,7 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- **types:** export all api types ([966091a](https://github.com/paypal/paypal-js/commit/966091a24579b6436b4d9ebc3b8bd04f01c09d1e)) +- **types:** export all api types ([966091a](https://github.com/paypal/paypal-js/commit/966091a24579b6436b4d9ebc3b8bd04f01c09d1e)) ### [3.1.9](https://github.com/paypal/paypal-js/compare/v3.1.8...v3.1.9) (2021-04-27) @@ -406,44 +406,44 @@ NOTE: Previous to v8.0.0, `standard-version` was used for changelog generation. ### Bug Fixes -- override tsconfig target in legacy build ([#76](https://github.com/paypal/paypal-js/issues/76)) ([3228e57](https://github.com/paypal/paypal-js/commit/3228e578d2fcc7659f59773d37569ed56a0ef289)) +- override tsconfig target in legacy build ([#76](https://github.com/paypal/paypal-js/issues/76)) ([3228e57](https://github.com/paypal/paypal-js/commit/3228e578d2fcc7659f59773d37569ed56a0ef289)) ### [3.1.7](https://github.com/paypal/paypal-js/compare/v3.1.6...v3.1.7) (2021-04-10) ### Bug Fixes -- **types:** add types for hosted-fields component ([#72](https://github.com/paypal/paypal-js/issues/72)) ([fd8652a](https://github.com/paypal/paypal-js/commit/fd8652a5bc192f3694c32ad734d42bf03c170098)) -- **types:** rename 'props' to 'options' ([a01c86e](https://github.com/paypal/paypal-js/commit/a01c86ee372f71c099f11e5a7c0d2d283b0d9db6)) +- **types:** add types for hosted-fields component ([#72](https://github.com/paypal/paypal-js/issues/72)) ([fd8652a](https://github.com/paypal/paypal-js/commit/fd8652a5bc192f3694c32ad734d42bf03c170098)) +- **types:** rename 'props' to 'options' ([a01c86e](https://github.com/paypal/paypal-js/commit/a01c86ee372f71c099f11e5a7c0d2d283b0d9db6)) ### [3.1.6](https://github.com/paypal/paypal-js/compare/v3.1.5...v3.1.6) (2021-04-02) ### Bug Fixes -- **types:** add types for funding-eligibility ([b78de97](https://github.com/paypal/paypal-js/commit/b78de970170c7f86d51524e97bee9edcd41bf2a8)) +- **types:** add types for funding-eligibility ([b78de97](https://github.com/paypal/paypal-js/commit/b78de970170c7f86d51524e97bee9edcd41bf2a8)) ### [3.1.5](https://github.com/paypal/paypal-js/compare/v3.1.4...v3.1.5) (2021-03-29) ### Bug Fixes -- **types:** add types for onApprove callback data ([9d98fd9](https://github.com/paypal/paypal-js/commit/9d98fd9a99cf7a469ab609d0f3970069b6e385c3)) -- **types:** update OrderApplicationContext fields to be optional ([#69](https://github.com/paypal/paypal-js/issues/69)) ([9a43f7f](https://github.com/paypal/paypal-js/commit/9a43f7f3fb903e50600ce35ced388dc91cdfeac7)) +- **types:** add types for onApprove callback data ([9d98fd9](https://github.com/paypal/paypal-js/commit/9d98fd9a99cf7a469ab609d0f3970069b6e385c3)) +- **types:** update OrderApplicationContext fields to be optional ([#69](https://github.com/paypal/paypal-js/issues/69)) ([9a43f7f](https://github.com/paypal/paypal-js/commit/9a43f7f3fb903e50600ce35ced388dc91cdfeac7)) ### [3.1.4](https://github.com/paypal/paypal-js/compare/v3.1.3...v3.1.4) (2021-03-22) ### Bug Fixes -- do not mutate the options object ([28b5984](https://github.com/paypal/paypal-js/commit/28b5984bc2d2d7c4b001f66118b9354a2c3f3df5)) +- do not mutate the options object ([28b5984](https://github.com/paypal/paypal-js/commit/28b5984bc2d2d7c4b001f66118b9354a2c3f3df5)) ### [3.1.3](https://github.com/paypal/paypal-js/compare/v3.1.2...v3.1.3) (2021-03-21) ### Bug Fixes -- **types:** button action functions return promises ([aeac03f](https://github.com/paypal/paypal-js/commit/aeac03f418b576fe2fce960e01ac33e9d21de067)) +- **types:** button action functions return promises ([aeac03f](https://github.com/paypal/paypal-js/commit/aeac03f418b576fe2fce960e01ac33e9d21de067)) ### [3.1.2](https://github.com/paypal/paypal-js/compare/v3.1.1...v3.1.2) (2021-03-19) ### Bug Fixes -- ignore data-uid-auto attribute in findScript ([99a7c8a](https://github.com/paypal/paypal-js/commit/99a7c8a8c2a7b6a4cb46be6539b1bf395b208ebf)) +- ignore data-uid-auto attribute in findScript ([99a7c8a](https://github.com/paypal/paypal-js/commit/99a7c8a8c2a7b6a4cb46be6539b1bf395b208ebf)) ### [3.1.1](https://github.com/paypal/paypal-js/compare/v3.1.0...v3.1.1) (2021-03-14) diff --git a/packages/paypal-js/src/utils.ts b/packages/paypal-js/src/utils.ts index efc98009..d987259f 100644 --- a/packages/paypal-js/src/utils.ts +++ b/packages/paypal-js/src/utils.ts @@ -158,3 +158,7 @@ function createScriptElement( return newScript; } + +export function isServer(): boolean { + return typeof window === "undefined" && typeof document === "undefined"; +} diff --git a/packages/paypal-js/src/v6/index.ts b/packages/paypal-js/src/v6/index.ts index 50c934e9..c3f8d3b9 100644 --- a/packages/paypal-js/src/v6/index.ts +++ b/packages/paypal-js/src/v6/index.ts @@ -1,4 +1,4 @@ -import { insertScriptElement } from "../utils"; +import { insertScriptElement, isServer } from "../utils"; import type { PayPalV6Namespace, LoadCoreSdkScriptOptions, @@ -8,6 +8,16 @@ const version = "__VERSION__"; function loadCoreSdkScript(options: LoadCoreSdkScriptOptions = {}) { validateArguments(options); + const isServerEnv = isServer(); + + // SSR safeguard - warn about incorrect usage + if (isServerEnv) { + console.warn( + "PayPal JS: loadCoreSdkScript() was called on the server. This function should only be called on the client side. Please ensure you're not calling this during server-side rendering.", + ); + return Promise.resolve(null); + } + const { environment, debug } = options; const baseURL = diff --git a/packages/paypal-js/types/v6/index.d.ts b/packages/paypal-js/types/v6/index.d.ts index f3fecef5..35ec4fb4 100644 --- a/packages/paypal-js/types/v6/index.d.ts +++ b/packages/paypal-js/types/v6/index.d.ts @@ -146,7 +146,7 @@ export type LoadCoreSdkScriptOptions = { export function loadCoreSdkScript( options: LoadCoreSdkScriptOptions, -): Promise; +): Promise; // Components export * from "./components/paypal-payments"; diff --git a/packages/react-paypal-js/CHANGELOG.md b/packages/react-paypal-js/CHANGELOG.md index 4a0f0b3a..e88ee118 100644 --- a/packages/react-paypal-js/CHANGELOG.md +++ b/packages/react-paypal-js/CHANGELOG.md @@ -4,33 +4,33 @@ ### Patch Changes -- b41126f: (fix) Proxy props added to Card Fields to prevent stale closure -- 0575877: Upgrade to package-lock v3 and fix rollup dependency -- Updated dependencies [6c83cf1] -- Updated dependencies [0575877] -- Updated dependencies [9b6eecc] - - @paypal/paypal-js@9.0.0 +- b41126f: (fix) Proxy props added to Card Fields to prevent stale closure +- 0575877: Upgrade to package-lock v3 and fix rollup dependency +- Updated dependencies [6c83cf1] +- Updated dependencies [0575877] +- Updated dependencies [9b6eecc] + - @paypal/paypal-js@9.0.0 ## 8.9.1 ### Patch Changes -- 67c5a2a: fix style types on CardField react component -- Updated dependencies [d3851e4] -- Updated dependencies [4d51a9a] - - @paypal/paypal-js@8.4.0 +- 67c5a2a: fix style types on CardField react component +- Updated dependencies [d3851e4] +- Updated dependencies [4d51a9a] + - @paypal/paypal-js@8.4.0 ## 8.9.0 ### Minor Changes -- eda47cb: Update card fields import paths and fix readme +- eda47cb: Update card fields import paths and fix readme ## 8.8.3 ### Patch Changes -- ebcfbaa: WHAT: Temporary fix for Braintree SDK versioning in React JS SDK. BT SDK version has been upgraded to latest version statically in the React SDK. +- ebcfbaa: WHAT: Temporary fix for Braintree SDK versioning in React JS SDK. BT SDK version has been upgraded to latest version statically in the React SDK. WHY: The BT SDK version is statically typed to an old version in our React SDK. As a short-term fix, we need to upgrade this version to the latest statically. @@ -38,60 +38,60 @@ ### Patch Changes -- 0176463: added missing style fields to CardField Types +- 0176463: added missing style fields to CardField Types ## 8.8.1 ### Patch Changes -- 10775ad: minor fixes to release and adding react 19 as peer dependency +- 10775ad: minor fixes to release and adding react 19 as peer dependency ## 8.8.0 ### Minor Changes -- 471280d: (fix) proxy props to prevent stale closure +- 471280d: (fix) proxy props to prevent stale closure ## 8.7.0 ### Minor Changes -- a83971e: Allows button message amount type to be string +- a83971e: Allows button message amount type to be string ### Patch Changes -- Updated dependencies [a83971e] - - @paypal/paypal-js@8.1.2 +- Updated dependencies [a83971e] + - @paypal/paypal-js@8.1.2 ## 8.6.0 ### Minor Changes -- dcd618c: Fixes Button rerendering unnecessarily when Buttons Message params change +- dcd618c: Fixes Button rerendering unnecessarily when Buttons Message params change ### Patch Changes -- 638e8e6: remove .nvmrc and lint-staged.config.js in react-paypal-js -- 638e8e6: remove the prettier dependency from each packages, update the prettier root version, fixed build error, update note version to 18 -- 543fa08: Add button style borderRadius type -- Updated dependencies [d36e386] -- Updated dependencies [638e8e6] -- Updated dependencies [638e8e6] -- Updated dependencies [543fa08] -- Updated dependencies [22f23ab] - - @paypal/paypal-js@8.1.1 +- 638e8e6: remove .nvmrc and lint-staged.config.js in react-paypal-js +- 638e8e6: remove the prettier dependency from each packages, update the prettier root version, fixed build error, update note version to 18 +- 543fa08: Add button style borderRadius type +- Updated dependencies [d36e386] +- Updated dependencies [638e8e6] +- Updated dependencies [638e8e6] +- Updated dependencies [543fa08] +- Updated dependencies [22f23ab] + - @paypal/paypal-js@8.1.1 ## 8.5.0 ### Minor Changes -- ecc9bc5: Add react-paypal-js to the paypal-js monorepo +- ecc9bc5: Add react-paypal-js to the paypal-js monorepo ### Patch Changes -- ecc9bc5: fixes button rerender issue due to obj in dependency array -- 12a76c9: set publish access to public -- cf50c1d: no-op change to re-trigger version packages pr +- ecc9bc5: fixes button rerender issue due to obj in dependency array +- 12a76c9: set publish access to public +- cf50c1d: no-op change to re-trigger version packages pr All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. @@ -99,49 +99,49 @@ All notable changes to this project will be documented in this file. See [standa ### Features -- updates PayPalButtons to add message option ([ee7cf02](https://github.com/paypal/react-paypal-js/commit/ee7cf029ad1d15d51aa38b2476f8c66bbcd511da)) -- updates PayPalButtons to add message option ([8213385](https://github.com/paypal/react-paypal-js/commit/8213385f64d814cf50ed233a2f8201fc2238b84a)) +- updates PayPalButtons to add message option ([ee7cf02](https://github.com/paypal/react-paypal-js/commit/ee7cf029ad1d15d51aa38b2476f8c66bbcd511da)) +- updates PayPalButtons to add message option ([8213385](https://github.com/paypal/react-paypal-js/commit/8213385f64d814cf50ed233a2f8201fc2238b84a)) ### Bug Fixes -- add individual story and cardfieldsprovider ([6c942c7](https://github.com/paypal/react-paypal-js/commit/6c942c75a58c8745236f261777c47ff1a1e97553)) -- prettier ([8fa2294](https://github.com/paypal/react-paypal-js/commit/8fa2294eb27cf958da44507a7c6a9218f006fbe3)) -- remove inputEvents and style for form component ([3306470](https://github.com/paypal/react-paypal-js/commit/3306470c3d1818a54bf74484bd58d883952636cb)) -- remove options from form component ([ffb7af8](https://github.com/paypal/react-paypal-js/commit/ffb7af8639c1f9452261499f1d0af456a5ec9e40)) -- skeleton for individual stories ([73676e6](https://github.com/paypal/react-paypal-js/commit/73676e6081d24e33485aad1268a7f6b45953bc4f)) -- typo correction in readme ([557f591](https://github.com/paypal/react-paypal-js/commit/557f591c6980f7ddf5eba38fe46c6b7bb713391f)) -- wip relative imports not working ([913dd15](https://github.com/paypal/react-paypal-js/commit/913dd153d73b6f17710cee20c9c17303cf4e5ebd)) +- add individual story and cardfieldsprovider ([6c942c7](https://github.com/paypal/react-paypal-js/commit/6c942c75a58c8745236f261777c47ff1a1e97553)) +- prettier ([8fa2294](https://github.com/paypal/react-paypal-js/commit/8fa2294eb27cf958da44507a7c6a9218f006fbe3)) +- remove inputEvents and style for form component ([3306470](https://github.com/paypal/react-paypal-js/commit/3306470c3d1818a54bf74484bd58d883952636cb)) +- remove options from form component ([ffb7af8](https://github.com/paypal/react-paypal-js/commit/ffb7af8639c1f9452261499f1d0af456a5ec9e40)) +- skeleton for individual stories ([73676e6](https://github.com/paypal/react-paypal-js/commit/73676e6081d24e33485aad1268a7f6b45953bc4f)) +- typo correction in readme ([557f591](https://github.com/paypal/react-paypal-js/commit/557f591c6980f7ddf5eba38fe46c6b7bb713391f)) +- wip relative imports not working ([913dd15](https://github.com/paypal/react-paypal-js/commit/913dd153d73b6f17710cee20c9c17303cf4e5ebd)) ## [8.3.0](https://github.com/paypal/react-paypal-js/compare/v8.2.0...v8.3.0) (2024-04-29) ### Features -- add cardfields form component ([634e6cd](https://github.com/paypal/react-paypal-js/commit/634e6cdfc4c3deb7d5b4cd903e196bf444bed9f4)) +- add cardfields form component ([634e6cd](https://github.com/paypal/react-paypal-js/commit/634e6cdfc4c3deb7d5b4cd903e196bf444bed9f4)) ### Bug Fixes -- prettier format ([3e03c3b](https://github.com/paypal/react-paypal-js/commit/3e03c3b7c34781ab98dbc624bac42f56c1b70cac)) -- rerender error fixed ([161fea6](https://github.com/paypal/react-paypal-js/commit/161fea66574f351eeb1b34f5d96b5f7014e0c72d)) +- prettier format ([3e03c3b](https://github.com/paypal/react-paypal-js/commit/3e03c3b7c34781ab98dbc624bac42f56c1b70cac)) +- rerender error fixed ([161fea6](https://github.com/paypal/react-paypal-js/commit/161fea66574f351eeb1b34f5d96b5f7014e0c72d)) ## [8.2.0](https://github.com/paypal/react-paypal-js/compare/v8.1.4...v8.2.0) (2024-03-20) ### Features -- add DATA_JS_SDK_LIBRARY to constants ([aa1b771](https://github.com/paypal/react-paypal-js/commit/aa1b771d85fa75083ad152f9d9b55d9c46ae051f)) -- add js library to options ([acc5123](https://github.com/paypal/react-paypal-js/commit/acc512371460da4b7d2f59ba10c69034f7ecef45)) -- hardcode js library ([95a29fa](https://github.com/paypal/react-paypal-js/commit/95a29fae3895042eca2b55f33a98a0d85ed97eae)) -- rename constant ([1d027b6](https://github.com/paypal/react-paypal-js/commit/1d027b6b93d23309a4d6966f998e320fcf7c94e5)) +- add DATA_JS_SDK_LIBRARY to constants ([aa1b771](https://github.com/paypal/react-paypal-js/commit/aa1b771d85fa75083ad152f9d9b55d9c46ae051f)) +- add js library to options ([acc5123](https://github.com/paypal/react-paypal-js/commit/acc512371460da4b7d2f59ba10c69034f7ecef45)) +- hardcode js library ([95a29fa](https://github.com/paypal/react-paypal-js/commit/95a29fae3895042eca2b55f33a98a0d85ed97eae)) +- rename constant ([1d027b6](https://github.com/paypal/react-paypal-js/commit/1d027b6b93d23309a4d6966f998e320fcf7c94e5)) ### Bug Fixes -- alphabetize constants ([0d9b495](https://github.com/paypal/react-paypal-js/commit/0d9b495a15e2fd8e923bc55237bb6ba0c69cd11e)) -- enforce values ([faa6278](https://github.com/paypal/react-paypal-js/commit/faa6278d1ad530658999c21be36f24fa1322d8e6)) +- alphabetize constants ([0d9b495](https://github.com/paypal/react-paypal-js/commit/0d9b495a15e2fd8e923bc55237bb6ba0c69cd11e)) +- enforce values ([faa6278](https://github.com/paypal/react-paypal-js/commit/faa6278d1ad530658999c21be36f24fa1322d8e6)) ### [8.1.4](https://github.com/paypal/react-paypal-js/compare/v8.1.3...v8.1.4) (2024-02-28) ### Bug Fixes -- failing typecheck ([#408](https://github.com/paypal/react-paypal-js/issues/408)) ([df8f63b](https://github.com/paypal/react-paypal-js/commit/df8f63b05585c51a7eef9d9296bdcb76e13fa4a8)) +- failing typecheck ([#408](https://github.com/paypal/react-paypal-js/issues/408)) ([df8f63b](https://github.com/paypal/react-paypal-js/commit/df8f63b05585c51a7eef9d9296bdcb76e13fa4a8)) ### [8.1.3](https://github.com/paypal/react-paypal-js/compare/v8.1.2...v8.1.3) (2023-08-16) @@ -149,7 +149,7 @@ All notable changes to this project will be documented in this file. See [standa ### Bug Fixes -- allow users to change data-sdk-integration-source ([#378](https://github.com/paypal/react-paypal-js/issues/378)) ([0feef3e](https://github.com/paypal/react-paypal-js/commit/0feef3e834fb2b9aaf23029855447715915bd1b2)) +- allow users to change data-sdk-integration-source ([#378](https://github.com/paypal/react-paypal-js/issues/378)) ([0feef3e](https://github.com/paypal/react-paypal-js/commit/0feef3e834fb2b9aaf23029855447715915bd1b2)) ### [8.1.1](https://github.com/paypal/react-paypal-js/compare/v8.1.0...v8.1.1) (2023-07-28) @@ -157,17 +157,17 @@ All notable changes to this project will be documented in this file. See [standa ### Features -- add loadingStatusErrorMessage to state ([#366](https://github.com/paypal/react-paypal-js/issues/366)) ([e1b9068](https://github.com/paypal/react-paypal-js/commit/e1b9068931c0fb832d884a0879d22deeca8304c2)) +- add loadingStatusErrorMessage to state ([#366](https://github.com/paypal/react-paypal-js/issues/366)) ([e1b9068](https://github.com/paypal/react-paypal-js/commit/e1b9068931c0fb832d884a0879d22deeca8304c2)) ## [8.0.0](https://github.com/paypal/react-paypal-js/compare/v7.8.3...v8.0.0) (2023-06-12) ### ⚠ BREAKING CHANGES -- this is a breaking change for PayPalScriptProvider options. +- this is a breaking change for PayPalScriptProvider options. ### Features -- use camelCase for PayPalScriptProvider options ([#360](https://github.com/paypal/react-paypal-js/issues/360)) ([168764e](https://github.com/paypal/react-paypal-js/commit/168764e4fb89be8717f256d4f9817bdf8e0a6eed)) +- use camelCase for PayPalScriptProvider options ([#360](https://github.com/paypal/react-paypal-js/issues/360)) ([168764e](https://github.com/paypal/react-paypal-js/commit/168764e4fb89be8717f256d4f9817bdf8e0a6eed)) ### [7.8.3](https://github.com/paypal/react-paypal-js/compare/v7.8.2...v7.8.3) (2023-03-27) @@ -179,117 +179,117 @@ All notable changes to this project will be documented in this file. See [standa ### Features -- **hostedFields:** add support for installments ([#271](https://github.com/paypal/react-paypal-js/issues/271)) ([c5e9670](https://github.com/paypal/react-paypal-js/commit/c5e967067517710765692c73c009d43ec60fb914)) +- **hostedFields:** add support for installments ([#271](https://github.com/paypal/react-paypal-js/issues/271)) ([c5e9670](https://github.com/paypal/react-paypal-js/commit/c5e967067517710765692c73c009d43ec60fb914)) ## [7.7.0](https://github.com/paypal/react-paypal-js/compare/v7.6.2...v7.7.0) (2022-05-10) ### Features -- **braintree:** add merchantAccountId prop ([#269](https://github.com/paypal/react-paypal-js/issues/269)) ([9ee701c](https://github.com/paypal/react-paypal-js/commit/9ee701caf3b2926e126a28d7a6a00c28912e7cf3)) +- **braintree:** add merchantAccountId prop ([#269](https://github.com/paypal/react-paypal-js/issues/269)) ([9ee701c](https://github.com/paypal/react-paypal-js/commit/9ee701caf3b2926e126a28d7a6a00c28912e7cf3)) ### [7.6.2](https://github.com/paypal/react-paypal-js/compare/v7.6.1...v7.6.2) (2022-05-09) ### Bug Fixes -- revert "fix(braintree): pass merchant-id through to session ([#265](https://github.com/paypal/react-paypal-js/issues/265))" ([#267](https://github.com/paypal/react-paypal-js/issues/267)) ([44b56b2](https://github.com/paypal/react-paypal-js/commit/44b56b2c9a799aad4108ba0fa0203bf86b359eb0)) +- revert "fix(braintree): pass merchant-id through to session ([#265](https://github.com/paypal/react-paypal-js/issues/265))" ([#267](https://github.com/paypal/react-paypal-js/issues/267)) ([44b56b2](https://github.com/paypal/react-paypal-js/commit/44b56b2c9a799aad4108ba0fa0203bf86b359eb0)) ### [7.6.1](https://github.com/paypal/react-paypal-js/compare/v7.6.0...v7.6.1) (2022-05-09) ### Bug Fixes -- **braintree:** pass merchant-id through to checkout session ([#265](https://github.com/paypal/react-paypal-js/issues/265)) ([1844fd5](https://github.com/paypal/react-paypal-js/commit/1844fd588c55de028656779e6ea3327f71b15d10)) +- **braintree:** pass merchant-id through to checkout session ([#265](https://github.com/paypal/react-paypal-js/issues/265)) ([1844fd5](https://github.com/paypal/react-paypal-js/commit/1844fd588c55de028656779e6ea3327f71b15d10)) ## [7.6.0](https://github.com/paypal/react-paypal-js/compare/v7.5.1...v7.6.0) (2022-02-01) ### Features -- **braintree:** add optional prop for braintree namespace ([#238](https://github.com/paypal/react-paypal-js/issues/238)) ([8deab76](https://github.com/paypal/react-paypal-js/commit/8deab76564181c5f2b1a08babf9d4316cae5720d)) -- **hostedFields:** support deeply nested children ([#240](https://github.com/paypal/react-paypal-js/issues/240)) ([f5fa95d](https://github.com/paypal/react-paypal-js/commit/f5fa95db3cfe1c8797e6f1eccb4c0abfb1355aaf)) +- **braintree:** add optional prop for braintree namespace ([#238](https://github.com/paypal/react-paypal-js/issues/238)) ([8deab76](https://github.com/paypal/react-paypal-js/commit/8deab76564181c5f2b1a08babf9d4316cae5720d)) +- **hostedFields:** support deeply nested children ([#240](https://github.com/paypal/react-paypal-js/issues/240)) ([f5fa95d](https://github.com/paypal/react-paypal-js/commit/f5fa95db3cfe1c8797e6f1eccb4c0abfb1355aaf)) ### [7.5.1](https://github.com/paypal/react-paypal-js/compare/v7.5.0...v7.5.1) (2022-01-14) ### Bug Fixes -- add type for Braintree billing agreement option ([#234](https://github.com/paypal/react-paypal-js/issues/234)) ([ddaced2](https://github.com/paypal/react-paypal-js/commit/ddaced241a6a243cbb51689619918ab93710233e)) -- **braintree:** support Braintree integrations using tokenization keys ([#216](https://github.com/paypal/react-paypal-js/issues/216)) ([3985a13](https://github.com/paypal/react-paypal-js/commit/3985a1309bb6c98f15584dc0ca33fe09c7207910)) +- add type for Braintree billing agreement option ([#234](https://github.com/paypal/react-paypal-js/issues/234)) ([ddaced2](https://github.com/paypal/react-paypal-js/commit/ddaced241a6a243cbb51689619918ab93710233e)) +- **braintree:** support Braintree integrations using tokenization keys ([#216](https://github.com/paypal/react-paypal-js/issues/216)) ([3985a13](https://github.com/paypal/react-paypal-js/commit/3985a1309bb6c98f15584dc0ca33fe09c7207910)) ## [7.5.0](https://github.com/paypal/react-paypal-js/compare/v7.4.2...v7.5.0) (2021-11-29) ### Features -- log loading errors for the JS SDK script ([#212](https://github.com/paypal/react-paypal-js/issues/212)) ([77973f0](https://github.com/paypal/react-paypal-js/commit/77973f0739e740ecbc4155cd79f733b9e2824484)) +- log loading errors for the JS SDK script ([#212](https://github.com/paypal/react-paypal-js/issues/212)) ([77973f0](https://github.com/paypal/react-paypal-js/commit/77973f0739e740ecbc4155cd79f733b9e2824484)) ### [7.4.2](https://github.com/paypal/react-paypal-js/compare/v7.4.1...v7.4.2) (2021-10-15) ### Bug Fixes -- add `createBillingAgreement` support for BraintreePayPalButtons ([#195](https://github.com/paypal/react-paypal-js/issues/195)) ([b4086ab](https://github.com/paypal/react-paypal-js/commit/b4086ab511565b1a904ceb241779c64f8adab36b)) +- add `createBillingAgreement` support for BraintreePayPalButtons ([#195](https://github.com/paypal/react-paypal-js/issues/195)) ([b4086ab](https://github.com/paypal/react-paypal-js/commit/b4086ab511565b1a904ceb241779c64f8adab36b)) ### [7.4.1](https://github.com/paypal/react-paypal-js/compare/v7.4.0...v7.4.1) (2021-10-09) ### Bug Fixes -- **types:** rename back to DISPATCH_ACTION ([#192](https://github.com/paypal/react-paypal-js/issues/192)) ([2b8f14a](https://github.com/paypal/react-paypal-js/commit/2b8f14ad41a6be3f461fe73b9661c92bd012df2a)) +- **types:** rename back to DISPATCH_ACTION ([#192](https://github.com/paypal/react-paypal-js/issues/192)) ([2b8f14a](https://github.com/paypal/react-paypal-js/commit/2b8f14ad41a6be3f461fe73b9661c92bd012df2a)) ## [7.4.0](https://github.com/paypal/react-paypal-js/compare/v7.3.3...v7.4.0) (2021-10-08) ### Features -- **hosted-fields:** add support for hosted-fields ([#160](https://github.com/paypal/react-paypal-js/issues/160)) ([e025d9a](https://github.com/paypal/react-paypal-js/commit/e025d9a1b45d43ad4b79e419188d59907b3cf1b8)) -- update Marks to support the children prop ([#155](https://github.com/paypal/react-paypal-js/issues/155)) ([6aebf98](https://github.com/paypal/react-paypal-js/commit/6aebf98b2592ed7ac68d6b232ab2fa4121dd114e)) +- **hosted-fields:** add support for hosted-fields ([#160](https://github.com/paypal/react-paypal-js/issues/160)) ([e025d9a](https://github.com/paypal/react-paypal-js/commit/e025d9a1b45d43ad4b79e419188d59907b3cf1b8)) +- update Marks to support the children prop ([#155](https://github.com/paypal/react-paypal-js/issues/155)) ([6aebf98](https://github.com/paypal/react-paypal-js/commit/6aebf98b2592ed7ac68d6b232ab2fa4121dd114e)) ### Bug Fixes -- **types:** standardize types for children ([#157](https://github.com/paypal/react-paypal-js/issues/157)) ([cc956be](https://github.com/paypal/react-paypal-js/commit/cc956beb1323a7516e30174b7d7fd20c9cd60e13)) -- update Marks to rerender when fundingSource changes ([#154](https://github.com/paypal/react-paypal-js/issues/154)) ([f7b4a25](https://github.com/paypal/react-paypal-js/commit/f7b4a251b01e7777948fda846fe0b55d348ec60a)) +- **types:** standardize types for children ([#157](https://github.com/paypal/react-paypal-js/issues/157)) ([cc956be](https://github.com/paypal/react-paypal-js/commit/cc956beb1323a7516e30174b7d7fd20c9cd60e13)) +- update Marks to rerender when fundingSource changes ([#154](https://github.com/paypal/react-paypal-js/issues/154)) ([f7b4a25](https://github.com/paypal/react-paypal-js/commit/f7b4a251b01e7777948fda846fe0b55d348ec60a)) ### [7.3.3](https://github.com/paypal/react-paypal-js/compare/v7.3.2...v7.3.3) (2021-08-31) ### Bug Fixes -- remove babel polyfill for typeof symbol ([d73fe72](https://github.com/paypal/react-paypal-js/commit/d73fe72e0bfa482226df8d38371dec969324583d)) -- update error handling logic for BraintreePayPalButtons ([1a1c73d](https://github.com/paypal/react-paypal-js/commit/1a1c73dfb15ff39452034d35a786938e5630aa5d)) +- remove babel polyfill for typeof symbol ([d73fe72](https://github.com/paypal/react-paypal-js/commit/d73fe72e0bfa482226df8d38371dec969324583d)) +- update error handling logic for BraintreePayPalButtons ([1a1c73d](https://github.com/paypal/react-paypal-js/commit/1a1c73dfb15ff39452034d35a786938e5630aa5d)) ### [7.3.2](https://github.com/paypal/react-paypal-js/compare/v7.3.1...v7.3.2) (2021-08-27) ### Bug Fixes -- **buttons:** catch errors thrown during button initialization ([f60176e](https://github.com/paypal/react-paypal-js/commit/f60176e50fdbfab317bcbb08fdaac890a57ba615)) -- remove async/await usage to avoid babel polyfill ([#150](https://github.com/paypal/react-paypal-js/issues/150)) ([ecaf084](https://github.com/paypal/react-paypal-js/commit/ecaf08402f17bf92de527bb4d4d714c5007ba5cd)) +- **buttons:** catch errors thrown during button initialization ([f60176e](https://github.com/paypal/react-paypal-js/commit/f60176e50fdbfab317bcbb08fdaac890a57ba615)) +- remove async/await usage to avoid babel polyfill ([#150](https://github.com/paypal/react-paypal-js/issues/150)) ([ecaf084](https://github.com/paypal/react-paypal-js/commit/ecaf08402f17bf92de527bb4d4d714c5007ba5cd)) ### [7.3.1](https://github.com/paypal/react-paypal-js/compare/v7.3.0...v7.3.1) (2021-08-26) ### Bug Fixes -- **types:** export all public types ([#147](https://github.com/paypal/react-paypal-js/issues/147)) ([9e8c39b](https://github.com/paypal/react-paypal-js/commit/9e8c39b773fa076c1ffabb3c259ca87f25c55141)) +- **types:** export all public types ([#147](https://github.com/paypal/react-paypal-js/issues/147)) ([9e8c39b](https://github.com/paypal/react-paypal-js/commit/9e8c39b773fa076c1ffabb3c259ca87f25c55141)) ## [7.3.0](https://github.com/paypal/react-paypal-js/compare/v7.2.1...v7.3.0) (2021-08-25) ### Features -- **braintree:** add new component ([#140](https://github.com/paypal/react-paypal-js/issues/140)) ([a2c7741](https://github.com/paypal/react-paypal-js/commit/a2c774168fbc5ae7a610df384feca684737d7fba)) +- **braintree:** add new component ([#140](https://github.com/paypal/react-paypal-js/issues/140)) ([a2c7741](https://github.com/paypal/react-paypal-js/commit/a2c774168fbc5ae7a610df384feca684737d7fba)) ### Bug Fixes -- prevent numeric overflow with hashStr function ([#141](https://github.com/paypal/react-paypal-js/issues/141)) ([9914f60](https://github.com/paypal/react-paypal-js/commit/9914f60701c19dcde2fb42ad8791265aee37e34c)) +- prevent numeric overflow with hashStr function ([#141](https://github.com/paypal/react-paypal-js/issues/141)) ([9914f60](https://github.com/paypal/react-paypal-js/commit/9914f60701c19dcde2fb42ad8791265aee37e34c)) ### [7.2.1](https://github.com/paypal/react-paypal-js/compare/v7.2.0...v7.2.1) (2021-07-28) ### Bug Fixes -- avoid reloading the script when options have not changed ([#135](https://github.com/paypal/react-paypal-js/issues/135)) ([0765e16](https://github.com/paypal/react-paypal-js/commit/0765e1600322bd511ddfc61b427d14b356d3f1b8)) +- avoid reloading the script when options have not changed ([#135](https://github.com/paypal/react-paypal-js/issues/135)) ([0765e16](https://github.com/paypal/react-paypal-js/commit/0765e1600322bd511ddfc61b427d14b356d3f1b8)) ## [7.2.0](https://github.com/paypal/react-paypal-js/compare/v7.1.2...v7.2.0) (2021-07-11) ### Features -- more robust package publishing ([#130](https://github.com/paypal/react-paypal-js/issues/130)) ([e5caf02](https://github.com/paypal/react-paypal-js/commit/e5caf02ece24b22f50f7f82b40203358746b5cc2)) +- more robust package publishing ([#130](https://github.com/paypal/react-paypal-js/issues/130)) ([e5caf02](https://github.com/paypal/react-paypal-js/commit/e5caf02ece24b22f50f7f82b40203358746b5cc2)) ### Bug Fixes -- **release:** do not publish types from storybook ([#131](https://github.com/paypal/react-paypal-js/issues/131)) ([6534d59](https://github.com/paypal/react-paypal-js/commit/6534d595033dc9960b1fe6939a31482e8f22fdbd)) -- increase opacity for disabled button ([d1ac1d2](https://github.com/paypal/react-paypal-js/commit/d1ac1d28d729774900dd757e0829812ab4cbc4f9)) -- type declarations don’t depend on internal typings ([#129](https://github.com/paypal/react-paypal-js/issues/129)) ([76a3b9f](https://github.com/paypal/react-paypal-js/commit/76a3b9f72b4893aa7c2210e0d77711820a875bef)) +- **release:** do not publish types from storybook ([#131](https://github.com/paypal/react-paypal-js/issues/131)) ([6534d59](https://github.com/paypal/react-paypal-js/commit/6534d595033dc9960b1fe6939a31482e8f22fdbd)) +- increase opacity for disabled button ([d1ac1d2](https://github.com/paypal/react-paypal-js/commit/d1ac1d28d729774900dd757e0829812ab4cbc4f9)) +- type declarations don’t depend on internal typings ([#129](https://github.com/paypal/react-paypal-js/issues/129)) ([76a3b9f](https://github.com/paypal/react-paypal-js/commit/76a3b9f72b4893aa7c2210e0d77711820a875bef)) ### [7.1.2](https://github.com/paypal/react-paypal-js/compare/v7.1.1...v7.1.2) (2021-07-05) @@ -297,24 +297,24 @@ All notable changes to this project will be documented in this file. See [standa ### Bug Fixes -- **types:** export the ScriptProviderProps interface ([e97e3d0](https://github.com/paypal/react-paypal-js/commit/e97e3d0b0cc404e807f7f9e1173ec532592fc8cf)) -- **types:** update resetOptions to support PayPalScriptOptions type ([236c3cf](https://github.com/paypal/react-paypal-js/commit/236c3cff9be53959b24725718a8b0a999e17f02c)) +- **types:** export the ScriptProviderProps interface ([e97e3d0](https://github.com/paypal/react-paypal-js/commit/e97e3d0b0cc404e807f7f9e1173ec532592fc8cf)) +- **types:** update resetOptions to support PayPalScriptOptions type ([236c3cf](https://github.com/paypal/react-paypal-js/commit/236c3cff9be53959b24725718a8b0a999e17f02c)) ## [7.1.0](https://github.com/paypal/react-paypal-js/compare/v7.0.0...v7.1.0) (2021-06-27) ### Features -- **storybook:** add support for overriding js sdk query params ([#121](https://github.com/paypal/react-paypal-js/issues/121)) ([14d62d0](https://github.com/paypal/react-paypal-js/commit/14d62d04b3be17312b8478e815ab826434dfc6fb)) +- **storybook:** add support for overriding js sdk query params ([#121](https://github.com/paypal/react-paypal-js/issues/121)) ([14d62d0](https://github.com/paypal/react-paypal-js/commit/14d62d04b3be17312b8478e815ab826434dfc6fb)) ## [7.0.0](https://github.com/paypal/react-paypal-js/compare/v6.0.2...v7.0.0) (2021-06-04) ### ⚠ BREAKING CHANGES -- new file names for built files in dist folder. +- new file names for built files in dist folder. ### Features -- improve dist folder structure ([b032f77](https://github.com/paypal/react-paypal-js/commit/b032f77ceeb0181123741c0b3422ac19af94131d)) +- improve dist folder structure ([b032f77](https://github.com/paypal/react-paypal-js/commit/b032f77ceeb0181123741c0b3422ac19af94131d)) ### [6.0.2](https://github.com/paypal/react-paypal-js/compare/v6.0.1...v6.0.2) (2021-06-04) @@ -322,29 +322,29 @@ All notable changes to this project will be documented in this file. See [standa ### Bug Fixes -- **types:** improve type for ScriptLoadingState ([#113](https://github.com/paypal/react-paypal-js/issues/113)) ([402afe4](https://github.com/paypal/react-paypal-js/commit/402afe4f54b58bd5dc1d097e7c8d64e12fc852ff)) +- **types:** improve type for ScriptLoadingState ([#113](https://github.com/paypal/react-paypal-js/issues/113)) ([402afe4](https://github.com/paypal/react-paypal-js/commit/402afe4f54b58bd5dc1d097e7c8d64e12fc852ff)) ## [6.0.0](https://github.com/paypal/react-paypal-js/compare/v5.2.0...v6.0.0) (2021-04-12) ### ⚠ BREAKING CHANGES -- forceReRender prop now accepts an array. +- forceReRender prop now accepts an array. ### Features -- update forceReRender to be an array ([#102](https://github.com/paypal/react-paypal-js/issues/102)) ([c41ee40](https://github.com/paypal/react-paypal-js/commit/c41ee40e6899f86f2300285c4826203458f457e5)) +- update forceReRender to be an array ([#102](https://github.com/paypal/react-paypal-js/issues/102)) ([c41ee40](https://github.com/paypal/react-paypal-js/commit/c41ee40e6899f86f2300285c4826203458f457e5)) ## [5.2.0](https://github.com/paypal/react-paypal-js/compare/v5.1.2...v5.2.0) (2021-04-05) ### Features -- add deferLoading prop to control sdk script loading ([2cf3904](https://github.com/paypal/react-paypal-js/commit/2cf3904ebe21edcd8ffd14dcd67b553ad6ced6c8)) +- add deferLoading prop to control sdk script loading ([2cf3904](https://github.com/paypal/react-paypal-js/commit/2cf3904ebe21edcd8ffd14dcd67b553ad6ced6c8)) ### [5.1.2](https://github.com/paypal/react-paypal-js/compare/v5.1.1...v5.1.2) (2021-04-02) ### Bug Fixes -- prevent script provider from loading more than one sdk script ([8d5dbb7](https://github.com/paypal/react-paypal-js/commit/8d5dbb709082bec45835336a0e04312fcc9c5e1e)) +- prevent script provider from loading more than one sdk script ([8d5dbb7](https://github.com/paypal/react-paypal-js/commit/8d5dbb709082bec45835336a0e04312fcc9c5e1e)) ### [5.1.1](https://github.com/paypal/react-paypal-js/compare/v5.1.0...v5.1.1) (2021-03-30) @@ -352,11 +352,11 @@ All notable changes to this project will be documented in this file. See [standa ### Features -- add support for custom namespaces ([8d3cd26](https://github.com/paypal/react-paypal-js/commit/8d3cd2612f9176dc266b4e0633827871a6ce5457)) -- support rendering custom content when ineligible ([c590e90](https://github.com/paypal/react-paypal-js/commit/c590e90dbead2539b3af6602a63f652aa6fcd7d8)) +- add support for custom namespaces ([8d3cd26](https://github.com/paypal/react-paypal-js/commit/8d3cd2612f9176dc266b4e0633827871a6ce5457)) +- support rendering custom content when ineligible ([c590e90](https://github.com/paypal/react-paypal-js/commit/c590e90dbead2539b3af6602a63f652aa6fcd7d8)) ### Bug Fixes -- ignore errors related to enable/disable actions ([f62eda7](https://github.com/paypal/react-paypal-js/commit/f62eda76b9ac00cadcce2a41b7fe14e80b9083a6)) -- ignore errors when cleaning up buttons component ([5a3e6f1](https://github.com/paypal/react-paypal-js/commit/5a3e6f15b81d37688cc40e8101c70ec3b07970ab)) -- use error boundaries approach for all components ([56f1b7e](https://github.com/paypal/react-paypal-js/commit/56f1b7e7486097701655e08be92b23de3135c863)) +- ignore errors related to enable/disable actions ([f62eda7](https://github.com/paypal/react-paypal-js/commit/f62eda76b9ac00cadcce2a41b7fe14e80b9083a6)) +- ignore errors when cleaning up buttons component ([5a3e6f1](https://github.com/paypal/react-paypal-js/commit/5a3e6f15b81d37688cc40e8101c70ec3b07970ab)) +- use error boundaries approach for all components ([56f1b7e](https://github.com/paypal/react-paypal-js/commit/56f1b7e7486097701655e08be92b23de3135c863)) diff --git a/packages/react-paypal-js/package.json b/packages/react-paypal-js/package.json index 8f097069..3d46816b 100644 --- a/packages/react-paypal-js/package.json +++ b/packages/react-paypal-js/package.json @@ -58,7 +58,8 @@ "homepage": "https://paypal.github.io/react-paypal-js/", "dependencies": { "@paypal/paypal-js": "^9.0.0", - "@paypal/sdk-constants": "^1.0.122" + "@paypal/sdk-constants": "^1.0.122", + "dequal": "^2.0.3" }, "devDependencies": { "@babel/core": "^7.17.5", @@ -124,7 +125,10 @@ ], "setupFilesAfterEnv": [ "./jest.setup.ts" - ] + ], + "moduleNameMapper": { + "@paypal/paypal-js/sdk-v6": "/../../node_modules/@paypal/paypal-js/dist/v6/esm/paypal-js.js" + } }, "bugs": { "url": "https://github.com/paypal/react-paypal-js/issues" diff --git a/packages/react-paypal-js/src/v6/components/PayPalProvider.ssr.test.tsx b/packages/react-paypal-js/src/v6/components/PayPalProvider.ssr.test.tsx new file mode 100644 index 00000000..0434ab99 --- /dev/null +++ b/packages/react-paypal-js/src/v6/components/PayPalProvider.ssr.test.tsx @@ -0,0 +1,242 @@ +/** + * @jest-environment node + */ + +import React from "react"; +import { renderToString } from "react-dom/server"; +import { loadCoreSdkScript } from "@paypal/paypal-js/sdk-v6"; + +import { PayPalProvider } from "./PayPalProvider"; +import { usePayPal } from "../hooks/usePayPal"; +import { INSTANCE_LOADING_STATE } from "../types/PayPalProviderTypes"; +import { isServer } from "../utils"; +import { TEST_CLIENT_TOKEN, expectInitialState } from "./providerTestUtils"; + +import type { + CreateInstanceOptions, + PayPalContextState, + LoadCoreSdkScriptOptions, +} from "../types"; + +jest.mock("@paypal/paypal-js/sdk-v6", () => ({ + loadCoreSdkScript: jest.fn(), +})); + +jest.mock("../utils", () => ({ + ...jest.requireActual("../utils"), + isServer: () => true, +})); + +const createInstanceOptions: CreateInstanceOptions<["paypal-payments"]> = { + components: ["paypal-payments"], + clientToken: TEST_CLIENT_TOKEN, +}; + +const scriptOptions: LoadCoreSdkScriptOptions = { + environment: "sandbox", +}; + +// Test utilities +function renderSSRProvider( + instanceOptions = createInstanceOptions, + scriptOpts = scriptOptions, + children?: React.ReactNode, +) { + const { state, TestComponent } = setupSSRTestComponent(); + const { components, clientToken } = instanceOptions; + + const html = renderToString( + + {children} + , + ); + + return { html, state }; +} + +describe("PayPalProvider SSR", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test("should verify isServer mock is working", () => { + expect(isServer()).toBe(true); + }); + + test("should initialize correctly and never load scripts during SSR", () => { + const { state } = renderSSRProvider(); + + expectInitialState(state); + expect(loadCoreSdkScript).not.toHaveBeenCalled(); + }); + + describe("Server-Side Rendering", () => { + test("should not attempt DOM access during server rendering", () => { + // In Node environment, document should be undefined + expect(typeof document).toBe("undefined"); + + expect(() => renderSSRProvider()).not.toThrow(); + }); + + test("should maintain state consistency across multiple server renders", () => { + const { html: html1, state: state1 } = renderSSRProvider(); + const { html: html2, state: state2 } = renderSSRProvider(); + + // Both renders should produce identical state and HTML + expectInitialState(state1); + expectInitialState(state2); + expect(html1).toBe(html2); + }); + }); + + describe("Hydration Preparation", () => { + test("should prepare serializable state for client hydration", () => { + const { state } = renderSSRProvider(); + + // Server state should be safe for serialization + const serializedState = JSON.stringify({ + loadingStatus: state.loadingStatus, + sdkInstance: state.sdkInstance, + eligiblePaymentMethods: state.eligiblePaymentMethods, + error: state.error, + }); + + expect(() => JSON.parse(serializedState)).not.toThrow(); + + const parsedState = JSON.parse(serializedState); + expectInitialState(parsedState); + }); + + test("should handle different options consistently", () => { + const updatedOptions = { + ...createInstanceOptions, + clientToken: "updated-token", + }; + + const { state: state1 } = renderSSRProvider(); + const { state: state2 } = renderSSRProvider(updatedOptions); + + // Both should have consistent initial state regardless of options + expectInitialState(state1); + expectInitialState(state2); + expect(loadCoreSdkScript).not.toHaveBeenCalled(); + }); + }); + + describe("React SSR Integration", () => { + test("should render without warnings or errors", () => { + const consoleSpy = jest + .spyOn(console, "error") + .mockImplementation(); + + const { html } = renderSSRProvider( + createInstanceOptions, + scriptOptions, +
SSR Content
, + ); + + expect(consoleSpy).not.toHaveBeenCalled(); + expect(html).toBeTruthy(); + expect(typeof html).toBe("string"); + expect(html).toContain("SSR Content"); + + consoleSpy.mockRestore(); + }); + + test("should handle complex options without issues", () => { + const complexOptions: CreateInstanceOptions< + ["paypal-payments", "venmo-payments"] + > = { + components: ["paypal-payments", "venmo-payments"], + clientToken: "complex-token-123", + locale: "en_US", + pageType: "checkout", + partnerAttributionId: "test-partner", + }; + + const { html } = renderSSRProvider( + // @ts-expect-error renderSSRProvider is typed for single component + complexOptions, + { environment: "production", debug: true }, +
Complex Options Test
, + ); + + expect(html).toBeTruthy(); + expect(html).toContain("Complex Options Test"); + }); + + test("should generate consistent HTML across renders", () => { + const { html: html1 } = renderSSRProvider( + createInstanceOptions, + scriptOptions, +
Test Content
, + ); + const { html: html2 } = renderSSRProvider( + createInstanceOptions, + scriptOptions, +
Test Content
, + ); + + expect(html1).toBe(html2); + expect(html1).toContain('data-testid="ssr-content"'); + }); + }); + + describe("Multiple Renders", () => { + test("should handle multiple renders without side effects", () => { + // Multiple renders should not cause issues + expect(() => { + for (let i = 0; i < 5; i++) { + renderSSRProvider({ + ...createInstanceOptions, + clientToken: `token-${i}`, + }); + } + }).not.toThrow(); + + // Should never attempt to load scripts regardless of render count + expect(loadCoreSdkScript).not.toHaveBeenCalled(); + }); + }); +}); + +describe("usePayPalInstance SSR", () => { + test("should work correctly in SSR context", () => { + const { state } = renderSSRProvider(); + + expectInitialState(state); + }); +}); + +function setupSSRTestComponent() { + const state: PayPalContextState = { + loadingStatus: INSTANCE_LOADING_STATE.INITIAL, + sdkInstance: null, + eligiblePaymentMethods: null, + error: null, + dispatch: jest.fn(), + }; + + function TestComponent({ + children = null, + }: { + children?: React.ReactNode; + }) { + try { + const instanceState = usePayPal(); + Object.assign(state, instanceState); + } catch (error) { + state.error = error as Error; + } + return <>{children}; + } + + return { + state, + TestComponent, + }; +} diff --git a/packages/react-paypal-js/src/v6/components/PayPalProvider.test.tsx b/packages/react-paypal-js/src/v6/components/PayPalProvider.test.tsx new file mode 100644 index 00000000..bd1e8404 --- /dev/null +++ b/packages/react-paypal-js/src/v6/components/PayPalProvider.test.tsx @@ -0,0 +1,575 @@ +import "@testing-library/jest-dom"; +import React from "react"; +import { render, waitFor } from "@testing-library/react"; +import { loadCoreSdkScript } from "@paypal/paypal-js/sdk-v6"; + +import { PayPalProvider } from "./PayPalProvider"; +import { usePayPal } from "../hooks/usePayPal"; +import { INSTANCE_LOADING_STATE } from "../types/PayPalProviderTypes"; +import { + TEST_CLIENT_TOKEN, + TEST_ERROR_MESSAGE, + TEST_ELIGIBILITY_RESULT, + createMockSdkInstance, + createMockPayPalNamespace, + expectPendingState, + expectResolvedState, + expectRejectedState, + expectResetState, + withConsoleSpy, +} from "./providerTestUtils"; + +import type { + CreateInstanceOptions, + LoadCoreSdkScriptOptions, + PayPalContextState, +} from "../types"; + +jest.mock("@paypal/paypal-js/sdk-v6", () => ({ + loadCoreSdkScript: jest.fn(), +})); + +jest.mock("../utils", () => ({ + ...jest.requireActual("../utils"), + isServer: () => false, +})); + +const createInstanceOptions: CreateInstanceOptions<["paypal-payments"]> = { + components: ["paypal-payments"], + clientToken: TEST_CLIENT_TOKEN, +}; + +const scriptOptions: LoadCoreSdkScriptOptions = { + environment: "sandbox", +}; + +function renderProvider( + instanceOptions = createInstanceOptions, + scriptOpts = scriptOptions, + children?: React.ReactNode, +) { + const { state, TestComponent } = setupTestComponent(); + + const result = render( + + {children} + , + ); + + return { ...result, state }; +} + +describe("PayPalProvider", () => { + beforeEach(() => { + document.head.innerHTML = ""; + (loadCoreSdkScript as jest.Mock).mockResolvedValue( + createMockPayPalNamespace(), + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + document.head.innerHTML = ""; + }); + + describe("SDK Loading", () => { + test("should transition to PENDING on client mount (hydration-safe)", async () => { + const { state } = renderProvider(); + + await waitFor(() => expectPendingState(state)); + }); + + test("should set loadingStatus to 'resolved' when SDK loads successfully", async () => { + const { state } = renderProvider(); + + expect(loadCoreSdkScript).toHaveBeenCalledWith(scriptOptions); + + await waitFor(() => expectResolvedState(state)); + }); + + test('should set loadingStatus to "rejected" when SDK fails to load', async () => { + await withConsoleSpy("error", async () => { + (loadCoreSdkScript as jest.Mock).mockRejectedValue( + new Error(TEST_ERROR_MESSAGE), + ); + + const { state } = renderProvider(); + + await waitFor(() => + expectRejectedState(state, new Error(TEST_ERROR_MESSAGE)), + ); + }); + }); + + test.each<[string, LoadCoreSdkScriptOptions, string, string]>([ + [ + "sandbox", + { environment: "sandbox" }, + "https://www.sandbox.paypal.com/web-sdk/v6/core", + "sandbox.paypal.com", + ], + [ + "production", + { environment: "production" }, + "https://www.paypal.com/web-sdk/v6/core", + "www.paypal.com", + ], + ])( + "should inject script element for %s environment", + async (_env, options, scriptSrc, urlFragment) => { + (loadCoreSdkScript as jest.Mock).mockImplementation(() => { + const script = document.createElement("script"); + script.src = scriptSrc; + document.head.appendChild(script); + return Promise.resolve(createMockPayPalNamespace()); + }); + + renderProvider(createInstanceOptions, options); + + expect(loadCoreSdkScript).toHaveBeenCalledWith(options); + + await waitFor(() => { + const scriptElement = document.querySelector( + `script[src*="${urlFragment}"]`, + ); + expect(scriptElement).toBeInTheDocument(); + }); + }, + ); + }); + + describe("Instance Creation", () => { + test("should call createInstance with correct options", async () => { + const mockCreateInstance = jest + .fn() + .mockResolvedValue(createMockSdkInstance()); + + (loadCoreSdkScript as jest.Mock).mockResolvedValue({ + createInstance: mockCreateInstance, + }); + + const { state } = renderProvider(); + + await waitFor(() => expectResolvedState(state)); + + expect(mockCreateInstance).toHaveBeenCalledWith( + createInstanceOptions, + ); + }); + + test("should handle createInstance failure", async () => { + const instanceError = new Error("Instance creation failed"); + const mockCreateInstance = jest + .fn() + .mockRejectedValue(instanceError); + + (loadCoreSdkScript as jest.Mock).mockResolvedValue({ + createInstance: mockCreateInstance, + }); + + const { state } = renderProvider(); + + await waitFor(() => expectRejectedState(state, instanceError)); + }); + + test("should work with multiple component types", async () => { + const multiComponentOptions: CreateInstanceOptions< + ["paypal-payments", "venmo-payments"] + > = { + components: ["paypal-payments", "venmo-payments"], + clientToken: TEST_CLIENT_TOKEN, + }; + + const mockMultiInstance = { + ...createMockSdkInstance(), + createVenmoOneTimePaymentSession: jest.fn(), + }; + + const mockCreateInstance = jest + .fn() + .mockResolvedValue(mockMultiInstance); + + (loadCoreSdkScript as jest.Mock).mockResolvedValue({ + createInstance: mockCreateInstance, + }); + // @ts-expect-error renderProvider is typed for single component only + const { state } = renderProvider(multiComponentOptions); + + await waitFor(() => expectResolvedState(state)); + + expect(mockCreateInstance).toHaveBeenCalledWith( + multiComponentOptions, + ); + }); + }); + + describe("Eligibility Loading", () => { + test("should load eligible payment methods after instance creation", async () => { + const { state } = renderProvider(); + + await waitFor(() => expectResolvedState(state)); + + await waitFor(() => + expect(state.eligiblePaymentMethods).toEqual( + TEST_ELIGIBILITY_RESULT, + ), + ); + }); + + test("should handle eligibility loading failure gracefully", async () => { + await withConsoleSpy("warn", async (spy) => { + const mockInstance = { + ...createMockSdkInstance(), + findEligibleMethods: jest + .fn() + .mockRejectedValue(new Error("Eligibility failed")), + }; + + (loadCoreSdkScript as jest.Mock).mockResolvedValue({ + createInstance: jest.fn().mockResolvedValue(mockInstance), + }); + + const { state } = renderProvider(); + + await waitFor(() => expectResolvedState(state)); + + await waitFor(() => + expect(spy).toHaveBeenCalledWith( + "Failed to get eligible payment methods:", + expect.any(Error), + ), + ); + + expect(state.eligiblePaymentMethods).toBe(null); + }); + }); + }); + + describe("Props Changes", () => { + test("should reset state when createInstanceOptions change", async () => { + const { state, TestComponent } = setupTestComponent(); + + const { rerender } = render( + + + , + ); + + // Wait for initial load + await waitFor(() => expectResolvedState(state)); + + // Change the options + rerender( + + + , + ); + + // Should reset to pending state + expectResetState(state); + + // Should reload with new options + await waitFor(() => expectResolvedState(state)); + }); + }); + + describe("Component Lifecycle", () => { + test.each<[string, () => void]>([ + [ + "SDK loading", + () => { + let resolveLoad: ( + value: ReturnType, + ) => void; + const loadPromise = new Promise< + ReturnType + >((resolve) => { + resolveLoad = resolve; + }); + (loadCoreSdkScript as jest.Mock).mockReturnValue( + loadPromise, + ); + + setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + resolveLoad!(createMockPayPalNamespace()); + }, 100); + }, + ], + [ + "instance creation", + () => { + let resolveCreateInstance: ( + value: ReturnType, + ) => void; + const createInstancePromise = new Promise< + ReturnType + >((resolve) => { + resolveCreateInstance = resolve; + }); + + (loadCoreSdkScript as jest.Mock).mockResolvedValue({ + createInstance: jest + .fn() + .mockReturnValue(createInstancePromise), + }); + + setTimeout(() => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + resolveCreateInstance!(createMockSdkInstance()); + }, 100); + }, + ], + ])( + "should not update state after component unmounts during %s", + async (_stage, setupMock) => { + setupMock(); + + const { state, unmount } = renderProvider(); + + await waitFor(() => expectPendingState(state)); + + // Unmount the component before async operation completes + unmount(); + + // Wait and ensure state wasn't updated + await waitFor( + () => { + expectPendingState(state); + expect(state.sdkInstance).toBe(null); + }, + { timeout: 500 }, + ); + }, + ); + }); +}); + +describe("Auto-memoization", () => { + beforeEach(() => { + document.head.innerHTML = ""; + (loadCoreSdkScript as jest.Mock).mockResolvedValue( + createMockPayPalNamespace(), + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + document.head.innerHTML = ""; + }); + + test("should not reload SDK when props have same values but different references", async () => { + const { state, TestComponent } = setupTestComponent(); + + const { rerender } = render( + + + , + ); + + await waitFor(() => expectResolvedState(state)); + + const loadCallCount = (loadCoreSdkScript as jest.Mock).mock.calls + .length; + + // Rerender with new object reference but same values + rerender( + + + , + ); + + // Wait a bit to ensure no reload happens + await new Promise((resolve) => setTimeout(resolve, 100)); + + // Should NOT reload + expect((loadCoreSdkScript as jest.Mock).mock.calls.length).toBe( + loadCallCount, + ); + }); + + test("should reload SDK when actual values change", async () => { + const { state, TestComponent } = setupTestComponent(); + + const { rerender } = render( + + + , + ); + + await waitFor(() => expectResolvedState(state)); + + const loadCallCount = (loadCoreSdkScript as jest.Mock).mock.calls + .length; + + // Rerender with different client token + rerender( + + + , + ); + + // Should reset to pending state + expectResetState(state); + + // Should reload with new token + await waitFor(() => + expect((loadCoreSdkScript as jest.Mock).mock.calls.length).toBe( + loadCallCount + 1, + ), + ); + }); + + test("should reload SDK when scriptOptions change", async () => { + const { state, TestComponent } = setupTestComponent(); + + const { rerender } = render( + + + , + ); + + await waitFor(() => expectResolvedState(state)); + + const loadCallCount = (loadCoreSdkScript as jest.Mock).mock.calls + .length; + + // Rerender with different environment + rerender( + + + , + ); + + // Should reset to pending state + expectResetState(state); + + // Should reload with new environment + await waitFor(() => + expect((loadCoreSdkScript as jest.Mock).mock.calls.length).toBe( + loadCallCount + 1, + ), + ); + }); + + test("should handle nested object changes correctly", async () => { + const { state, TestComponent } = setupTestComponent(); + + const complexOptions: CreateInstanceOptions< + ["paypal-payments", "venmo-payments"] + > = { + components: ["paypal-payments", "venmo-payments"], + clientToken: TEST_CLIENT_TOKEN, + locale: "en_US", + }; + + const { rerender } = render( + + + , + ); + + await waitFor(() => expectResolvedState(state)); + + const loadCallCount = (loadCoreSdkScript as jest.Mock).mock.calls + .length; + + // Rerender with same values but new object reference + rerender( + + + , + ); + + // Wait a bit to ensure no reload happens + await new Promise((resolve) => setTimeout(resolve, 100)); + + // Should NOT reload + expect((loadCoreSdkScript as jest.Mock).mock.calls.length).toBe( + loadCallCount, + ); + }); +}); + +describe("usePayPal", () => { + test("should throw an error when used without PayPalProvider", () => { + withConsoleSpy("error", () => { + const { TestComponent } = setupTestComponent(); + + expect(() => render()).toThrow( + "usePayPal must be used within a PayPalProvider", + ); + }); + }); +}); + +function setupTestComponent() { + const state: PayPalContextState = { + loadingStatus: INSTANCE_LOADING_STATE.INITIAL, + sdkInstance: null, + eligiblePaymentMethods: null, + error: null, + dispatch: jest.fn(), + }; + + function TestComponent({ + children = null, + }: { + children?: React.ReactNode; + }) { + const instanceState = usePayPal(); + Object.assign(state, instanceState); + return <>{children}; + } + + return { + state, + TestComponent, + }; +} diff --git a/packages/react-paypal-js/src/v6/components/PayPalProvider.tsx b/packages/react-paypal-js/src/v6/components/PayPalProvider.tsx new file mode 100644 index 00000000..7a36628a --- /dev/null +++ b/packages/react-paypal-js/src/v6/components/PayPalProvider.tsx @@ -0,0 +1,227 @@ +import React, { useEffect, useMemo, useReducer, useRef } from "react"; +import { loadCoreSdkScript } from "@paypal/paypal-js/sdk-v6"; + +import { + PayPalContext, + instanceReducer, +} from "../context/PayPalProviderContext"; +import { + INSTANCE_LOADING_STATE, + INSTANCE_DISPATCH_ACTION, +} from "../types/PayPalProviderTypes"; +import { isServer, useDeepCompareMemoize } from "../utils"; + +import type { + CreateInstanceOptions, + Components, + LoadCoreSdkScriptOptions, +} from "../types"; + +type PayPalProviderProps = CreateInstanceOptions< + readonly [Components, ...Components[]] +> & { + // Provider-specific properties + children: React.ReactNode; + scriptOptions: LoadCoreSdkScriptOptions; +}; + +/** + * PayPal SDK Instance Provider with SSR support + * + * SSR Behavior: + * - Server: Initializes in INITIAL state, no script loading attempted + * - Client: Initializes in PENDING state, loads scripts on mount + * - Hydration: Client takes over from server state seamlessly + * + * Props are automatically deep-compared to prevent unnecessary SDK reloads. + * You can pass options directly without manual memoization. + * + * @example + * + * {children} + * + */ +export const PayPalProvider: React.FC = ({ + clientMetadataId, + clientToken, + components, + locale, + pageType, + partnerAttributionId, + shopperSessionId, + testBuyerCountry, + children, + scriptOptions, +}) => { + // Auto-memoize props based on deep equality to prevent unnecessary reloads + const memoizedCreateOptions = useDeepCompareMemoize({ + clientMetadataId, + clientToken, + components, + locale, + pageType, + partnerAttributionId, + shopperSessionId, + testBuyerCountry, + }); + const memoizedScriptOptions = useDeepCompareMemoize(scriptOptions); + + // Track if we've already handled the initial hydration + const hasHandledInitialHydration = useRef(false); + + const [state, dispatch] = useReducer(instanceReducer, { + sdkInstance: null, + eligiblePaymentMethods: null, + loadingStatus: INSTANCE_LOADING_STATE.INITIAL, + error: null, + }); + + // Client-side hydration: transition from INITIAL to PENDING state + useEffect(() => { + if ( + !isServer() && + state.loadingStatus === INSTANCE_LOADING_STATE.INITIAL && + !hasHandledInitialHydration.current + ) { + hasHandledInitialHydration.current = true; + dispatch({ + type: INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS, + value: INSTANCE_LOADING_STATE.PENDING, + }); + } + }, [state.loadingStatus]); // Run when loadingStatus changes, but only act once + + // Effect to reset state if options change + useEffect(() => { + if (!state.sdkInstance) { + return; + } + + dispatch({ + type: INSTANCE_DISPATCH_ACTION.RESET_STATE, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [memoizedCreateOptions, memoizedScriptOptions]); // Only reset when options change, not the SDK instance + + // SDK loading effect - only runs on client (useEffect doesn't run during SSR) + useEffect(() => { + if (state.loadingStatus !== INSTANCE_LOADING_STATE.PENDING) { + return; + } + + let isSubscribed = true; + + const loadSdk = async () => { + try { + // Load the core SDK script + const paypalNamespace = await loadCoreSdkScript( + memoizedScriptOptions, + ); + + if (!isSubscribed || !paypalNamespace) { + return; + } + + // Create SDK instance + const instance = await paypalNamespace.createInstance( + memoizedCreateOptions, + ); + + if (!isSubscribed || !instance) { + return; + } + + dispatch({ + type: INSTANCE_DISPATCH_ACTION.SET_INSTANCE, + value: instance, + }); + } catch (error) { + if (isSubscribed) { + const errorInstance = + error instanceof Error + ? error + : new Error(String(error)); + dispatch({ + type: INSTANCE_DISPATCH_ACTION.SET_ERROR, + value: errorInstance, + }); + } + } + }; + + loadSdk(); + + return () => { + isSubscribed = false; + }; + }, [state.loadingStatus, memoizedCreateOptions, memoizedScriptOptions]); + + // Separate effect for eligibility - runs after instance is created + useEffect(() => { + // Only run when we have an instance and it's in resolved state + if ( + !state.sdkInstance || + state.loadingStatus !== INSTANCE_LOADING_STATE.RESOLVED + ) { + return; + } + + let isSubscribed = true; + + const loadEligibility = async () => { + try { + const eligiblePaymentMethods = + await state.sdkInstance?.findEligibleMethods({}); + + if (!isSubscribed || !eligiblePaymentMethods) { + return; + } + + dispatch({ + type: INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY, + value: eligiblePaymentMethods, + }); + } catch (error) { + if (isSubscribed) { + console.warn( + "Failed to get eligible payment methods:", + error, + ); + } + } + }; + + loadEligibility(); + + return () => { + isSubscribed = false; + }; + }, [state.sdkInstance, state.loadingStatus]); + + const contextValue = useMemo( + () => ({ + sdkInstance: state.sdkInstance, + eligiblePaymentMethods: state.eligiblePaymentMethods, + error: state.error, + dispatch, + loadingStatus: state.loadingStatus, + }), + [ + state.sdkInstance, + state.eligiblePaymentMethods, + state.error, + state.loadingStatus, + dispatch, + ], + ); + + return ( + + {children} + + ); +}; diff --git a/packages/react-paypal-js/src/v6/components/providerTestUtils.ts b/packages/react-paypal-js/src/v6/components/providerTestUtils.ts new file mode 100644 index 00000000..9bae74f7 --- /dev/null +++ b/packages/react-paypal-js/src/v6/components/providerTestUtils.ts @@ -0,0 +1,80 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { INSTANCE_LOADING_STATE } from "../types/PayPalProviderTypes"; + +import type { PayPalContextState } from "../types"; + +// Test constants +export const TEST_CLIENT_TOKEN = "test-client-token"; +export const TEST_ERROR_MESSAGE = "test error"; +export const TEST_ELIGIBILITY_RESULT = { + paypal: { eligible: true }, + venmo: { eligible: false }, +}; + +// Mock factories +export function createMockSdkInstance() { + return { + findEligibleMethods: jest + .fn() + .mockResolvedValue(TEST_ELIGIBILITY_RESULT), + createPayPalOneTimePaymentSession: jest.fn(), + updateLocale: jest.fn(), + }; +} + +export function createMockPayPalNamespace() { + return { + createInstance: jest.fn().mockResolvedValue(createMockSdkInstance()), + }; +} + +// State assertion helpers +export function expectInitialState(state: Partial) { + expect(state.loadingStatus).toBe(INSTANCE_LOADING_STATE.INITIAL); + expect(state.sdkInstance).toBe(null); + expect(state.eligiblePaymentMethods).toBe(null); + expect(state.error).toBe(null); +} + +export function expectPendingState(state: Partial) { + expect(state.loadingStatus).toBe(INSTANCE_LOADING_STATE.PENDING); +} + +export function expectResolvedState(state: Partial) { + expect(state.loadingStatus).toBe(INSTANCE_LOADING_STATE.RESOLVED); + expect(state.sdkInstance).toBeTruthy(); + expect(state.error).toBe(null); +} + +export function expectRejectedState( + state: Partial, + error?: Error, +) { + expect(state.loadingStatus).toBe(INSTANCE_LOADING_STATE.REJECTED); + expect(state.sdkInstance).toBe(null); + if (error) { + expect(state.error).toEqual(error); + } +} + +export function expectResetState(state: Partial) { + expect(state.loadingStatus).toBe(INSTANCE_LOADING_STATE.PENDING); + expect(state.sdkInstance).toBe(null); + expect(state.eligiblePaymentMethods).toBe(null); + expect(state.error).toBe(null); +} + +// Console spy utilities +export function withConsoleSpy( + method: "error" | "warn" | "log", + testFn: (spy: jest.SpyInstance) => void | Promise, +) { + const spy = jest.spyOn(console, method).mockImplementation(); + const result = testFn(spy); + + if (result instanceof Promise) { + return result.finally(() => spy.mockRestore()); + } + + spy.mockRestore(); +} diff --git a/packages/react-paypal-js/src/v6/context/PayPalProviderContext.test.ts b/packages/react-paypal-js/src/v6/context/PayPalProviderContext.test.ts new file mode 100644 index 00000000..4e879491 --- /dev/null +++ b/packages/react-paypal-js/src/v6/context/PayPalProviderContext.test.ts @@ -0,0 +1,305 @@ +import { mock } from "jest-mock-extended"; + +import { instanceReducer } from "./PayPalProviderContext"; +import { + INSTANCE_LOADING_STATE, + INSTANCE_DISPATCH_ACTION, + PayPalState, + InstanceAction, +} from "../types/PayPalProviderTypes"; + +import type { + SdkInstance, + EligiblePaymentMethodsOutput, + CreateInstanceOptions, + LoadCoreSdkScriptOptions, + Components, +} from "../types"; + +// Test utilities and mock factories +function createMockSdkInstance() { + return mock>({ + findEligibleMethods: jest.fn().mockResolvedValue({}), + createPayPalOneTimePaymentSession: jest.fn(), + updateLocale: jest.fn(), + }); +} + +function createMockEligiblePaymentMethods(): EligiblePaymentMethodsOutput { + return { + isEligible: jest.fn((paymentMethod) => { + switch (paymentMethod) { + case "paypal": + case "credit": + return true; + case "venmo": + case "paylater": + default: + return false; + } + }), + getDetails: jest.fn((fundingSource) => { + if (fundingSource === "credit") { + return { + canBeVaulted: true, + countryCode: "US", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + } + if (fundingSource === "paylater") { + return { + canBeVaulted: true, + countryCode: "US", + productCode: "PAY_IN_4", + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + } + return { + canBeVaulted: true, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any; + }), + }; +} + +function createMockCreateInstanceOptions(): CreateInstanceOptions< + readonly [Components, ...Components[]] +> { + return { + components: ["paypal-payments" as Components], + clientToken: "test-client-token", + }; +} + +function createMockScriptOptions(): LoadCoreSdkScriptOptions { + return { + environment: "sandbox", + }; +} + +function createInitialState(): PayPalState { + return { + sdkInstance: null, + eligiblePaymentMethods: null, + loadingStatus: INSTANCE_LOADING_STATE.INITIAL, + error: null, + }; +} + +describe("instanceReducer", () => { + let initialState: PayPalState; + + beforeEach(() => { + initialState = createInitialState(); + }); + + describe("SET_LOADING_STATUS action", () => { + test.each([ + INSTANCE_LOADING_STATE.PENDING, + INSTANCE_LOADING_STATE.RESOLVED, + INSTANCE_LOADING_STATE.REJECTED, + ])("should set loadingStatus to %s", (status) => { + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS, + value: status, + }; + + const result = instanceReducer(initialState, action); + + expect(result.loadingStatus).toBe(status); + expect(result).not.toBe(initialState); + }); + }); + + describe("SET_INSTANCE action", () => { + test("should set SDK instance and automatically set loadingStatus to RESOLVED", () => { + const mockInstance = createMockSdkInstance(); + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.SET_INSTANCE, + value: mockInstance, + }; + + const result = instanceReducer(initialState, action); + + expect(result.sdkInstance).toBe(mockInstance); + expect(result.loadingStatus).toBe(INSTANCE_LOADING_STATE.RESOLVED); + expect(result).not.toBe(initialState); + }); + }); + + describe("SET_ELIGIBILITY action", () => { + test("should set eligible payment methods", () => { + const mockEligibility = createMockEligiblePaymentMethods(); + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY, + value: mockEligibility, + }; + + const result = instanceReducer(initialState, action); + + expect(result.eligiblePaymentMethods).toBe(mockEligibility); + expect(result).not.toBe(initialState); + }); + }); + + describe("SET_ERROR action", () => { + test.each([ + ["Error", new Error("SDK loading failed")], + ["TypeError", new TypeError("Network error")], + ])( + "should set error and automatically set loadingStatus to REJECTED for %s", + (_name, error) => { + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.SET_ERROR, + value: error, + }; + + const result = instanceReducer(initialState, action); + + expect(result.error).toBe(error); + expect(result.loadingStatus).toBe( + INSTANCE_LOADING_STATE.REJECTED, + ); + expect(result).not.toBe(initialState); + }, + ); + }); + + describe("RESET_STATE action", () => { + test("should reset state with new options", () => { + const stateWithData = { + ...initialState, + sdkInstance: createMockSdkInstance(), + eligiblePaymentMethods: createMockEligiblePaymentMethods(), + error: new Error("previous error"), + loadingStatus: INSTANCE_LOADING_STATE.RESOLVED, + }; + + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.RESET_STATE, + }; + + const result = instanceReducer(stateWithData, action); + + expect(result.sdkInstance).toBe(null); + expect(result.eligiblePaymentMethods).toBe(null); + expect(result.error).toBe(null); + expect(result.loadingStatus).toBe(INSTANCE_LOADING_STATE.PENDING); + expect(result).not.toBe(stateWithData); + }); + + test("should reset from initial state", () => { + const action: InstanceAction = { + type: INSTANCE_DISPATCH_ACTION.RESET_STATE, + }; + + const result = instanceReducer(initialState, action); + + expect(result.sdkInstance).toBe(null); + expect(result.eligiblePaymentMethods).toBe(null); + expect(result.error).toBe(null); + expect(result.loadingStatus).toBe(INSTANCE_LOADING_STATE.PENDING); + }); + }); + + describe("Invalid actions", () => { + test("should return same state for unknown action type", () => { + const result = instanceReducer(initialState, { + // @ts-expect-error invalid action type + type: "UNKNOWN_ACTION", + // @ts-expect-error invalid component value + value: "test", + }); + + expect(result).toBe(initialState); + }); + }); + + describe("State immutability and preservation", () => { + test("should return new state object for all valid actions", () => { + const testCases: InstanceAction[] = [ + { + type: INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS, + value: INSTANCE_LOADING_STATE.PENDING, + }, + { + type: INSTANCE_DISPATCH_ACTION.SET_INSTANCE, + value: createMockSdkInstance(), + }, + { + type: INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY, + value: createMockEligiblePaymentMethods(), + }, + { + type: INSTANCE_DISPATCH_ACTION.SET_ERROR, + value: new Error("test"), + }, + { + type: INSTANCE_DISPATCH_ACTION.RESET_STATE, + }, + ]; + + testCases.forEach((action) => { + const result = instanceReducer(initialState, action); + expect(result).not.toBe(initialState); + }); + }); + + test.each<[string, InstanceAction]>([ + [ + "SET_LOADING_STATUS", + { + type: INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS, + value: INSTANCE_LOADING_STATE.PENDING, + }, + ], + [ + "SET_INSTANCE", + { + type: INSTANCE_DISPATCH_ACTION.SET_INSTANCE, + value: createMockSdkInstance(), + }, + ], + [ + "SET_ELIGIBILITY", + { + type: INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY, + value: createMockEligiblePaymentMethods(), + }, + ], + [ + "SET_ERROR", + { + type: INSTANCE_DISPATCH_ACTION.SET_ERROR, + value: new Error("test"), + }, + ], + ])( + "should preserve unmodified state properties for %s action", + (_name, action) => { + const mockInstance = createMockSdkInstance(); + const mockEligibility = createMockEligiblePaymentMethods(); + const mockOptions = createMockCreateInstanceOptions(); + const mockScriptOptions = createMockScriptOptions(); + + const stateWithData = { + ...initialState, + sdkInstance: mockInstance, + eligiblePaymentMethods: mockEligibility, + createInstanceOptions: mockOptions, + scriptOptions: mockScriptOptions, + }; + + const result = instanceReducer(stateWithData, action); + + // Verify unmodified properties maintain reference equality + if (action.type !== INSTANCE_DISPATCH_ACTION.SET_INSTANCE) { + expect(result.sdkInstance).toBe(mockInstance); + } + if (action.type !== INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY) { + expect(result.eligiblePaymentMethods).toBe(mockEligibility); + } + }, + ); + }); +}); diff --git a/packages/react-paypal-js/src/v6/context/PayPalProviderContext.tsx b/packages/react-paypal-js/src/v6/context/PayPalProviderContext.tsx new file mode 100644 index 00000000..1cba99f3 --- /dev/null +++ b/packages/react-paypal-js/src/v6/context/PayPalProviderContext.tsx @@ -0,0 +1,45 @@ +import { createContext } from "react"; + +import { + PayPalContextState, + PayPalState, + InstanceAction, + INSTANCE_LOADING_STATE, + INSTANCE_DISPATCH_ACTION, +} from "../types/PayPalProviderTypes"; + +export function instanceReducer( + state: PayPalState, + action: InstanceAction, +): PayPalState { + switch (action.type) { + case INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS: + return { ...state, loadingStatus: action.value }; + case INSTANCE_DISPATCH_ACTION.SET_INSTANCE: + return { + ...state, + sdkInstance: action.value, + loadingStatus: INSTANCE_LOADING_STATE.RESOLVED, + }; + case INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY: + return { ...state, eligiblePaymentMethods: action.value }; + case INSTANCE_DISPATCH_ACTION.SET_ERROR: + return { + ...state, + error: action.value, + loadingStatus: INSTANCE_LOADING_STATE.REJECTED, + }; + case INSTANCE_DISPATCH_ACTION.RESET_STATE: + return { + ...state, + sdkInstance: null, + eligiblePaymentMethods: null, + error: null, + loadingStatus: INSTANCE_LOADING_STATE.PENDING, + }; + default: + return state; + } +} + +export const PayPalContext = createContext(null); diff --git a/packages/react-paypal-js/src/v6/hooks/usePayPal.ts b/packages/react-paypal-js/src/v6/hooks/usePayPal.ts new file mode 100644 index 00000000..0edd4fa1 --- /dev/null +++ b/packages/react-paypal-js/src/v6/hooks/usePayPal.ts @@ -0,0 +1,15 @@ +import { useContext } from "react"; + +import { PayPalContext } from "../context/PayPalProviderContext"; + +import type { PayPalContextState } from "../types/PayPalProviderTypes"; + +export function usePayPal(): PayPalContextState { + const context = useContext(PayPalContext); + + if (context === null) { + throw new Error("usePayPal must be used within a PayPalProvider"); + } + + return context; +} diff --git a/packages/react-paypal-js/src/v6/index.ts b/packages/react-paypal-js/src/v6/index.ts index eea524d6..77a0c10e 100644 --- a/packages/react-paypal-js/src/v6/index.ts +++ b/packages/react-paypal-js/src/v6/index.ts @@ -1 +1,4 @@ export * from "./types"; +export { PayPalProvider } from "./components/PayPalProvider"; +export { PayPalContext } from "./context/PayPalProviderContext"; +export { usePayPal } from "./hooks/usePayPal"; diff --git a/packages/react-paypal-js/src/v6/types/PayPalProviderTypes.ts b/packages/react-paypal-js/src/v6/types/PayPalProviderTypes.ts new file mode 100644 index 00000000..572c6c5d --- /dev/null +++ b/packages/react-paypal-js/src/v6/types/PayPalProviderTypes.ts @@ -0,0 +1,49 @@ +import type { Components, SdkInstance, EligiblePaymentMethodsOutput } from "."; + +export enum INSTANCE_LOADING_STATE { + INITIAL = "initial", + PENDING = "pending", + RESOLVED = "resolved", + REJECTED = "rejected", +} + +export enum INSTANCE_DISPATCH_ACTION { + SET_LOADING_STATUS = "setLoadingStatus", + SET_INSTANCE = "setInstance", + SET_ELIGIBILITY = "setEligibility", + SET_ERROR = "setError", + RESET_STATE = "resetState", +} + +export interface PayPalState { + sdkInstance: SdkInstance | null; + eligiblePaymentMethods: EligiblePaymentMethodsOutput | null; + loadingStatus: INSTANCE_LOADING_STATE; + error: Error | null; +} + +export type InstanceAction = + | { + type: INSTANCE_DISPATCH_ACTION.SET_LOADING_STATUS; + value: INSTANCE_LOADING_STATE; + } + | { + type: INSTANCE_DISPATCH_ACTION.SET_INSTANCE; + value: SdkInstance; + } + | { + type: INSTANCE_DISPATCH_ACTION.SET_ELIGIBILITY; + value: EligiblePaymentMethodsOutput; + } + | { type: INSTANCE_DISPATCH_ACTION.SET_ERROR; value: Error } + | { + type: INSTANCE_DISPATCH_ACTION.RESET_STATE; + }; + +export interface PayPalContextState { + sdkInstance: SdkInstance | null; + eligiblePaymentMethods: EligiblePaymentMethodsOutput | null; + error: Error | null; + dispatch: React.Dispatch; + loadingStatus: INSTANCE_LOADING_STATE; +} diff --git a/packages/react-paypal-js/src/v6/types/index.ts b/packages/react-paypal-js/src/v6/types/index.ts index c216cddb..3133fae3 100644 --- a/packages/react-paypal-js/src/v6/types/index.ts +++ b/packages/react-paypal-js/src/v6/types/index.ts @@ -1,3 +1,2 @@ -import type { PayPalV6Namespace } from "@paypal/paypal-js/sdk-v6"; - -export type { PayPalV6Namespace }; +export type * from "@paypal/paypal-js/sdk-v6"; +export * from "./PayPalProviderTypes"; diff --git a/packages/react-paypal-js/src/v6/utils.ts b/packages/react-paypal-js/src/v6/utils.ts new file mode 100644 index 00000000..4805ad7d --- /dev/null +++ b/packages/react-paypal-js/src/v6/utils.ts @@ -0,0 +1,31 @@ +import { useRef } from "react"; +import { dequal } from "dequal"; + +export function isServer(): boolean { + return typeof window === "undefined" && typeof document === "undefined"; +} + +/** + * Custom hook that memoizes a value based on deep equality comparison. + * Returns a stable reference when the deep value hasn't changed. + * + * This allows developers to pass inline objects without causing unnecessary re-renders. + * + * @param value - The value to memoize + * @returns A stable reference to the value + * + * @example + * const memoizedOptions = useDeepCompareMemoize({ + * clientToken: token, + * components: ["paypal-payments"] + * }); + */ +export function useDeepCompareMemoize(value: T): T { + const ref = useRef(value); + + if (!dequal(ref.current, value)) { + ref.current = value; + } + + return ref.current; +}