@vtex/faststore 0.0.8 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/README.md +0 -1
- package/dist/actions.json +48 -1
- package/dist/catalog.json +1397 -1594
- package/dist/cli/index.d.ts +66 -28
- package/dist/cli/index.js +7371 -512
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/server-runtime.js +41 -60
- package/dist/cli/server-runtime.js.map +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +2 -2
- package/dist/components.d.ts +67 -56
- package/dist/components.js +64 -53
- package/dist/content-types.json +5886 -555
- package/dist/core/dist/define-component.d.ts +7 -2
- package/dist/core/dist/define-content-type.d.ts +50 -2
- package/dist/core/dist/define-content-type.js +107 -3
- package/dist/core/dist/define-content-type.js.map +1 -1
- package/dist/core/dist/index.d.ts +2 -2
- package/dist/docs/access-code-field.md +1 -1
- package/dist/docs/access-code-sign-in.md +126 -77
- package/dist/docs/account-address-book.md +210 -95
- package/dist/docs/account-entry-point.md +4 -4
- package/dist/docs/account-menu.md +16 -17
- package/dist/docs/account-saved-cards.md +306 -0
- package/dist/docs/alert-dialog.md +3 -1
- package/dist/docs/avatar.md +4 -2
- package/dist/docs/billing-address.md +99 -30
- package/dist/docs/binding-switcher.md +157 -0
- package/dist/docs/buy-button.md +7 -8
- package/dist/docs/card-entry.md +42 -29
- package/dist/docs/card-summary.md +185 -0
- package/dist/docs/cardholder-document.md +5 -3
- package/dist/docs/carousel.md +5 -4
- package/dist/docs/cart-destination.md +251 -0
- package/dist/docs/cart-item.md +48 -15
- package/dist/docs/cart-totalizer.md +8 -6
- package/dist/docs/cart.md +240 -39
- package/dist/docs/challenge-return.md +135 -0
- package/dist/docs/client-preferences-fieldset.md +10 -5
- package/dist/docs/client-preferences.md +31 -8
- package/dist/docs/client-profile-fieldset.md +20 -6
- package/dist/docs/client-profile.md +12 -3
- package/dist/docs/copy-text.md +9 -7
- package/dist/docs/document-field.md +1 -1
- package/dist/docs/email-field.md +2 -1
- package/dist/docs/email-identification.md +12 -2
- package/dist/docs/footer-copyright.md +4 -2
- package/dist/docs/footer-social.md +1 -1
- package/dist/docs/form.md +54 -18
- package/dist/docs/free-shipping-progress.md +18 -13
- package/dist/docs/identity-edit.md +8 -2
- package/dist/docs/identity-summary.md +18 -5
- package/dist/docs/incentives.md +2 -2
- package/dist/docs/installments.md +46 -32
- package/dist/docs/logo.md +1 -1
- package/dist/docs/my-account-profile.md +16 -11
- package/dist/docs/navigation-link.md +5 -3
- package/dist/docs/order-cancel.md +3 -1
- package/dist/docs/order-delivery-address.md +7 -5
- package/dist/docs/order-delivery-group.md +1 -3
- package/dist/docs/order-details-back.md +1 -1
- package/dist/docs/order-details-header.md +1 -4
- package/dist/docs/order-invoice-download.md +60 -0
- package/dist/docs/order-list-row.md +1 -1
- package/dist/docs/order-list-search.md +13 -20
- package/dist/docs/order-list-views.md +11 -17
- package/dist/docs/order-list.md +12 -5
- package/dist/docs/order-payment.md +9 -7
- package/dist/docs/order-placed-date.md +1 -1
- package/dist/docs/order-placed-payment-summary.md +28 -15
- package/dist/docs/order-placed.md +49 -14
- package/dist/docs/order-progress.md +1 -1
- package/dist/docs/order-status-badge.md +20 -9
- package/dist/docs/order-summary.md +2 -2
- package/dist/docs/order-tracking-link.md +58 -0
- package/dist/docs/payment-method-badges.md +32 -6
- package/dist/docs/payment-methods.md +2 -2
- package/dist/docs/payment.md +36 -17
- package/dist/docs/phone-field.md +4 -4
- package/dist/docs/place-order.md +84 -36
- package/dist/docs/postal-code-field.md +3 -1
- package/dist/docs/pricing.md +21 -23
- package/dist/docs/product-gallery.md +19 -20
- package/dist/docs/product-information.md +14 -10
- package/dist/docs/product-list.md +7 -6
- package/dist/docs/product-shelf.md +7 -1
- package/dist/docs/promotion.md +4 -2
- package/dist/docs/region.md +23 -15
- package/dist/docs/save-card.md +7 -6
- package/dist/docs/saved-cards.md +65 -36
- package/dist/docs/select.md +3 -4
- package/dist/docs/shipping-address.md +57 -21
- package/dist/docs/shipping-simulator.md +53 -15
- package/dist/docs/sign-in-disclosure.md +176 -0
- package/dist/docs/sign-in-form.md +78 -47
- package/dist/docs/sign-in-redirect.md +5 -3
- package/dist/docs/sign-in.md +173 -0
- package/dist/docs/toast.md +45 -16
- package/dist/docs/variant-selector.md +15 -11
- package/dist/graphql/types.d.ts +4 -14
- package/dist/index.d.ts +3 -2
- package/dist/internal/client.d.ts +4 -3
- package/dist/internal/client.js +5 -2
- package/dist/internal/server.d.ts +10 -5
- package/dist/internal/server.js +9 -4
- package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +250 -66
- package/dist/matter/access-code-sign-in/access-code-sign-in.js +459 -188
- package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-delete.d.ts +78 -40
- package/dist/matter/account-address-book/account-address-book-delete.js +86 -50
- package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +21 -4
- package/dist/matter/account-address-book/account-address-book-deliverability.js +45 -17
- package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +74 -19
- package/dist/matter/account-address-book/account-address-book-form-parts.js +77 -26
- package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +27 -6
- package/dist/matter/account-address-book/account-address-book-profile-notice.js +55 -28
- package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book.d.ts +67 -14
- package/dist/matter/account-address-book/account-address-book.js +74 -33
- package/dist/matter/account-address-book/account-address-book.js.map +1 -1
- package/dist/matter/account-address-book/account-address-country-switch.js +3 -3
- package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -1
- package/dist/matter/account-address-book/account-address-country.d.ts +66 -20
- package/dist/matter/account-address-book/account-address-country.js +83 -49
- package/dist/matter/account-address-book/account-address-country.js.map +1 -1
- package/dist/matter/account-address-book/account-address-form-context.d.ts +8 -4
- package/dist/matter/account-address-book/account-address-form-context.js.map +1 -1
- package/dist/matter/account-address-book/account-address-form.d.ts +468 -45
- package/dist/matter/account-address-book/account-address-form.js +518 -155
- package/dist/matter/account-address-book/account-address-form.js.map +1 -1
- package/dist/matter/account-address-book/account-address-record.d.ts +27 -6
- package/dist/matter/account-address-book/account-address-record.js +32 -17
- package/dist/matter/account-address-book/account-address-record.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +34 -17
- package/dist/matter/account-menu/account-menu.js +46 -54
- package/dist/matter/account-menu/account-menu.js.map +1 -1
- package/dist/matter/account-menu-identity/account-menu-identity.js +1 -1
- package/dist/matter/account-saved-cards/account-saved-cards.d.ts +463 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js +1011 -0
- package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
- package/dist/matter/billing-address/billing-address.d.ts +156 -74
- package/dist/matter/billing-address/billing-address.js +227 -156
- package/dist/matter/billing-address/billing-address.js.map +1 -1
- package/dist/matter/breadcrumb/breadcrumb.d.ts +21 -3
- package/dist/matter/breadcrumb/breadcrumb.js +24 -9
- package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/matter/buy-button/buy-button.d.ts +8 -11
- package/dist/matter/buy-button/buy-button.js +10 -19
- package/dist/matter/buy-button/buy-button.js.map +1 -1
- package/dist/matter/card-entry/card-capture.js +12 -4
- package/dist/matter/card-entry/card-capture.js.map +1 -1
- package/dist/matter/card-entry/card-entry.d.ts +123 -32
- package/dist/matter/card-entry/card-entry.js +348 -221
- package/dist/matter/card-entry/card-entry.js.map +1 -1
- package/dist/matter/cart/cart-namespace.d.ts +11 -1
- package/dist/matter/cart/cart-namespace.js +11 -1
- package/dist/matter/cart/cart-namespace.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +416 -45
- package/dist/matter/cart/cart.js +782 -101
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-destination/cart-destination.d.ts +233 -0
- package/dist/matter/cart-destination/cart-destination.js +703 -0
- package/dist/matter/cart-destination/cart-destination.js.map +1 -0
- package/dist/matter/cart-item/cart-item.d.ts +145 -16
- package/dist/matter/cart-item/cart-item.js +230 -54
- package/dist/matter/cart-item/cart-item.js.map +1 -1
- package/dist/matter/cart-item-compositions/cart-item-compositions.js +1 -1
- package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -1
- package/dist/matter/cart-item-customizations/cart-item-customizations.js +1 -1
- package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -1
- package/dist/matter/cart-item-discounts/cart-item-discounts.js +1 -1
- package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -1
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +1 -1
- package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -1
- package/dist/matter/cart-item-variations/cart-item-variations.js +1 -1
- package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -1
- package/dist/matter/cart-totalizer/cart-totalizer.d.ts +43 -9
- package/dist/matter/cart-totalizer/cart-totalizer.js +49 -19
- package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
- package/dist/matter/challenge-return/challenge-return.d.ts +62 -0
- package/dist/matter/challenge-return/challenge-return.js +241 -0
- package/dist/matter/challenge-return/challenge-return.js.map +1 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +86 -17
- package/dist/matter/client-preferences/client-preferences-fieldset.js +126 -54
- package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences.d.ts +50 -7
- package/dist/matter/client-preferences/client-preferences.js +84 -15
- package/dist/matter/client-preferences/client-preferences.js.map +1 -1
- package/dist/matter/client-profile/client-profile.d.ts +44 -9
- package/dist/matter/client-profile/client-profile.js +64 -24
- package/dist/matter/client-profile/client-profile.js.map +1 -1
- package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -22
- package/dist/matter/client-profile-form/client-profile-fieldset.js +161 -73
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options-accordion.d.ts +49 -4
- package/dist/matter/delivery-options/delivery-options-accordion.js +67 -14
- package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options-controller.d.ts +69 -9
- package/dist/matter/delivery-options/delivery-options-controller.js +80 -14
- package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -1
- package/dist/matter/delivery-options/delivery-options.d.ts +37 -2
- package/dist/matter/delivery-options/delivery-options.js +75 -12
- package/dist/matter/delivery-options/delivery-options.js.map +1 -1
- package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +1 -0
- package/dist/matter/delivery-options/use-delivery-option-selection.js +1 -1
- package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -1
- package/dist/matter/email-identification/email-identification.d.ts +25 -3
- package/dist/matter/email-identification/email-identification.js +49 -12
- package/dist/matter/email-identification/email-identification.js.map +1 -1
- package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +85 -10
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +153 -53
- package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.d.ts +52 -10
- package/dist/matter/identity-edit/identity-edit.js +47 -19
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.d.ts +76 -22
- package/dist/matter/identity-summary/identity-summary.js +95 -45
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/installments/installments-select.d.ts +98 -16
- package/dist/matter/installments/installments-select.js +156 -48
- package/dist/matter/installments/installments-select.js.map +1 -1
- package/dist/matter/installments/installments.d.ts +96 -16
- package/dist/matter/installments/installments.js +115 -40
- package/dist/matter/installments/installments.js.map +1 -1
- package/dist/matter/installments/use-installments-selection.d.ts +1 -0
- package/dist/matter/installments/use-installments-selection.js +8 -3
- package/dist/matter/installments/use-installments-selection.js.map +1 -1
- package/dist/matter/my-account-profile/my-account-profile.d.ts +358 -103
- package/dist/matter/my-account-profile/my-account-profile.js +370 -174
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-cancel/order-cancel.d.ts +65 -19
- package/dist/matter/order-cancel/order-cancel.js +118 -51
- package/dist/matter/order-cancel/order-cancel.js.map +1 -1
- package/dist/matter/order-delivery-address/order-delivery-address.d.ts +8 -18
- package/dist/matter/order-delivery-address/order-delivery-address.js +14 -23
- package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -1
- package/dist/matter/order-delivery-group/order-delivery-group.d.ts +40 -24
- package/dist/matter/order-delivery-group/order-delivery-group.js +64 -74
- package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -1
- package/dist/matter/order-details-header/order-details-header.d.ts +32 -15
- package/dist/matter/order-details-header/order-details-header.js +66 -58
- package/dist/matter/order-details-header/order-details-header.js.map +1 -1
- package/dist/matter/order-invoice-download/order-invoice-download.d.ts +78 -0
- package/dist/matter/order-invoice-download/order-invoice-download.js +173 -0
- package/dist/matter/order-invoice-download/order-invoice-download.js.map +1 -0
- package/dist/matter/order-list/order-list.d.ts +164 -19
- package/dist/matter/order-list/order-list.js +229 -87
- package/dist/matter/order-list/order-list.js.map +1 -1
- package/dist/matter/order-list-row/order-list-row.d.ts +6 -1
- package/dist/matter/order-list-row/order-list-row.js +3 -2
- package/dist/matter/order-list-row/order-list-row.js.map +1 -1
- package/dist/matter/order-list-search/order-list-search.d.ts +18 -26
- package/dist/matter/order-list-search/order-list-search.js +30 -69
- package/dist/matter/order-list-search/order-list-search.js.map +1 -1
- package/dist/matter/order-list-views/order-list-views.d.ts +15 -22
- package/dist/matter/order-list-views/order-list-views.js +22 -68
- package/dist/matter/order-list-views/order-list-views.js.map +1 -1
- package/dist/matter/order-payment/order-payment.d.ts +33 -10
- package/dist/matter/order-payment/order-payment.js +44 -39
- package/dist/matter/order-payment/order-payment.js.map +1 -1
- package/dist/matter/order-placed/order-placed-deliveries.d.ts +144 -12
- package/dist/matter/order-placed/order-placed-deliveries.js +115 -40
- package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -1
- package/dist/matter/order-placed/order-placed.d.ts +198 -31
- package/dist/matter/order-placed/order-placed.js +230 -139
- package/dist/matter/order-placed/order-placed.js.map +1 -1
- package/dist/matter/order-placed-date/order-placed-date.d.ts +5 -8
- package/dist/matter/order-placed-date/order-placed-date.js +7 -8
- package/dist/matter/order-placed-date/order-placed-date.js.map +1 -1
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +90 -17
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +93 -117
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
- package/dist/matter/order-progress/order-progress.d.ts +19 -8
- package/dist/matter/order-progress/order-progress.js +37 -45
- package/dist/matter/order-progress/order-progress.js.map +1 -1
- package/dist/matter/order-summary/order-summary.d.ts +19 -9
- package/dist/matter/order-summary/order-summary.js +38 -44
- package/dist/matter/order-summary/order-summary.js.map +1 -1
- package/dist/matter/order-tracking-link/order-tracking-link.d.ts +43 -0
- package/dist/matter/order-tracking-link/order-tracking-link.js +107 -0
- package/dist/matter/order-tracking-link/order-tracking-link.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.js +17 -10
- package/dist/matter/payment/payment-card-capture.js.map +1 -1
- package/dist/matter/payment/payment-controller.d.ts +4 -2
- package/dist/matter/payment/payment-controller.js +30 -9
- package/dist/matter/payment/payment-controller.js.map +1 -1
- package/dist/matter/payment/payment-method-badges.js +1 -1
- package/dist/matter/payment/payment.d.ts +69 -19
- package/dist/matter/payment/payment.js +101 -35
- package/dist/matter/payment/payment.js.map +1 -1
- package/dist/matter/payment/use-payment-method-selection.d.ts +25 -4
- package/dist/matter/payment/use-payment-method-selection.js +94 -32
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
- package/dist/matter/payment/use-payment-submit-gate.d.ts +14 -3
- package/dist/matter/payment/use-payment-submit-gate.js +47 -8
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
- package/dist/matter/place-order/place-order.d.ts +171 -57
- package/dist/matter/place-order/place-order.js +376 -185
- package/dist/matter/place-order/place-order.js.map +1 -1
- package/dist/matter/pricing/pricing.d.ts +152 -13
- package/dist/matter/pricing/pricing.js +153 -52
- package/dist/matter/pricing/pricing.js.map +1 -1
- package/dist/matter/product-information/product-information.d.ts +27 -4
- package/dist/matter/product-information/product-information.js +32 -15
- package/dist/matter/product-information/product-information.js.map +1 -1
- package/dist/matter/product-list/product-list.d.ts +24 -6
- package/dist/matter/product-list/product-list.js +32 -26
- package/dist/matter/product-list/product-list.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +8 -3
- package/dist/matter/product-shelf/product-shelf.js +111 -10
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.d.ts +33 -16
- package/dist/matter/region/region.js +59 -52
- package/dist/matter/region/region.js.map +1 -1
- package/dist/matter/save-card/save-card.d.ts +43 -8
- package/dist/matter/save-card/save-card.js +61 -23
- package/dist/matter/save-card/save-card.js.map +1 -1
- package/dist/matter/saved-cards/saved-cards.d.ts +113 -21
- package/dist/matter/saved-cards/saved-cards.js +349 -77
- package/dist/matter/saved-cards/saved-cards.js.map +1 -1
- package/dist/matter/shipping-address/address-payload.js +25 -0
- package/dist/matter/shipping-address/address-payload.js.map +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +71 -71
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/library-country-descriptors.js +136 -0
- package/dist/matter/shipping-address/library-country-descriptors.js.map +1 -0
- package/dist/matter/shipping-address/shipping-address.d.ts +312 -45
- package/dist/matter/shipping-address/shipping-address.js +443 -188
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +251 -25
- package/dist/matter/shipping-simulator/shipping-simulator.js +261 -51
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/sign-in/sign-in.d.ts +108 -0
- package/dist/matter/sign-in/sign-in.js +285 -0
- package/dist/matter/sign-in/sign-in.js.map +1 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.d.ts +81 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.js +232 -0
- package/dist/matter/sign-in-disclosure/sign-in-disclosure.js.map +1 -0
- package/dist/matter/sign-in-form/sign-in-form.d.ts +93 -62
- package/dist/matter/sign-in-form/sign-in-form.js +134 -144
- package/dist/matter/sign-in-form/sign-in-form.js.map +1 -1
- package/dist/particles/binding-switcher/binding-switcher.d.ts +59 -0
- package/dist/particles/binding-switcher/binding-switcher.js +194 -0
- package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
- package/dist/particles/card-summary/card-network.d.ts +17 -0
- package/dist/particles/card-summary/card-network.js +25 -0
- package/dist/particles/card-summary/card-network.js.map +1 -0
- package/dist/particles/card-summary/card-summary.d.ts +113 -0
- package/dist/particles/card-summary/card-summary.js +221 -0
- package/dist/particles/card-summary/card-summary.js.map +1 -0
- package/dist/particles/carousel/carousel.d.ts +99 -11
- package/dist/particles/carousel/carousel.js +103 -35
- package/dist/particles/carousel/carousel.js.map +1 -1
- package/dist/particles/copy-text/copy-text.js +5 -15
- package/dist/particles/copy-text/copy-text.js.map +1 -1
- package/dist/particles/dialog/dialog.d.ts +14 -6
- package/dist/particles/dialog/dialog.js +6 -3
- package/dist/particles/dialog/dialog.js.map +1 -1
- package/dist/particles/drawer/drawer.js +1 -1
- package/dist/particles/drawer/drawer.js.map +1 -1
- package/dist/particles/email-field/email-field.d.ts +2 -1
- package/dist/particles/email-field/email-field.js +2 -1
- package/dist/particles/email-field/email-field.js.map +1 -1
- package/dist/particles/footer-link-group/footer-link-group.js +1 -0
- package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
- package/dist/particles/footer-social/footer-social.d.ts +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/footer-social/footer-social.js.map +1 -1
- package/dist/particles/form/form.d.ts +85 -13
- package/dist/particles/form/form.js +91 -42
- package/dist/particles/form/form.js.map +1 -1
- package/dist/particles/gallery/gallery.d.ts +129 -12
- package/dist/particles/gallery/gallery.js +121 -34
- package/dist/particles/gallery/gallery.js.map +1 -1
- package/dist/particles/incentives/incentives.d.ts +1 -1
- package/dist/particles/incentives/incentives.js +1 -1
- package/dist/particles/incentives/incentives.js.map +1 -1
- package/dist/particles/order-details-back/order-details-back.d.ts +5 -3
- package/dist/particles/order-details-back/order-details-back.js +8 -10
- package/dist/particles/order-details-back/order-details-back.js.map +1 -1
- package/dist/particles/order-status-badge/order-status-badge.d.ts +3 -3
- package/dist/particles/order-status-badge/order-status-badge.js +4 -20
- package/dist/particles/order-status-badge/order-status-badge.js.map +1 -1
- package/dist/particles/password-field/password-field.d.ts +1 -1
- package/dist/particles/password-field/password-field.js +2 -4
- package/dist/particles/password-field/password-field.js.map +1 -1
- package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
- package/dist/particles/payment-methods/payment-methods.js +1 -1
- package/dist/particles/payment-methods/payment-methods.js.map +1 -1
- package/dist/particles/phone-field/phone-field.d.ts +4 -4
- package/dist/particles/phone-field/phone-field.js +8 -11
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/spinner/spinner.d.ts +24 -4
- package/dist/particles/spinner/spinner.js +25 -9
- package/dist/particles/spinner/spinner.js.map +1 -1
- package/dist/particles/switch/switch.d.ts +4 -1
- package/dist/particles/switch/switch.js +3 -1
- package/dist/particles/switch/switch.js.map +1 -1
- package/dist/particles/toast/toast.d.ts +49 -9
- package/dist/particles/toast/toast.js +81 -15
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +461 -89
- package/dist/sdk/actions/index.d.ts +3 -1
- package/dist/sdk/actions/index.js +3 -1
- package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
- package/dist/sdk/actions/locale-action-provider.js +20 -0
- package/dist/sdk/actions/locale-action-provider.js.map +1 -0
- package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
- package/dist/sdk/actions/saved-card-action-provider.js +16 -0
- package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
- package/dist/sdk/actions/types.d.ts +6 -2
- package/dist/sdk/address/address-fields.js +4 -4
- package/dist/sdk/address/address-fields.js.map +1 -1
- package/dist/sdk/address/constants.js +1 -6
- package/dist/sdk/address/constants.js.map +1 -1
- package/dist/sdk/address/messages.js +44 -44
- package/dist/sdk/address/messages.js.map +1 -1
- package/dist/sdk/address/postal-code.js +15 -2
- package/dist/sdk/address/postal-code.js.map +1 -1
- package/dist/sdk/address/types.d.ts +5 -3
- package/dist/sdk/address/validate-address.js +3 -3
- package/dist/sdk/address/validate-address.js.map +1 -1
- package/dist/sdk/analytics/use-analytics-actions.d.ts +1 -1
- package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
- package/dist/sdk/cache/storefront-cache.js +2 -1
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +2 -1
- package/dist/sdk/cart/operations.js +55 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.d.ts +30 -7
- package/dist/sdk/cart/optimistic.js +78 -41
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
- package/dist/sdk/cart/use-cart-actions.js +61 -15
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
- package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
- package/dist/sdk/data/index.js +2 -2
- package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
- package/dist/sdk/generated/gql.js +16 -12
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +197 -51
- package/dist/sdk/generated/graphql.js +2318 -91
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/format-error-code.js +23 -0
- package/dist/sdk/i18n/format-error-code.js.map +1 -0
- package/dist/sdk/i18n/message-formatter.d.ts +22 -0
- package/dist/sdk/i18n/message-formatter.js +140 -0
- package/dist/sdk/i18n/message-formatter.js.map +1 -0
- package/dist/sdk/i18n/use-message-formatter.d.ts +8 -0
- package/dist/sdk/i18n/use-message-formatter.js +18 -0
- package/dist/sdk/i18n/use-message-formatter.js.map +1 -0
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
- package/dist/sdk/locale/binding-switch-provider.js +20 -0
- package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
- package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
- package/dist/sdk/locale/use-locale-actions.js +70 -0
- package/dist/sdk/locale/use-locale-actions.js.map +1 -0
- package/dist/sdk/navigation/binding-switch.d.ts +39 -0
- package/dist/sdk/navigation/binding-switch.js +129 -0
- package/dist/sdk/navigation/binding-switch.js.map +1 -0
- package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
- package/dist/sdk/navigation/decode-route-params.js +32 -0
- package/dist/sdk/navigation/decode-route-params.js.map +1 -0
- package/dist/sdk/navigation/redirect.d.ts +2 -0
- package/dist/sdk/navigation/redirect.js +19 -1
- package/dist/sdk/navigation/redirect.js.map +1 -1
- package/dist/sdk/navigation/types.d.ts +13 -0
- package/dist/sdk/payment/bin-format.js +20 -0
- package/dist/sdk/payment/bin-format.js.map +1 -0
- package/dist/sdk/payment/challenge-return.js +37 -0
- package/dist/sdk/payment/challenge-return.js.map +1 -0
- package/dist/sdk/payment/confirmation-last-four.js +39 -0
- package/dist/sdk/payment/confirmation-last-four.js.map +1 -0
- package/dist/sdk/payment/gateway.d.ts +1 -1
- package/dist/sdk/payment/gateway.js +8 -2
- package/dist/sdk/payment/gateway.js.map +1 -1
- package/dist/sdk/payment/operations.d.ts +1 -0
- package/dist/sdk/payment/operations.js +28 -6
- package/dist/sdk/payment/operations.js.map +1 -1
- package/dist/sdk/payment/resumed-purchase.d.ts +1 -0
- package/dist/sdk/payment/resumed-purchase.js +119 -0
- package/dist/sdk/payment/resumed-purchase.js.map +1 -0
- package/dist/sdk/payment/security-code-mask.js +16 -23
- package/dist/sdk/payment/security-code-mask.js.map +1 -1
- package/dist/sdk/payment/submission-registry.js +6 -2
- package/dist/sdk/payment/submission-registry.js.map +1 -1
- package/dist/sdk/payment/use-payment-actions.d.ts +18 -3
- package/dist/sdk/payment/use-payment-actions.js +23 -3
- package/dist/sdk/payment/use-payment-actions.js.map +1 -1
- package/dist/sdk/payment/use-place-order.d.ts +10 -2
- package/dist/sdk/payment/use-place-order.js +138 -76
- package/dist/sdk/payment/use-place-order.js.map +1 -1
- package/dist/sdk/provider/storefront-provider.d.ts +1 -7
- package/dist/sdk/provider/storefront-provider.js +4 -11
- package/dist/sdk/provider/storefront-provider.js.map +1 -1
- package/dist/sdk/saved-cards/operations.d.ts +16 -0
- package/dist/sdk/saved-cards/operations.js +41 -0
- package/dist/sdk/saved-cards/operations.js.map +1 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
- package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
- package/dist/sdk/seo/entity-landing.d.ts +24 -0
- package/dist/sdk/seo/entity-landing.js +30 -0
- package/dist/sdk/seo/entity-landing.js.map +1 -0
- package/dist/sdk/seo/page-alternates.d.ts +8 -5
- package/dist/sdk/seo/page-alternates.js +11 -14
- package/dist/sdk/seo/page-alternates.js.map +1 -1
- package/dist/sdk/seo/search-landing.d.ts +42 -0
- package/dist/sdk/seo/search-landing.js +85 -0
- package/dist/sdk/seo/search-landing.js.map +1 -0
- package/dist/sdk/session/mock-session.d.ts +9 -0
- package/dist/sdk/session/mock-session.js +31 -0
- package/dist/sdk/session/mock-session.js.map +1 -0
- package/dist/sdk/session/read-server-session.d.ts +3 -0
- package/dist/sdk/session/read-server-session.js +5 -0
- package/dist/sdk/session/read-server-session.js.map +1 -1
- package/dist/sdk/session/return-path-segment.d.ts +10 -0
- package/dist/sdk/session/return-path-segment.js +15 -0
- package/dist/sdk/session/return-path-segment.js.map +1 -0
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js +13 -0
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +9 -2
- package/dist/sdk/state/cart.js +9 -2
- package/dist/sdk/state/cart.js.map +1 -1
- package/dist/utils/safe-href.d.ts +2 -0
- package/package.json +4 -3
- package/skills/storefront-asset/SKILL.md +2 -2
- package/skills/storefront-asset/references/api-side.md +27 -14
- package/skills/storefront-asset/references/findings.md +5 -2
- package/src/styles/tailwind.css +9 -2
- package/dist/matter/shipping-address/country-descriptors.d.ts +0 -1
- package/dist/message-locales.json +0 -7
- package/dist/sdk/i18n/client.d.ts +0 -4
- package/dist/sdk/i18n/client.js +0 -4
- package/dist/sdk/i18n/locales.d.ts +0 -8
- package/dist/sdk/i18n/locales.js +0 -57
- package/dist/sdk/i18n/locales.js.map +0 -1
- package/dist/sdk/i18n/messages/en-US.js +0 -164
- package/dist/sdk/i18n/messages/en-US.js.map +0 -1
- package/dist/sdk/i18n/messages/en-US.json +0 -159
- package/dist/sdk/i18n/messages/en-US.json.d.ts +0 -163
- package/dist/sdk/i18n/messages/es-ES.js +0 -164
- package/dist/sdk/i18n/messages/es-ES.js.map +0 -1
- package/dist/sdk/i18n/messages/es-ES.json +0 -159
- package/dist/sdk/i18n/messages/pt-BR.js +0 -164
- package/dist/sdk/i18n/messages/pt-BR.js.map +0 -1
- package/dist/sdk/i18n/messages/pt-BR.json +0 -159
- package/dist/sdk/i18n/provider.d.ts +0 -1
- package/dist/sdk/i18n/provider.js +0 -30
- package/dist/sdk/i18n/provider.js.map +0 -1
- package/dist/sdk/i18n/server.d.ts +0 -28
- package/dist/sdk/i18n/server.js +0 -59
- package/dist/sdk/i18n/server.js.map +0 -1
- package/dist/utils/resolve-authored-copy.js +0 -18
- package/dist/utils/resolve-authored-copy.js.map +0 -1
- package/dist/utils/substitute-template.js +0 -33
- package/dist/utils/substitute-template.js.map +0 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { loggableErrorName } from "../../utils/loggable-error-name.js";
|
|
3
|
+
import { SETTLED_ORDER_FACTS } from "./operations.js";
|
|
4
|
+
import { getApolloContext } from "@apollo/client/react";
|
|
5
|
+
import { useCallback, useContext } from "react";
|
|
6
|
+
//#region src/sdk/payment/resumed-purchase.ts
|
|
7
|
+
/**
|
|
8
|
+
* The `purchase` analytics event for an order that was finished on a second call: the in-page resume
|
|
9
|
+
* that `usePlaceOrder` runs, and the return page the bank sends the shopper to (T208, RFC D23).
|
|
10
|
+
*
|
|
11
|
+
* The attempt record may carry no value or currency (T29 FR-7), and a resume holds no transaction, so
|
|
12
|
+
* both are read from the settled order. Every `purchase` in this package goes through `claimPurchase`,
|
|
13
|
+
* so an order is reported once whichever path finished it.
|
|
14
|
+
*/
|
|
15
|
+
const PURCHASE_MARKER_PREFIX = "fs:purchase-sent:";
|
|
16
|
+
/** Only used when storage cannot be read or written: one page lifetime still reports an order once. */
|
|
17
|
+
const claimedInMemory = /* @__PURE__ */ new Set();
|
|
18
|
+
/**
|
|
19
|
+
* A synchronous check-and-set on `localStorage`, keyed on the order group and holding `1`, never a value, a
|
|
20
|
+
* currency or anything about the shopper. The key is written before the caller emits, so an emission that
|
|
21
|
+
* throws is still never repeated. Two browsers may each report one order once (ruled 2026-10-14); the marker
|
|
22
|
+
* never expires and no server holds it.
|
|
23
|
+
*/
|
|
24
|
+
function claimPurchase(orderGroup) {
|
|
25
|
+
const key = `${PURCHASE_MARKER_PREFIX}${orderGroup}`;
|
|
26
|
+
try {
|
|
27
|
+
if (localStorage.getItem(key) !== null) return false;
|
|
28
|
+
localStorage.setItem(key, "1");
|
|
29
|
+
return true;
|
|
30
|
+
} catch {
|
|
31
|
+
if (claimedInMemory.has(key)) return false;
|
|
32
|
+
claimedInMemory.add(key);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The budget for the settled-order read: a hung read must not hold the shopper on a blank return page. A
|
|
38
|
+
* local race with a cleared timer, mirroring the API's own ten-second default. On expiry nothing is
|
|
39
|
+
* reported and the flow goes on.
|
|
40
|
+
*/
|
|
41
|
+
const SETTLED_ORDER_READ_TIMEOUT_MS = 1e4;
|
|
42
|
+
const ABANDONED = Symbol("abandoned");
|
|
43
|
+
async function readWithinBudget(readOrder, orderNodeId) {
|
|
44
|
+
let timer;
|
|
45
|
+
const deadline = new Promise((resolve) => {
|
|
46
|
+
timer = setTimeout(() => resolve(ABANDONED), SETTLED_ORDER_READ_TIMEOUT_MS);
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
return await Promise.race([readOrder(orderNodeId), deadline]);
|
|
50
|
+
} finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Reads a settled order for the resume paths. `null` without an Apollo client, so a story or a test rendered
|
|
56
|
+
* with no provider has no read and reports no purchase; the client is taken from Apollo's context rather than
|
|
57
|
+
* `useApolloClient()`, which throws without one.
|
|
58
|
+
*/
|
|
59
|
+
function useSettledOrderRead() {
|
|
60
|
+
const { client } = useContext(getApolloContext());
|
|
61
|
+
const read = useCallback(async (orderNodeId) => {
|
|
62
|
+
if (!client) return null;
|
|
63
|
+
const { data } = await client.query({
|
|
64
|
+
query: SETTLED_ORDER_FACTS,
|
|
65
|
+
variables: { id: orderNodeId },
|
|
66
|
+
fetchPolicy: "network-only"
|
|
67
|
+
});
|
|
68
|
+
const order = data?.order;
|
|
69
|
+
if (!order) return null;
|
|
70
|
+
const { reference, status, total } = order;
|
|
71
|
+
return {
|
|
72
|
+
reference,
|
|
73
|
+
status,
|
|
74
|
+
total: total ? {
|
|
75
|
+
amount: total.amount,
|
|
76
|
+
currencyCode: total.currencyCode
|
|
77
|
+
} : null
|
|
78
|
+
};
|
|
79
|
+
}, [client]);
|
|
80
|
+
return client ? read : null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Reports the purchase of an order a resume just finished. Reads the order (under the budget), then emits
|
|
84
|
+
* unless it is `DENIED` or carries no total: an order that failed is not a sale, and one without a total has
|
|
85
|
+
* no value to report. `PENDING` (anti-fraud review) and `UNKNOWN` report, as the direct path reports a
|
|
86
|
+
* placed order without reading its status. The marker is claimed only after those checks, so an order that
|
|
87
|
+
* was not reported is not burned.
|
|
88
|
+
*
|
|
89
|
+
* Never rejects and never throws: the order is finished whether or not the event could be sent, so a read
|
|
90
|
+
* that fails, a tracker that throws or storage that refuses must not change what the shopper sees.
|
|
91
|
+
*/
|
|
92
|
+
async function emitPurchaseForOrder({ track, readOrder, orderNodeId }) {
|
|
93
|
+
if (!track || !readOrder) return;
|
|
94
|
+
let facts;
|
|
95
|
+
try {
|
|
96
|
+
facts = await readWithinBudget(readOrder, orderNodeId);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("[payment.purchase] the settled order could not be read", loggableErrorName(error));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (facts === ABANDONED || facts === null || facts.status === "DENIED" || facts.total === null) return;
|
|
102
|
+
if (!claimPurchase(facts.reference)) return;
|
|
103
|
+
try {
|
|
104
|
+
track({
|
|
105
|
+
name: "purchase",
|
|
106
|
+
transactionId: facts.reference,
|
|
107
|
+
value: {
|
|
108
|
+
amount: Number(facts.total.amount),
|
|
109
|
+
currencyCode: facts.total.currencyCode
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("[payment.purchase] the purchase event could not be sent", loggableErrorName(error));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { SETTLED_ORDER_READ_TIMEOUT_MS, claimPurchase, emitPurchaseForOrder, useSettledOrderRead };
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=resumed-purchase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resumed-purchase.js","names":[],"sources":["../../../src/sdk/payment/resumed-purchase.ts"],"sourcesContent":["'use client';\n\nimport { getApolloContext } from '@apollo/client/react';\nimport { useCallback, useContext } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport type { AnalyticsActions } from '../analytics/use-analytics-actions.js';\nimport { SETTLED_ORDER_FACTS } from './operations.js';\n\n/**\n * The `purchase` analytics event for an order that was finished on a second call: the in-page resume\n * that `usePlaceOrder` runs, and the return page the bank sends the shopper to (T208, RFC D23).\n *\n * The attempt record may carry no value or currency (T29 FR-7), and a resume holds no transaction, so\n * both are read from the settled order. Every `purchase` in this package goes through `claimPurchase`,\n * so an order is reported once whichever path finished it.\n */\n\nconst PURCHASE_MARKER_PREFIX = 'fs:purchase-sent:';\n\n/** Only used when storage cannot be read or written: one page lifetime still reports an order once. */\nconst claimedInMemory = new Set<string>();\n\n/**\n * A synchronous check-and-set on `localStorage`, keyed on the order group and holding `1`, never a value, a\n * currency or anything about the shopper. The key is written before the caller emits, so an emission that\n * throws is still never repeated. Two browsers may each report one order once (ruled 2026-10-14); the marker\n * never expires and no server holds it.\n */\nexport function claimPurchase(orderGroup: string): boolean {\n const key = `${PURCHASE_MARKER_PREFIX}${orderGroup}`;\n try {\n if (localStorage.getItem(key) !== null) return false;\n localStorage.setItem(key, '1');\n return true;\n } catch {\n if (claimedInMemory.has(key)) return false;\n claimedInMemory.add(key);\n return true;\n }\n}\n\nexport type SettledOrderFacts = Readonly<{\n reference: string;\n status: 'APPROVED' | 'PENDING' | 'DENIED' | 'UNKNOWN';\n total: Readonly<{ amount: string; currencyCode: string }> | null;\n}>;\n\nexport type SettledOrderRead = (orderNodeId: string) => Promise<SettledOrderFacts | null>;\n\n/**\n * The budget for the settled-order read: a hung read must not hold the shopper on a blank return page. A\n * local race with a cleared timer, mirroring the API's own ten-second default. On expiry nothing is\n * reported and the flow goes on.\n */\nexport const SETTLED_ORDER_READ_TIMEOUT_MS = 10_000;\n\nconst ABANDONED = Symbol('abandoned');\n\nasync function readWithinBudget(\n readOrder: SettledOrderRead,\n orderNodeId: string,\n): Promise<SettledOrderFacts | null | typeof ABANDONED> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const deadline = new Promise<typeof ABANDONED>((resolve) => {\n timer = setTimeout(() => resolve(ABANDONED), SETTLED_ORDER_READ_TIMEOUT_MS);\n });\n try {\n return await Promise.race([readOrder(orderNodeId), deadline]);\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Reads a settled order for the resume paths. `null` without an Apollo client, so a story or a test rendered\n * with no provider has no read and reports no purchase; the client is taken from Apollo's context rather than\n * `useApolloClient()`, which throws without one.\n */\nexport function useSettledOrderRead(): SettledOrderRead | null {\n const { client } = useContext(getApolloContext());\n\n const read = useCallback<SettledOrderRead>(\n async (orderNodeId) => {\n if (!client) return null;\n const { data } = await client.query({\n query: SETTLED_ORDER_FACTS,\n variables: { id: orderNodeId },\n fetchPolicy: 'network-only',\n });\n const order = data?.order;\n if (!order) return null;\n const { reference, status, total } = order;\n return {\n reference,\n status,\n total: total ? { amount: total.amount, currencyCode: total.currencyCode } : null,\n };\n },\n [client],\n );\n\n return client ? read : null;\n}\n\n/**\n * Reports the purchase of an order a resume just finished. Reads the order (under the budget), then emits\n * unless it is `DENIED` or carries no total: an order that failed is not a sale, and one without a total has\n * no value to report. `PENDING` (anti-fraud review) and `UNKNOWN` report, as the direct path reports a\n * placed order without reading its status. The marker is claimed only after those checks, so an order that\n * was not reported is not burned.\n *\n * Never rejects and never throws: the order is finished whether or not the event could be sent, so a read\n * that fails, a tracker that throws or storage that refuses must not change what the shopper sees.\n */\nexport async function emitPurchaseForOrder({\n track,\n readOrder,\n orderNodeId,\n}: {\n track: AnalyticsActions['track'] | null | undefined;\n readOrder: SettledOrderRead | null | undefined;\n orderNodeId: string;\n}): Promise<void> {\n if (!track || !readOrder) return;\n\n let facts: SettledOrderFacts | null | typeof ABANDONED;\n try {\n facts = await readWithinBudget(readOrder, orderNodeId);\n } catch (error) {\n console.error('[payment.purchase] the settled order could not be read', loggableErrorName(error));\n return;\n }\n if (facts === ABANDONED || facts === null || facts.status === 'DENIED' || facts.total === null) return;\n\n if (!claimPurchase(facts.reference)) return;\n try {\n track({\n name: 'purchase',\n transactionId: facts.reference,\n value: { amount: Number(facts.total.amount), currencyCode: facts.total.currencyCode },\n });\n } catch (error) {\n console.error('[payment.purchase] the purchase event could not be sent', loggableErrorName(error));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAM,yBAAyB;;AAG/B,MAAM,kCAAkB,IAAI,IAAY;;;;;;;AAQxC,SAAgB,cAAc,YAA6B;CACzD,MAAM,MAAM,GAAG,yBAAyB;CACxC,IAAI;EACF,IAAI,aAAa,QAAQ,GAAG,MAAM,MAAM,OAAO;EAC/C,aAAa,QAAQ,KAAK,GAAG;EAC7B,OAAO;CACT,QAAQ;EACN,IAAI,gBAAgB,IAAI,GAAG,GAAG,OAAO;EACrC,gBAAgB,IAAI,GAAG;EACvB,OAAO;CACT;AACF;;;;;;AAeA,MAAa,gCAAgC;AAE7C,MAAM,YAAY,OAAO,WAAW;AAEpC,eAAe,iBACb,WACA,aACsD;CACtD,IAAI;CACJ,MAAM,WAAW,IAAI,SAA2B,YAAY;EAC1D,QAAQ,iBAAiB,QAAQ,SAAS,GAAG,6BAA6B;CAC5E,CAAC;CACD,IAAI;EACF,OAAO,MAAM,QAAQ,KAAK,CAAC,UAAU,WAAW,GAAG,QAAQ,CAAC;CAC9D,UAAU;EACR,aAAa,KAAK;CACpB;AACF;;;;;;AAOA,SAAgB,sBAA+C;CAC7D,MAAM,EAAE,WAAW,WAAW,iBAAiB,CAAC;CAEhD,MAAM,OAAO,YACX,OAAO,gBAAgB;EACrB,IAAI,CAAC,QAAQ,OAAO;EACpB,MAAM,EAAE,SAAS,MAAM,OAAO,MAAM;GAClC,OAAO;GACP,WAAW,EAAE,IAAI,YAAY;GAC7B,aAAa;EACf,CAAC;EACD,MAAM,QAAQ,MAAM;EACpB,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,EAAE,WAAW,QAAQ,UAAU;EACrC,OAAO;GACL;GACA;GACA,OAAO,QAAQ;IAAE,QAAQ,MAAM;IAAQ,cAAc,MAAM;GAAa,IAAI;EAC9E;CACF,GACA,CAAC,MAAM,CACT;CAEA,OAAO,SAAS,OAAO;AACzB;;;;;;;;;;;AAYA,eAAsB,qBAAqB,EACzC,OACA,WACA,eAKgB;CAChB,IAAI,CAAC,SAAS,CAAC,WAAW;CAE1B,IAAI;CACJ,IAAI;EACF,QAAQ,MAAM,iBAAiB,WAAW,WAAW;CACvD,SAAS,OAAO;EACd,QAAQ,MAAM,0DAA0D,kBAAkB,KAAK,CAAC;EAChG;CACF;CACA,IAAI,UAAU,aAAa,UAAU,QAAQ,MAAM,WAAW,YAAY,MAAM,UAAU,MAAM;CAEhG,IAAI,CAAC,cAAc,MAAM,SAAS,GAAG;CACrC,IAAI;EACF,MAAM;GACJ,MAAM;GACN,eAAe,MAAM;GACrB,OAAO;IAAE,QAAQ,OAAO,MAAM,MAAM,MAAM;IAAG,cAAc,MAAM,MAAM;GAAa;EACtF,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,2DAA2D,kBAAkB,KAAK,CAAC;CACnG;AACF"}
|
|
@@ -39,33 +39,26 @@
|
|
|
39
39
|
*/
|
|
40
40
|
const SECURITY_CODE_MASK_STYLE = Object.freeze({ WebkitTextSecurity: "disc" });
|
|
41
41
|
/**
|
|
42
|
-
* Whether the security code is
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* the code.
|
|
42
|
+
* Whether the security code is obscured: while it is non-empty and its input does not have focus
|
|
43
|
+
* (specs/stop-sending-a-stale-non-displayable-cardholder.md, T34, reversing the T173 timing that
|
|
44
|
+
* obscured a code the instant its last digit arrived). A shopper who is still in the field can read
|
|
45
|
+
* back what they typed and catch a typo; the moment focus leaves, nothing is left legible. The
|
|
46
|
+
* mechanism is untouched; only its timing moves.
|
|
48
47
|
*
|
|
49
|
-
* `
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* own three-or-four-digit floor. Resolving it here would mean knowing about payment-method validators
|
|
53
|
-
* and saved-card rows, and would still leave the comparison itself free to drift between the two.
|
|
48
|
+
* `focused` is passed in already folded with whatever else disables the input: a browser fires no
|
|
49
|
+
* `blur` when a focused element becomes disabled, so each caller counts a disabled input as
|
|
50
|
+
* unfocused. This function knows nothing about `disabled`.
|
|
54
51
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* the
|
|
59
|
-
*
|
|
60
|
-
* Derived from the value on every render, with no state and no timer. That is what makes the render
|
|
61
|
-
* which first holds a complete code already the masked one — so a paste delivering every digit in one
|
|
62
|
-
* event opens no legible frame — lets a cleared field unmask with nothing to reset, and leaves a code
|
|
63
|
-
* the shopper backspaces into legible again while they correct it.
|
|
52
|
+
* Derived from the value and the focus flag on every render, never from an effect or a timer. That
|
|
53
|
+
* is what makes the render which first holds an unfocused code already the masked one — so a paste or
|
|
54
|
+
* a browser autofill delivering every digit in one event, and the blur itself, open no legible frame.
|
|
55
|
+
* The length of the code plays no part: the mask no longer needs a per-network or per-field length,
|
|
56
|
+
* and a partial code is hidden on blur like a complete one.
|
|
64
57
|
*/
|
|
65
|
-
function
|
|
66
|
-
return value.length > 0 &&
|
|
58
|
+
function isSecurityCodeMasked(value, focused) {
|
|
59
|
+
return value.length > 0 && !focused;
|
|
67
60
|
}
|
|
68
61
|
//#endregion
|
|
69
|
-
export { SECURITY_CODE_MASK_STYLE,
|
|
62
|
+
export { SECURITY_CODE_MASK_STYLE, isSecurityCodeMasked };
|
|
70
63
|
|
|
71
64
|
//# sourceMappingURL=security-code-mask.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-code-mask.js","names":[],"sources":["../../../src/sdk/payment/security-code-mask.ts"],"sourcesContent":["import type { CSSProperties } from 'react';\n\n/**\n * The security-code masking mechanism (specs/choose-a-security-code-masking-mechanism.md, T101 of\n * the Credit Card epic; docs/features/credit-card/rfc.md § D13). One shared constant for the two\n * inputs that hold a security code — `CardEntry`'s `cvv` field and `SavedCardCvvField`'s CVV\n * re-entry field — so the two call sites cannot drift on the mechanism.\n *\n * Why this and not `type=\"password\"`: T70 shipped `type=\"password\"` on both fields and it made real\n * Chrome offer a \"Save password?\" prompt on the new-card form — pairing the expiration date as a\n * fake *Username* and the security code as *Password*, and offering to store it in Google Password\n * Manager, synced to the signed-in account. PCI-DSS forbids retaining the security code past\n * authorization, and a cloud-synced credential vault is a strictly worse posture than the field's\n * pre-T70 baseline. `type=\"password\"` was reverted; both fields ship `type=\"text\"`.\n *\n * `-webkit-text-security: disc` obscures the digits on screen without touching `type`, so the\n * heuristic that triggered the prompt (keyed off `type=\"password\"` fields in the form) never fires —\n * settled by the 2026-08-24 unblock ruling through measurement in real Chrome, not documentation.\n * Applied as an **element inline style**, never a stylesheet the package ships (forbidden by\n * ADR-0007's Consequences, `:104`) and never a class a store authors (defeatable by any compound\n * swatch) — an inline declaration is the one CSS route that is both within the architecture rule and\n * outside the store's reach, and it outranks every class-based rule at normal importance.\n *\n * This closes the password-manager capture surface structurally — it does not mean the code never\n * leaves the browser by any path. `CardEntry`'s CVV keeps `autoComplete=\"cc-csc\"` (FR-5, unchanged by\n * this task): the exact token Chrome's own Autofill uses to classify the field as\n * `CREDIT_CARD_VERIFICATION_CODE`, and Chrome ships CVC storage (`AutofillEnableCvcStorageAndFilling`)\n * that retains the CVC beside a saved server card and syncs it to the signed-in Google account. This\n * mechanism does not close that path and is not trying to — it is the separate *card* vault the field\n * honestly declares itself to via `autoComplete`, not the credential vault this change removes (spec\n * § Verification, G1(d)).\n *\n * `WebkitTextSecurity` is asserted `as CSSProperties` because csstype 3.2.3 declares no such key —\n * mirrors the existing assertion in `variant-selector.tsx`. The property is standardized nowhere;\n * supported in Chromium and WebKit (and Firefox 114+, per T70's spec). An engine without it renders\n * exactly what ships today — not a regression.\n *\n * Defined once at module scope so the object is referentially stable and React's style diffing never\n * has work to do on re-render.\n */\nexport const SECURITY_CODE_MASK_STYLE: CSSProperties = Object.freeze({ WebkitTextSecurity: 'disc' }) as CSSProperties;\n\n/**\n * Whether the security code is
|
|
1
|
+
{"version":3,"file":"security-code-mask.js","names":[],"sources":["../../../src/sdk/payment/security-code-mask.ts"],"sourcesContent":["import type { CSSProperties } from 'react';\n\n/**\n * The security-code masking mechanism (specs/choose-a-security-code-masking-mechanism.md, T101 of\n * the Credit Card epic; docs/features/credit-card/rfc.md § D13). One shared constant for the two\n * inputs that hold a security code — `CardEntry`'s `cvv` field and `SavedCardCvvField`'s CVV\n * re-entry field — so the two call sites cannot drift on the mechanism.\n *\n * Why this and not `type=\"password\"`: T70 shipped `type=\"password\"` on both fields and it made real\n * Chrome offer a \"Save password?\" prompt on the new-card form — pairing the expiration date as a\n * fake *Username* and the security code as *Password*, and offering to store it in Google Password\n * Manager, synced to the signed-in account. PCI-DSS forbids retaining the security code past\n * authorization, and a cloud-synced credential vault is a strictly worse posture than the field's\n * pre-T70 baseline. `type=\"password\"` was reverted; both fields ship `type=\"text\"`.\n *\n * `-webkit-text-security: disc` obscures the digits on screen without touching `type`, so the\n * heuristic that triggered the prompt (keyed off `type=\"password\"` fields in the form) never fires —\n * settled by the 2026-08-24 unblock ruling through measurement in real Chrome, not documentation.\n * Applied as an **element inline style**, never a stylesheet the package ships (forbidden by\n * ADR-0007's Consequences, `:104`) and never a class a store authors (defeatable by any compound\n * swatch) — an inline declaration is the one CSS route that is both within the architecture rule and\n * outside the store's reach, and it outranks every class-based rule at normal importance.\n *\n * This closes the password-manager capture surface structurally — it does not mean the code never\n * leaves the browser by any path. `CardEntry`'s CVV keeps `autoComplete=\"cc-csc\"` (FR-5, unchanged by\n * this task): the exact token Chrome's own Autofill uses to classify the field as\n * `CREDIT_CARD_VERIFICATION_CODE`, and Chrome ships CVC storage (`AutofillEnableCvcStorageAndFilling`)\n * that retains the CVC beside a saved server card and syncs it to the signed-in Google account. This\n * mechanism does not close that path and is not trying to — it is the separate *card* vault the field\n * honestly declares itself to via `autoComplete`, not the credential vault this change removes (spec\n * § Verification, G1(d)).\n *\n * `WebkitTextSecurity` is asserted `as CSSProperties` because csstype 3.2.3 declares no such key —\n * mirrors the existing assertion in `variant-selector.tsx`. The property is standardized nowhere;\n * supported in Chromium and WebKit (and Firefox 114+, per T70's spec). An engine without it renders\n * exactly what ships today — not a regression.\n *\n * Defined once at module scope so the object is referentially stable and React's style diffing never\n * has work to do on re-render.\n */\nexport const SECURITY_CODE_MASK_STYLE: CSSProperties = Object.freeze({ WebkitTextSecurity: 'disc' }) as CSSProperties;\n\n/**\n * Whether the security code is obscured: while it is non-empty and its input does not have focus\n * (specs/stop-sending-a-stale-non-displayable-cardholder.md, T34, reversing the T173 timing that\n * obscured a code the instant its last digit arrived). A shopper who is still in the field can read\n * back what they typed and catch a typo; the moment focus leaves, nothing is left legible. The\n * mechanism is untouched; only its timing moves.\n *\n * `focused` is passed in already folded with whatever else disables the input: a browser fires no\n * `blur` when a focused element becomes disabled, so each caller counts a disabled input as\n * unfocused. This function knows nothing about `disabled`.\n *\n * Derived from the value and the focus flag on every render, never from an effect or a timer. That\n * is what makes the render which first holds an unfocused code already the masked one — so a paste or\n * a browser autofill delivering every digit in one event, and the blur itself, open no legible frame.\n * The length of the code plays no part: the mask no longer needs a per-network or per-field length,\n * and a partial code is hidden on blur like a complete one.\n */\nexport function isSecurityCodeMasked(value: string, focused: boolean): boolean {\n return value.length > 0 && !focused;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAa,2BAA0C,OAAO,OAAO,EAAE,oBAAoB,OAAO,CAAC;;;;;;;;;;;;;;;;;;AAmBnG,SAAgB,qBAAqB,OAAe,SAA2B;CAC7E,OAAO,MAAM,SAAS,KAAK,CAAC;AAC9B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext, useContext,
|
|
2
|
+
import { createContext, useContext, useLayoutEffect, useMemo, useRef } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
//#region src/sdk/payment/submission-registry.tsx
|
|
5
5
|
const SUBMISSION_CONTEXT_UNSET = Symbol("PaymentSubmissionContextUnset");
|
|
@@ -45,10 +45,14 @@ function usePaymentSubmission() {
|
|
|
45
45
|
* `path`, and unregisters on unmount or on any argument
|
|
46
46
|
* changing, so the map always holds the latest closures over the holder's card fields — a stale one
|
|
47
47
|
* would pay with the previous keystroke's CVV.
|
|
48
|
+
*
|
|
49
|
+
* Registration runs in the layout phase: before paint and before any passive effect of the commit.
|
|
50
|
+
* A render that no discrete event caused (an async mutation response, a timer) can be clicked on
|
|
51
|
+
* before its passive effects flush, and the click would then resolve the previous commit's closure.
|
|
48
52
|
*/
|
|
49
53
|
function useRegisterPaymentSubmission(path, submit, preflight, explainMissingMethod) {
|
|
50
54
|
const { register } = usePaymentSubmission();
|
|
51
|
-
|
|
55
|
+
useLayoutEffect(() => register(path, submit, preflight, explainMissingMethod), [
|
|
52
56
|
register,
|
|
53
57
|
path,
|
|
54
58
|
submit,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submission-registry.js","names":[],"sources":["../../../src/sdk/payment/submission-registry.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, type ReactNode, useContext, useEffect, useMemo, useRef } from 'react';\nimport type { PaymentGatewayResult, PaymentGatewayTransaction } from './gateway.js';\nimport type { PaymentUserError } from './operations.js';\n\n/**\n * The card-data submission channel (specs/use-place-order.md, Decision 1; specs/epics/credit-card.md\n * § \"The card-data submission channel\"). **The holder submits; the orchestrator never holds.**\n *\n * T7 (new card) and T12 (saved card) each register a submit-time continuation here. Each closes over\n * its own card fields, builds the gateway card object inside that closure, calls\n * `$actions.payment.sendPayments` itself, and returns only the gateway leg's result: its `userErrors` and\n * whether a request reached the gateway (T112). T13's\n * `usePlaceOrder` resolves one by `path` and invokes it between start-transaction and\n * gateway-callback, so no card-shaped field appears anywhere in this channel's type signature.\n *\n * It is a *second*, narrow context beside T5's `payment` context rather than a field on it, because\n * the two have different shapes and different readers: `draft` is render state every leaf reads, this\n * is an imperative registry exactly two components write and one hook reads. Registration is a\n * ref-held `Map`, not state — T7 re-registers a fresh closure on every keystroke, and making that a\n * render would re-render the whole payment section per character.\n *\n * Values that are **not** sensitive travel on T5's `draft`, never here: the save-card flag and label\n * (T10), the cardholder document (T8), and the billing-address-differs flag (T11). The holder folds\n * them into the card object inside its own closure.\n *\n * This module lives in the SDK rather than beside T5's roots so the layering stays `matter → sdk`:\n * `usePlaceOrder` is an SDK hook and cannot import from `matter/`. \"Provided by T5's root\" means the\n * root renders `PaymentSubmissionProvider`, which it does — both of them, for the same ADR-0009\n * reason the `payment` context has two providers.\n */\n\n/** Which entry path a submission serves. The canonical key type; T5's `PaymentPath` aliases it. */\nexport type PaymentSubmissionPath = 'new-card' | 'saved-card';\n\n/**\n * What a continuation resolves (T112): the gateway leg's `userErrors` (empty on success) and\n * `reachedGateway`, which is `false` only when the holder can show it refused before issuing any\n * request. `usePlaceOrder` frees the attempt for exactly that case and locks it for every other one,\n * including a missing or non-boolean flag. Defined by the producer, `gateway.ts`; re-exported here so the\n * hook imports it from this module and keeps `./gateway.js` to the transaction type alone.\n */\nexport type PaymentSubmissionResult = PaymentGatewayResult;\n\n/**\n * A holder's submit-time continuation — the whole channel. It takes the non-sensitive transaction\n * descriptor and resolves a `PaymentSubmissionResult`. It must not log, serialize, or return the card.\n */\nexport type PaymentSubmission = (transaction: PaymentGatewayTransaction) => Promise<PaymentSubmissionResult>;\n\n/**\n * A holder's pre-flight verdict on its own draft, resolved before any transaction opens (T27,\n * specs/place-order-preflight-card-validation.md). Returns the refusals that would make this\n * submission pointless, or an empty array to proceed. Synchronous by contract (Decision 6): a holder\n * validates what it already holds and performs no I/O.\n *\n * Card-free by the same rule the submission itself follows — it returns `PaymentUserError`s and never\n * the fields it inspected. It may have side effects inside its own component (rendering field errors,\n * moving focus); that is the half a value-shaped gate cannot carry.\n */\nexport type PaymentPreflightCheck = () => readonly PaymentUserError[];\n\n/**\n * A holder's explanation of why no payment method is selected (T47, specs/distinguish-a-pan-that-\n * matches-no-configured.md, Decision 2/4/5). Consulted only by `usePlaceOrder`'s method step, and only\n * when nothing is selected, so it can never reorder the checks. Returns the refusal to show in place of\n * the generic missing-method one, or `null` when the holder has nothing more specific to say.\n *\n * Synchronous and side-effect-free, unlike the pre-flight: it returns a value and touches nothing in its\n * own component. Fixed copy and a fixed code only — it must never echo anything the shopper typed.\n */\nexport type PaymentMissingMethodExplainer = () => PaymentUserError | null;\n\n/** One path's registration. `preflight` and `explainMissingMethod` are `null` when its holder registered none (FR-6). */\ntype PaymentSubmissionEntry = Readonly<{\n submit: PaymentSubmission;\n preflight: PaymentPreflightCheck | null;\n explainMissingMethod: PaymentMissingMethodExplainer | null;\n}>;\n\nexport type PaymentSubmissionChannel = Readonly<{\n /**\n * The entry path the shopper is on — T5's `draft.path`, mirrored here so the place-order sequence\n * resolves it without reading the matter context. One-way and derived: the root passes it through\n * on every render.\n */\n path: PaymentSubmissionPath | null;\n /**\n * Registers (or replaces) the continuation, and optionally its pre-flight check and its missing-method\n * explainer, for a path. Returns its unregister function.\n */\n register: (\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n ) => () => void;\n /** Unchanged: the continuation registered for a path, or `null` when its holder is not composed or unmounted. */\n resolve: (path: PaymentSubmissionPath) => PaymentSubmission | null;\n /** The pre-flight check registered for a path, or `null` when its holder registered none. */\n resolvePreflight: (path: PaymentSubmissionPath) => PaymentPreflightCheck | null;\n /** The missing-method explainer registered for a path, or `null` when its holder registered none (T47). */\n resolveMissingMethodExplainer: (path: PaymentSubmissionPath) => PaymentMissingMethodExplainer | null;\n}>;\n\nconst SUBMISSION_CONTEXT_UNSET = Symbol('PaymentSubmissionContextUnset');\n\nconst PaymentSubmissionContext = createContext<PaymentSubmissionChannel | typeof SUBMISSION_CONTEXT_UNSET>(\n SUBMISSION_CONTEXT_UNSET,\n);\n\nexport type PaymentSubmissionProviderProps = Readonly<{\n /** T5's `draft.path`. */\n path: PaymentSubmissionPath | null;\n children: ReactNode;\n}>;\n\n/** Rendered by `PaymentSectionRoot` and `PaymentSectionController` around the section composition. */\nexport function PaymentSubmissionProvider({ path, children }: PaymentSubmissionProviderProps) {\n const submissions = useRef(new Map<PaymentSubmissionPath, PaymentSubmissionEntry>());\n\n const channel = useMemo<PaymentSubmissionChannel>(\n () => ({\n path,\n register: (registeredPath, submit, preflight, explainMissingMethod) => {\n submissions.current.set(registeredPath, {\n submit,\n preflight: preflight ?? null,\n explainMissingMethod: explainMissingMethod ?? null,\n });\n return () => {\n // Delete only if this registration is still the one on file: a Map holds one entry per\n // path, so an unmounting holder whose registration was already superseded by a still-mounted\n // sibling under the same path must not wipe that sibling's live continuation (or its check).\n if (submissions.current.get(registeredPath)?.submit === submit) {\n submissions.current.delete(registeredPath);\n }\n };\n },\n resolve: (registeredPath) => submissions.current.get(registeredPath)?.submit ?? null,\n resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null,\n resolveMissingMethodExplainer: (registeredPath) =>\n submissions.current.get(registeredPath)?.explainMissingMethod ?? null,\n }),\n [path],\n );\n\n return <PaymentSubmissionContext value={channel}>{children}</PaymentSubmissionContext>;\n}\n\n/**\n * Read the submission channel from the nearest `PaymentSectionRoot` or `PaymentSectionController`.\n * Throws outside either subtree, mirroring `usePayment()`: a misplaced holder or CTA is a composition\n * bug the author should see immediately. Distinct from the two *runtime* states — no path chosen, no\n * continuation registered — which `usePlaceOrder` resolves as a userError.\n */\nexport function usePaymentSubmission(): PaymentSubmissionChannel {\n const channel = useContext(PaymentSubmissionContext);\n if (channel === SUBMISSION_CONTEXT_UNSET) {\n throw new Error(\n 'usePaymentSubmission() must be used inside a <PaymentSectionRoot> or <PaymentSectionController> subtree.',\n );\n }\n return channel;\n}\n\n/**\n * The holder-facing signature (T7, T12; `preflight` added by T27, `explainMissingMethod` by T47).\n * Registers `submit` — and, optionally, its pre-flight check and its missing-method explainer — for\n * `path`, and unregisters on unmount or on any argument\n * changing, so the map always holds the latest closures over the holder's card fields — a stale one\n * would pay with the previous keystroke's CVV.\n */\nexport function useRegisterPaymentSubmission(\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n): void {\n const { register } = usePaymentSubmission();\n\n useEffect(\n () => register(path, submit, preflight, explainMissingMethod),\n [register, path, submit, preflight, explainMissingMethod],\n );\n}\n"],"mappings":";;;;AA0GA,MAAM,2BAA2B,OAAO,+BAA+B;AAEvE,MAAM,2BAA2B,cAC/B,wBACF;;AASA,SAAgB,0BAA0B,EAAE,MAAM,YAA4C;CAC5F,MAAM,cAAc,uBAAO,IAAI,IAAmD,CAAC;CAEnF,MAAM,UAAU,eACP;EACL;EACA,WAAW,gBAAgB,QAAQ,WAAW,yBAAyB;GACrE,YAAY,QAAQ,IAAI,gBAAgB;IACtC;IACA,WAAW,aAAa;IACxB,sBAAsB,wBAAwB;GAChD,CAAC;GACD,aAAa;IAIX,IAAI,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,WAAW,QACtD,YAAY,QAAQ,OAAO,cAAc;GAE7C;EACF;EACA,UAAU,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,UAAU;EAChF,mBAAmB,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,aAAa;EAC5F,gCAAgC,mBAC9B,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,wBAAwB;CACrE,IACA,CAAC,IAAI,CACP;CAEA,OAAO,oBAAC,0BAAD;EAA0B,OAAO;EAAU;CAAmC,CAAA;AACvF;;;;;;;AAQA,SAAgB,uBAAiD;CAC/D,MAAM,UAAU,WAAW,wBAAwB;CACnD,IAAI,YAAY,0BACd,MAAM,IAAI,MACR,0GACF;CAEF,OAAO;AACT;;;;;;;;AASA,SAAgB,6BACd,MACA,QACA,WACA,sBACM;CACN,MAAM,EAAE,aAAa,qBAAqB;CAE1C,gBACQ,SAAS,MAAM,QAAQ,WAAW,oBAAoB,GAC5D;EAAC;EAAU;EAAM;EAAQ;EAAW;CAAoB,CAC1D;AACF"}
|
|
1
|
+
{"version":3,"file":"submission-registry.js","names":[],"sources":["../../../src/sdk/payment/submission-registry.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, type ReactNode, useContext, useLayoutEffect, useMemo, useRef } from 'react';\nimport type { PaymentGatewayResult, PaymentGatewayTransaction } from './gateway.js';\nimport type { PaymentUserError } from './operations.js';\n\n/**\n * The card-data submission channel (specs/use-place-order.md, Decision 1; specs/epics/credit-card.md\n * § \"The card-data submission channel\"). **The holder submits; the orchestrator never holds.**\n *\n * T7 (new card) and T12 (saved card) each register a submit-time continuation here. Each closes over\n * its own card fields, builds the gateway card object inside that closure, calls\n * `$actions.payment.sendPayments` itself, and returns only the gateway leg's result: its `userErrors` and\n * whether a request reached the gateway (T112). T13's\n * `usePlaceOrder` resolves one by `path` and invokes it between start-transaction and\n * gateway-callback, so no card-shaped field appears anywhere in this channel's type signature.\n *\n * It is a *second*, narrow context beside T5's `payment` context rather than a field on it, because\n * the two have different shapes and different readers: `draft` is render state every leaf reads, this\n * is an imperative registry exactly two components write and one hook reads. Registration is a\n * ref-held `Map`, not state — T7 re-registers a fresh closure on every keystroke, and making that a\n * render would re-render the whole payment section per character.\n *\n * Values that are **not** sensitive travel on T5's `draft`, never here: the save-card flag and label\n * (T10), the cardholder document (T8), and the billing-address-differs flag (T11). The holder folds\n * them into the card object inside its own closure.\n *\n * This module lives in the SDK rather than beside T5's roots so the layering stays `matter → sdk`:\n * `usePlaceOrder` is an SDK hook and cannot import from `matter/`. \"Provided by T5's root\" means the\n * root renders `PaymentSubmissionProvider`, which it does — both of them, for the same ADR-0009\n * reason the `payment` context has two providers.\n */\n\n/** Which entry path a submission serves. The canonical key type; T5's `PaymentPath` aliases it. */\nexport type PaymentSubmissionPath = 'new-card' | 'saved-card';\n\n/**\n * What a continuation resolves (T112): the gateway leg's `userErrors` (empty on success) and\n * `reachedGateway`, which is `false` only when the holder can show it refused before issuing any\n * request. `usePlaceOrder` frees the attempt for exactly that case and locks it for every other one,\n * including a missing or non-boolean flag. Defined by the producer, `gateway.ts`; re-exported here so the\n * hook imports it from this module and keeps `./gateway.js` to the transaction type alone.\n */\nexport type PaymentSubmissionResult = PaymentGatewayResult &\n Readonly<{\n /**\n * `true` only from a holder whose order is placed by Start Transaction alone, so the gateway leg and its\n * callback never run (T39). Read as `=== true`, and only with an empty `userErrors`: anything else keeps\n * the callback leg.\n */\n completesWithoutGateway?: boolean;\n }>;\n\n/**\n * A holder's submit-time continuation — the whole channel. It takes the non-sensitive transaction\n * descriptor and resolves a `PaymentSubmissionResult`. It must not log, serialize, or return the card.\n */\nexport type PaymentSubmission = (transaction: PaymentGatewayTransaction) => Promise<PaymentSubmissionResult>;\n\n/**\n * A holder's pre-flight verdict on its own draft, resolved before any transaction opens (T27,\n * specs/place-order-preflight-card-validation.md). Returns the refusals that would make this\n * submission pointless, or an empty array to proceed. Synchronous by contract (Decision 6): a holder\n * validates what it already holds and performs no I/O.\n *\n * Card-free by the same rule the submission itself follows — it returns `PaymentUserError`s and never\n * the fields it inspected. It may have side effects inside its own component (rendering field errors,\n * moving focus); that is the half a value-shaped gate cannot carry.\n */\nexport type PaymentPreflightCheck = () => readonly PaymentUserError[];\n\n/**\n * A holder's explanation of why no payment method is selected (T47, specs/distinguish-a-pan-that-\n * matches-no-configured.md, Decision 2/4/5). Consulted only by `usePlaceOrder`'s method step, and only\n * when nothing is selected, so it can never reorder the checks. Returns the refusal to show in place of\n * the generic missing-method one, or `null` when the holder has nothing more specific to say.\n *\n * Synchronous and side-effect-free, unlike the pre-flight: it returns a value and touches nothing in its\n * own component. Fixed copy and a fixed code only — it must never echo anything the shopper typed.\n */\nexport type PaymentMissingMethodExplainer = () => PaymentUserError | null;\n\n/** One path's registration. `preflight` and `explainMissingMethod` are `null` when its holder registered none (FR-6). */\ntype PaymentSubmissionEntry = Readonly<{\n submit: PaymentSubmission;\n preflight: PaymentPreflightCheck | null;\n explainMissingMethod: PaymentMissingMethodExplainer | null;\n}>;\n\nexport type PaymentSubmissionChannel = Readonly<{\n /**\n * The entry path the shopper is on — T5's `draft.path`, mirrored here so the place-order sequence\n * resolves it without reading the matter context. One-way and derived: the root passes it through\n * on every render.\n */\n path: PaymentSubmissionPath | null;\n /**\n * Registers (or replaces) the continuation, and optionally its pre-flight check and its missing-method\n * explainer, for a path. Returns its unregister function.\n */\n register: (\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n ) => () => void;\n /** Unchanged: the continuation registered for a path, or `null` when its holder is not composed or unmounted. */\n resolve: (path: PaymentSubmissionPath) => PaymentSubmission | null;\n /** The pre-flight check registered for a path, or `null` when its holder registered none. */\n resolvePreflight: (path: PaymentSubmissionPath) => PaymentPreflightCheck | null;\n /** The missing-method explainer registered for a path, or `null` when its holder registered none (T47). */\n resolveMissingMethodExplainer: (path: PaymentSubmissionPath) => PaymentMissingMethodExplainer | null;\n}>;\n\nconst SUBMISSION_CONTEXT_UNSET = Symbol('PaymentSubmissionContextUnset');\n\nconst PaymentSubmissionContext = createContext<PaymentSubmissionChannel | typeof SUBMISSION_CONTEXT_UNSET>(\n SUBMISSION_CONTEXT_UNSET,\n);\n\nexport type PaymentSubmissionProviderProps = Readonly<{\n /** T5's `draft.path`. */\n path: PaymentSubmissionPath | null;\n children: ReactNode;\n}>;\n\n/** Rendered by `PaymentSectionRoot` and `PaymentSectionController` around the section composition. */\nexport function PaymentSubmissionProvider({ path, children }: PaymentSubmissionProviderProps) {\n const submissions = useRef(new Map<PaymentSubmissionPath, PaymentSubmissionEntry>());\n\n const channel = useMemo<PaymentSubmissionChannel>(\n () => ({\n path,\n register: (registeredPath, submit, preflight, explainMissingMethod) => {\n submissions.current.set(registeredPath, {\n submit,\n preflight: preflight ?? null,\n explainMissingMethod: explainMissingMethod ?? null,\n });\n return () => {\n // Delete only if this registration is still the one on file: a Map holds one entry per\n // path, so an unmounting holder whose registration was already superseded by a still-mounted\n // sibling under the same path must not wipe that sibling's live continuation (or its check).\n if (submissions.current.get(registeredPath)?.submit === submit) {\n submissions.current.delete(registeredPath);\n }\n };\n },\n resolve: (registeredPath) => submissions.current.get(registeredPath)?.submit ?? null,\n resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null,\n resolveMissingMethodExplainer: (registeredPath) =>\n submissions.current.get(registeredPath)?.explainMissingMethod ?? null,\n }),\n [path],\n );\n\n return <PaymentSubmissionContext value={channel}>{children}</PaymentSubmissionContext>;\n}\n\n/**\n * Read the submission channel from the nearest `PaymentSectionRoot` or `PaymentSectionController`.\n * Throws outside either subtree, mirroring `usePayment()`: a misplaced holder or CTA is a composition\n * bug the author should see immediately. Distinct from the two *runtime* states — no path chosen, no\n * continuation registered — which `usePlaceOrder` resolves as a userError.\n */\nexport function usePaymentSubmission(): PaymentSubmissionChannel {\n const channel = useContext(PaymentSubmissionContext);\n if (channel === SUBMISSION_CONTEXT_UNSET) {\n throw new Error(\n 'usePaymentSubmission() must be used inside a <PaymentSectionRoot> or <PaymentSectionController> subtree.',\n );\n }\n return channel;\n}\n\n/**\n * The holder-facing signature (T7, T12; `preflight` added by T27, `explainMissingMethod` by T47).\n * Registers `submit` — and, optionally, its pre-flight check and its missing-method explainer — for\n * `path`, and unregisters on unmount or on any argument\n * changing, so the map always holds the latest closures over the holder's card fields — a stale one\n * would pay with the previous keystroke's CVV.\n *\n * Registration runs in the layout phase: before paint and before any passive effect of the commit.\n * A render that no discrete event caused (an async mutation response, a timer) can be clicked on\n * before its passive effects flush, and the click would then resolve the previous commit's closure.\n */\nexport function useRegisterPaymentSubmission(\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n): void {\n const { register } = usePaymentSubmission();\n\n useLayoutEffect(\n () => register(path, submit, preflight, explainMissingMethod),\n [register, path, submit, preflight, explainMissingMethod],\n );\n}\n"],"mappings":";;;;AAkHA,MAAM,2BAA2B,OAAO,+BAA+B;AAEvE,MAAM,2BAA2B,cAC/B,wBACF;;AASA,SAAgB,0BAA0B,EAAE,MAAM,YAA4C;CAC5F,MAAM,cAAc,uBAAO,IAAI,IAAmD,CAAC;CAEnF,MAAM,UAAU,eACP;EACL;EACA,WAAW,gBAAgB,QAAQ,WAAW,yBAAyB;GACrE,YAAY,QAAQ,IAAI,gBAAgB;IACtC;IACA,WAAW,aAAa;IACxB,sBAAsB,wBAAwB;GAChD,CAAC;GACD,aAAa;IAIX,IAAI,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,WAAW,QACtD,YAAY,QAAQ,OAAO,cAAc;GAE7C;EACF;EACA,UAAU,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,UAAU;EAChF,mBAAmB,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,aAAa;EAC5F,gCAAgC,mBAC9B,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,wBAAwB;CACrE,IACA,CAAC,IAAI,CACP;CAEA,OAAO,oBAAC,0BAAD;EAA0B,OAAO;EAAU;CAAmC,CAAA;AACvF;;;;;;;AAQA,SAAgB,uBAAiD;CAC/D,MAAM,UAAU,WAAW,wBAAwB;CACnD,IAAI,YAAY,0BACd,MAAM,IAAI,MACR,0GACF;CAEF,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,6BACd,MACA,QACA,WACA,sBACM;CACN,MAAM,EAAE,aAAa,qBAAqB;CAE1C,sBACQ,SAAS,MAAM,QAAQ,WAAW,oBAAoB,GAC5D;EAAC;EAAU;EAAM;EAAQ;EAAW;CAAoB,CAC1D;AACF"}
|
|
@@ -38,6 +38,11 @@ export type PaymentStartTransactionResult = Readonly<{
|
|
|
38
38
|
/** Gateway origin. Nullable, and never interpolated into a URL before `isTrustedGatewayOrigin`. */
|
|
39
39
|
gatewayUrl: string | null;
|
|
40
40
|
orderGroup: string | null;
|
|
41
|
+
/**
|
|
42
|
+
* The Relay Node ID of the order, for `Query.order(id:)`. Null when the transaction carried no order
|
|
43
|
+
* group. Optional so a provider written before this field existed still satisfies the type.
|
|
44
|
+
*/
|
|
45
|
+
orderNodeId?: string | null;
|
|
41
46
|
userProfileId: string | null;
|
|
42
47
|
/** Display decimal. The gateway body's unit is `valueInCents`. */
|
|
43
48
|
value: PaymentMoney | null;
|
|
@@ -47,12 +52,16 @@ export type PaymentStartTransactionResult = Readonly<{
|
|
|
47
52
|
}>;
|
|
48
53
|
export type PaymentGatewayCallbackResult = Readonly<{
|
|
49
54
|
orderId: string | null;
|
|
55
|
+
/** The Relay Node ID of the finalized order, for `Query.order(id:)`. Null unless the callback succeeded. */
|
|
56
|
+
orderNodeId?: string | null;
|
|
57
|
+
/** The bank's challenge page. Set only when the server answered a challenge with a usable URL. */
|
|
58
|
+
redirectUrl?: string | null;
|
|
50
59
|
userErrors: readonly PaymentUserError[];
|
|
51
60
|
}>;
|
|
52
61
|
export type PaymentActions = Readonly<{
|
|
53
62
|
/** Select a payment method, optionally identifying a new card's BIN or a saved card's account. */
|
|
54
63
|
setMethod: (input: PaymentMethodSelectInput) => Promise<readonly PaymentUserError[]>;
|
|
55
|
-
/** Select an installment count for the current method. The response
|
|
64
|
+
/** Select an installment count for the current method. The response's `cart.total` is the greater of the order form's value and the selected payment's value. */
|
|
56
65
|
setInstallments: (count: number) => Promise<readonly PaymentUserError[]>;
|
|
57
66
|
/** Persist the billing address, or fall back to the delivery address (`sameAsDelivery: true`). */
|
|
58
67
|
setBillingAddress: (input: PaymentBillingAddressUpdateInput) => Promise<readonly PaymentUserError[]>;
|
|
@@ -66,8 +75,14 @@ export type PaymentActions = Readonly<{
|
|
|
66
75
|
saveCard: (enabled: boolean) => Promise<readonly PaymentUserError[]>;
|
|
67
76
|
/** Open a VTEX transaction from the persisted selection. Resolves the payload the gateway call needs. */
|
|
68
77
|
startTransaction: () => Promise<PaymentStartTransactionResult>;
|
|
69
|
-
/**
|
|
70
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Finalize the transaction after the gateway accepted the card. `acceptChallenges: true` is sent only by
|
|
80
|
+
* the page the bank returns the shopper to, and only then; omitted, the server asks for a challenge
|
|
81
|
+
* instead of finishing the order.
|
|
82
|
+
*/
|
|
83
|
+
gatewayCallback: (orderGroup: string, options?: Readonly<{
|
|
84
|
+
acceptChallenges?: boolean;
|
|
85
|
+
}>) => Promise<PaymentGatewayCallbackResult>;
|
|
71
86
|
/**
|
|
72
87
|
* Façade: post the card straight to the payment gateway. Issues no GraphQL operation and writes
|
|
73
88
|
* nothing to the cache. Never rejects: resolves `{ reachedGateway, userErrors }`, with one `GATEWAY_ERROR`
|
|
@@ -4,10 +4,16 @@ import "../../core/dist/index.js";
|
|
|
4
4
|
import { loggableErrorName } from "../../utils/loggable-error-name.js";
|
|
5
5
|
import { PAYMENT_BILLING_ADDRESS_UPDATE, PAYMENT_GATEWAY_CALLBACK, PAYMENT_INSTALLMENT_SELECT, PAYMENT_METHOD_SELECT, PAYMENT_NETWORK_ERROR_CODE, PAYMENT_START_TRANSACTION } from "./operations.js";
|
|
6
6
|
import { CLIENT_PREFERENCES_UPDATE } from "../identity/operations.js";
|
|
7
|
+
import { isAcceptedBin } from "./bin-format.js";
|
|
7
8
|
import { PAYMENT_GATEWAY_USER_ERROR, postPaymentsToGateway } from "./gateway.js";
|
|
8
9
|
import { useMutation } from "@apollo/client/react";
|
|
9
10
|
import { useCallback, useMemo } from "react";
|
|
11
|
+
import { INVALID_BIN_MESSAGE } from "@vtex/fs-domain-logic/checkout/rules";
|
|
10
12
|
//#region src/sdk/payment/use-payment-actions.ts
|
|
13
|
+
const INVALID_BIN_ERROR = {
|
|
14
|
+
code: "INVALID_BIN_FORMAT",
|
|
15
|
+
message: INVALID_BIN_MESSAGE
|
|
16
|
+
};
|
|
11
17
|
const NETWORK_ERROR = {
|
|
12
18
|
code: PAYMENT_NETWORK_ERROR_CODE,
|
|
13
19
|
message: "Unable to complete the request. Please try again."
|
|
@@ -18,6 +24,7 @@ const EMPTY_START_TRANSACTION = {
|
|
|
18
24
|
merchantName: null,
|
|
19
25
|
gatewayUrl: null,
|
|
20
26
|
orderGroup: null,
|
|
27
|
+
orderNodeId: null,
|
|
21
28
|
userProfileId: null,
|
|
22
29
|
value: null,
|
|
23
30
|
valueInCents: null,
|
|
@@ -37,6 +44,7 @@ function usePaymentActions() {
|
|
|
37
44
|
const [startTransactionMutation] = useMutation(PAYMENT_START_TRANSACTION);
|
|
38
45
|
const [gatewayCallbackMutation] = useMutation(PAYMENT_GATEWAY_CALLBACK);
|
|
39
46
|
const setMethod = useCallback(async (input) => {
|
|
47
|
+
if (!isAcceptedBin(input)) return [INVALID_BIN_ERROR];
|
|
40
48
|
try {
|
|
41
49
|
return (await methodSelectMutation({ variables: { input } })).data?.paymentMethodSelect.userErrors ?? [];
|
|
42
50
|
} catch (error) {
|
|
@@ -76,6 +84,7 @@ function usePaymentActions() {
|
|
|
76
84
|
merchantName: payload?.merchantName ?? null,
|
|
77
85
|
gatewayUrl: payload?.gatewayUrl ?? null,
|
|
78
86
|
orderGroup: payload?.orderGroup ?? null,
|
|
87
|
+
orderNodeId: payload?.orderNodeId ?? null,
|
|
79
88
|
userProfileId: payload?.userProfileId ?? null,
|
|
80
89
|
value: payload?.value ?? null,
|
|
81
90
|
valueInCents: payload?.valueInCents ?? null,
|
|
@@ -90,17 +99,24 @@ function usePaymentActions() {
|
|
|
90
99
|
};
|
|
91
100
|
}
|
|
92
101
|
}, [startTransactionMutation]);
|
|
93
|
-
const gatewayCallback = useCallback(async (orderGroup) => {
|
|
102
|
+
const gatewayCallback = useCallback(async (orderGroup, options) => {
|
|
94
103
|
try {
|
|
95
|
-
const
|
|
104
|
+
const input = options?.acceptChallenges === true ? {
|
|
105
|
+
orderGroup,
|
|
106
|
+
acceptChallenges: true
|
|
107
|
+
} : { orderGroup };
|
|
108
|
+
const payload = (await gatewayCallbackMutation({ variables: { input } })).data?.paymentGatewayCallback;
|
|
96
109
|
return {
|
|
97
110
|
orderId: payload?.orderId ?? null,
|
|
111
|
+
orderNodeId: payload?.orderNodeId ?? null,
|
|
112
|
+
...payload?.redirectUrl ? { redirectUrl: payload.redirectUrl } : {},
|
|
98
113
|
userErrors: payload?.userErrors ?? []
|
|
99
114
|
};
|
|
100
115
|
} catch (error) {
|
|
101
116
|
console.error("[payment.gatewayCallback] paymentGatewayCallback failed", loggableErrorName(error));
|
|
102
117
|
return {
|
|
103
118
|
orderId: null,
|
|
119
|
+
orderNodeId: null,
|
|
104
120
|
userErrors: [NETWORK_ERROR]
|
|
105
121
|
};
|
|
106
122
|
}
|
|
@@ -162,7 +178,7 @@ defineActions({
|
|
|
162
178
|
]
|
|
163
179
|
},
|
|
164
180
|
setInstallments: {
|
|
165
|
-
description: "Select an installment count for the current method (async/pessimistic). The response
|
|
181
|
+
description: "Select an installment count for the current method (async/pessimistic). The response carries the cart, whose total is the greater of the order form value and the selected payment value, so it includes the interest of the picked tier. Resolves the payload userErrors.",
|
|
166
182
|
payload: [{
|
|
167
183
|
name: "count",
|
|
168
184
|
type: "number"
|
|
@@ -243,6 +259,10 @@ defineActions({
|
|
|
243
259
|
payload: [{
|
|
244
260
|
name: "orderGroup",
|
|
245
261
|
type: "string"
|
|
262
|
+
}, {
|
|
263
|
+
name: "acceptChallenges",
|
|
264
|
+
type: "boolean",
|
|
265
|
+
optional: true
|
|
246
266
|
}]
|
|
247
267
|
},
|
|
248
268
|
sendPayments: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-payment-actions.js","names":[],"sources":["../../../src/sdk/payment/use-payment-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { CLIENT_PREFERENCES_UPDATE } from '../identity/operations.js';\nimport {\n PAYMENT_GATEWAY_USER_ERROR,\n type PaymentGatewayResult,\n postPaymentsToGateway,\n type SendPaymentsRequest,\n} from './gateway.js';\nimport {\n PAYMENT_BILLING_ADDRESS_UPDATE,\n PAYMENT_GATEWAY_CALLBACK,\n PAYMENT_INSTALLMENT_SELECT,\n PAYMENT_METHOD_SELECT,\n PAYMENT_NETWORK_ERROR_CODE,\n PAYMENT_START_TRANSACTION,\n type PaymentBillingAddressUpdateInput,\n type PaymentMethodSelectInput,\n type PaymentMoney,\n type PaymentUserError,\n} from './operations.js';\n\n/**\n * The `payment` action namespace — the sanctioned client write surface for credit-card payment\n * (specs/payment-action-namespace.md; docs/features/credit-card/rfc.md § D12;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Six mutation-backed methods run the write model T3 shipped (`checkout/schema.graphql` § 11), except\n * `saveCard`, which reuses the already-shipped `clientPreferencesUpdate` document this package owns —\n * there is no `paymentSaveCard` mutation and T3 decided there must not be one. All six are\n * async/pessimistic: the handler awaits the mutation and only the server-confirmed payload changes the\n * cache. Each is stateless (no reactive vars, no module state), resolves its payload `userErrors` (empty\n * on success), and never throws for an expected outcome; an infrastructure failure (transport or an\n * upstream GraphQLError) is caught and collapsed to one synthetic `NETWORK_ERROR` userError with no\n * per-code branching, mirroring `useShippingActions`.\n *\n * `sendPayments` is the seventh method and the odd one: a **façade** (ADR-0010's sanctioned flavor,\n * alongside `notifications`) that posts card data from the browser straight to the payment gateway,\n * touching neither our GraphQL layer nor the normalized cache. It is catalogued like any other method —\n * per D12, hiding a write route with no read-back would cost discoverability without protecting\n * anything, and the compiler wants to *see* which components reference it. What is deliberately absent\n * from the catalog is the card data itself: no `payload` entry below names a card number, CVV, expiry,\n * or holder name, so there is no schema-bindable name for the editor or the agent to map a value onto\n * (RFC D13). The card reaches the handler as a runtime argument from the card-entry component's local\n * state (T7), and `gateway.ts` — which has no Apollo import — is the only module that touches it.\n */\n\n/**\n * Everything `usePlaceOrder` (T13) needs to assemble `PaymentGatewayTransaction`, minus the five\n * fields that come from the `Payment` read model. Every field is nullable because a payload carrying\n * `userErrors` nulls all of them (T18 Decision 4), so a complete descriptor is only guaranteed once\n * `userErrors` is empty *and* the payload passes the caller's completeness check.\n */\nexport type PaymentStartTransactionResult = Readonly<{\n transactionId: string | null;\n merchantName: string | null;\n /** Gateway origin. Nullable, and never interpolated into a URL before `isTrustedGatewayOrigin`. */\n gatewayUrl: string | null;\n orderGroup: string | null;\n userProfileId: string | null;\n /** Display decimal. The gateway body's unit is `valueInCents`. */\n value: PaymentMoney | null;\n valueInCents: number | null;\n referenceValueInCents: number | null;\n userErrors: readonly PaymentUserError[];\n}>;\n\nexport type PaymentGatewayCallbackResult = Readonly<{\n orderId: string | null;\n userErrors: readonly PaymentUserError[];\n}>;\n\nexport type PaymentActions = Readonly<{\n /** Select a payment method, optionally identifying a new card's BIN or a saved card's account. */\n setMethod: (input: PaymentMethodSelectInput) => Promise<readonly PaymentUserError[]>;\n /** Select an installment count for the current method. The response carries the recomputed cart total. */\n setInstallments: (count: number) => Promise<readonly PaymentUserError[]>;\n /** Persist the billing address, or fall back to the delivery address (`sameAsDelivery: true`). */\n setBillingAddress: (input: PaymentBillingAddressUpdateInput) => Promise<readonly PaymentUserError[]>;\n /**\n * Record the data-storage consent a saved card requires, over the existing `clientPreferencesUpdate`.\n * This does not by itself save the card: the save flag and label travel on `sendPayments`'s card\n * argument (RFC D5's two halves). The boolean passes through unchanged — whether unchecking should\n * revoke a consent an unrelated opt-in component may have granted is T10's decision, and its spec must\n * state one (Gap 4 in specs/payment-action-namespace.md).\n */\n saveCard: (enabled: boolean) => Promise<readonly PaymentUserError[]>;\n /** Open a VTEX transaction from the persisted selection. Resolves the payload the gateway call needs. */\n startTransaction: () => Promise<PaymentStartTransactionResult>;\n /** Finalize the transaction after the gateway accepted the card. */\n gatewayCallback: (orderGroup: string) => Promise<PaymentGatewayCallbackResult>;\n /**\n * Façade: post the card straight to the payment gateway. Issues no GraphQL operation and writes\n * nothing to the cache. Never rejects: resolves `{ reachedGateway, userErrors }`, with one `GATEWAY_ERROR`\n * userError when the gateway rejects the call or it could not be issued. `reachedGateway` is `false`\n * only when no request was issued; every outcome it cannot classify is `true`.\n */\n sendPayments: (request: SendPaymentsRequest) => Promise<PaymentGatewayResult>;\n}>;\n\nconst NETWORK_ERROR: PaymentUserError = {\n code: PAYMENT_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\n/** Mirrors the resolver's own nulled-fields constant, so one added field is nulled in one place. */\nconst EMPTY_START_TRANSACTION = {\n transactionId: null,\n merchantName: null,\n gatewayUrl: null,\n orderGroup: null,\n userProfileId: null,\n value: null,\n valueInCents: null,\n referenceValueInCents: null,\n} as const;\n\n/**\n * The `payment` namespace hook. Registered with the first-party action registry via `paymentActions`\n * below; the compiler-emitted `PaymentActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.payment`. Writes persist purely through the normalized-cache merge of each\n * mutation response — no refetch, no imperative cache write.\n */\nexport function usePaymentActions(): PaymentActions {\n const [methodSelectMutation] = useMutation(PAYMENT_METHOD_SELECT);\n const [installmentSelectMutation] = useMutation(PAYMENT_INSTALLMENT_SELECT);\n const [billingAddressMutation] = useMutation(PAYMENT_BILLING_ADDRESS_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [startTransactionMutation] = useMutation(PAYMENT_START_TRANSACTION);\n const [gatewayCallbackMutation] = useMutation(PAYMENT_GATEWAY_CALLBACK);\n\n const setMethod = useCallback<PaymentActions['setMethod']>(\n async (input) => {\n try {\n const result = await methodSelectMutation({ variables: { input } });\n return result.data?.paymentMethodSelect.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the input carries the card's BIN, and a variable-coercion error's\n // message echoes the offending value (`got invalid value … at \"input.bin\"`).\n console.error('[payment.setMethod] paymentMethodSelect failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [methodSelectMutation],\n );\n\n const setInstallments = useCallback<PaymentActions['setInstallments']>(\n async (count) => {\n try {\n const result = await installmentSelectMutation({ variables: { input: { count } } });\n return result.data?.paymentInstallmentSelect.userErrors ?? [];\n } catch (error) {\n console.error('[payment.setInstallments] paymentInstallmentSelect failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [installmentSelectMutation],\n );\n\n const setBillingAddress = useCallback<PaymentActions['setBillingAddress']>(\n async (input) => {\n try {\n const result = await billingAddressMutation({ variables: { input } });\n return result.data?.paymentBillingAddressUpdate.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted address (PII).\n console.error('[payment.setBillingAddress] paymentBillingAddressUpdate failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [billingAddressMutation],\n );\n\n const saveCard = useCallback<PaymentActions['saveCard']>(\n async (enabled) => {\n try {\n const result = await preferencesMutation({ variables: { input: { savePersonalData: enabled } } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n console.error('[payment.saveCard] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const startTransaction = useCallback<PaymentActions['startTransaction']>(async () => {\n try {\n const result = await startTransactionMutation();\n const payload = result.data?.paymentStartTransaction;\n return {\n transactionId: payload?.transactionId ?? null,\n merchantName: payload?.merchantName ?? null,\n gatewayUrl: payload?.gatewayUrl ?? null,\n orderGroup: payload?.orderGroup ?? null,\n userProfileId: payload?.userProfileId ?? null,\n value: payload?.value ?? null,\n valueInCents: payload?.valueInCents ?? null,\n referenceValueInCents: payload?.referenceValueInCents ?? null,\n userErrors: payload?.userErrors ?? [],\n };\n } catch (error) {\n console.error('[payment.startTransaction] paymentStartTransaction failed', loggableErrorName(error));\n return { ...EMPTY_START_TRANSACTION, userErrors: [NETWORK_ERROR] };\n }\n }, [startTransactionMutation]);\n\n const gatewayCallback = useCallback<PaymentActions['gatewayCallback']>(\n async (orderGroup) => {\n try {\n const result = await gatewayCallbackMutation({ variables: { input: { orderGroup } } });\n const payload = result.data?.paymentGatewayCallback;\n return { orderId: payload?.orderId ?? null, userErrors: payload?.userErrors ?? [] };\n } catch (error) {\n console.error('[payment.gatewayCallback] paymentGatewayCallback failed', loggableErrorName(error));\n return { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n },\n [gatewayCallbackMutation],\n );\n\n const sendPayments = useCallback<PaymentActions['sendPayments']>(async (request) => {\n try {\n return await postPaymentsToGateway(request);\n } catch (error) {\n // Log the error NAME ONLY. The request carries a card number and CVV, and a thrown fetch error's\n // message can echo the URL or the body — nothing on this path is ever serialized to a log.\n console.error('[payment.sendPayments] gateway request failed', loggableErrorName(error));\n // A rejected request is unclassified — it may have been processed — so it counts as reached.\n return { reachedGateway: true, userErrors: [PAYMENT_GATEWAY_USER_ERROR] };\n }\n }, []);\n\n return useMemo(\n () => ({\n setMethod,\n setInstallments,\n setBillingAddress,\n saveCard,\n startTransaction,\n gatewayCallback,\n sendPayments,\n }),\n [setMethod, setInstallments, setBillingAddress, saveCard, startTransaction, gatewayCallback, sendPayments],\n );\n}\n\n/**\n * Declares the `payment` action namespace — the single source of truth for its method/payload metadata,\n * runtime provider, and `use` hook (mirrors `cartActions`, `shippingActions`). The native catalog\n * builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `PaymentActionProvider` calls `usePaymentActions` directly.\n *\n * `sendPayments`'s `payload` lists only the non-sensitive transaction descriptor's identifiers.\n * `ActionPayloadField` is the surface a schema-bindable name would come from, so the card fields'\n * absence here is the mechanical form of RFC D13: card number and CVV are never expressed as a declared\n * action payload. The `SendPaymentsRequest` type in `gateway.ts` is the source of truth for the real\n * call shape.\n */\nexport const paymentActions = defineActions({\n namespace: 'payment',\n description:\n 'Mutation-backed payment writes against the VTEX orderForm paymentData/invoiceData, plus a façade that posts card data directly to the payment gateway (never through our GraphQL layer or cache).',\n provider: { name: 'PaymentActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setMethod: {\n description:\n 'Select a payment method, optionally identifying a new card by BIN or a saved card by account (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'methodId', type: 'string' },\n { name: 'bin', type: 'string', optional: true },\n { name: 'accountId', type: 'string', optional: true },\n ],\n },\n setInstallments: {\n description:\n 'Select an installment count for the current method (async/pessimistic). The response recomputes the cart total with interest. Resolves the payload userErrors.',\n payload: [{ name: 'count', type: 'number' }],\n },\n setBillingAddress: {\n description:\n 'Persist the billing address, or fall back to the delivery address with sameAsDelivery (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'sameAsDelivery', type: 'boolean' },\n { name: 'addressType', type: 'string', optional: true },\n { name: 'postalCode', type: 'string', optional: true },\n { name: 'country', type: 'string', optional: true },\n { name: 'street', type: 'string', optional: true },\n { name: 'number', type: 'string', optional: true },\n { name: 'complement', type: 'string', optional: true },\n { name: 'neighborhood', type: 'string', optional: true },\n { name: 'city', type: 'string', optional: true },\n { name: 'state', type: 'string', optional: true },\n { name: 'reference', type: 'string', optional: true },\n ],\n },\n saveCard: {\n description:\n 'Record the data-storage consent a saved card requires, reusing the existing clientPreferencesUpdate write. Does not itself save the card — the save flag and label travel on sendPayments.',\n payload: [{ name: 'enabled', type: 'boolean' }],\n },\n startTransaction: {\n description:\n 'Open a VTEX transaction from the persisted payment selection. Takes no arguments; resolves the transaction identifiers the gateway call needs.',\n payload: [],\n },\n gatewayCallback: {\n description: 'Finalize the transaction after the gateway accepted the card. Resolves the payload userErrors.',\n payload: [{ name: 'orderGroup', type: 'string' }],\n },\n sendPayments: {\n description:\n 'Façade: post the card directly from the browser to the payment gateway. Issues no GraphQL operation and writes nothing to the cache. Resolves { reachedGateway, userErrors }: reachedGateway is false only when no request was issued. The card number and CVV are runtime-only arguments and are deliberately absent from this payload — they are never a bindable field (RFC D13).',\n payload: [\n { name: 'gatewayUrl', type: 'string' },\n { name: 'transactionId', type: 'string' },\n { name: 'merchantName', type: 'string' },\n { name: 'orderGroup', type: 'string' },\n { name: 'userProfileId', type: 'string' },\n ],\n },\n },\n use: usePaymentActions,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-payment-actions.js","names":[],"sources":["../../../src/sdk/payment/use-payment-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { INVALID_BIN_MESSAGE } from '@vtex/fs-domain-logic/checkout/rules';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { CLIENT_PREFERENCES_UPDATE } from '../identity/operations.js';\nimport { isAcceptedBin } from './bin-format.js';\nimport {\n PAYMENT_GATEWAY_USER_ERROR,\n type PaymentGatewayResult,\n postPaymentsToGateway,\n type SendPaymentsRequest,\n} from './gateway.js';\nimport {\n PAYMENT_BILLING_ADDRESS_UPDATE,\n PAYMENT_GATEWAY_CALLBACK,\n PAYMENT_INSTALLMENT_SELECT,\n PAYMENT_METHOD_SELECT,\n PAYMENT_NETWORK_ERROR_CODE,\n PAYMENT_START_TRANSACTION,\n type PaymentBillingAddressUpdateInput,\n type PaymentMethodSelectInput,\n type PaymentMoney,\n type PaymentUserError,\n} from './operations.js';\n\n/**\n * The `payment` action namespace — the sanctioned client write surface for credit-card payment\n * (specs/payment-action-namespace.md; docs/features/credit-card/rfc.md § D12;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Six mutation-backed methods run the write model T3 shipped (`checkout/schema.graphql` § 11), except\n * `saveCard`, which reuses the already-shipped `clientPreferencesUpdate` document this package owns —\n * there is no `paymentSaveCard` mutation and T3 decided there must not be one. All six are\n * async/pessimistic: the handler awaits the mutation and only the server-confirmed payload changes the\n * cache. Each is stateless (no reactive vars, no module state), resolves its payload `userErrors` (empty\n * on success), and never throws for an expected outcome; an infrastructure failure (transport or an\n * upstream GraphQLError) is caught and collapsed to one synthetic `NETWORK_ERROR` userError with no\n * per-code branching, mirroring `useShippingActions`.\n *\n * `sendPayments` is the seventh method and the odd one: a **façade** (ADR-0010's sanctioned flavor,\n * alongside `notifications`) that posts card data from the browser straight to the payment gateway,\n * touching neither our GraphQL layer nor the normalized cache. It is catalogued like any other method —\n * per D12, hiding a write route with no read-back would cost discoverability without protecting\n * anything, and the compiler wants to *see* which components reference it. What is deliberately absent\n * from the catalog is the card data itself: no `payload` entry below names a card number, CVV, expiry,\n * or holder name, so there is no schema-bindable name for the editor or the agent to map a value onto\n * (RFC D13). The card reaches the handler as a runtime argument from the card-entry component's local\n * state (T7), and `gateway.ts` — which has no Apollo import — is the only module that touches it.\n */\n\n/**\n * Everything `usePlaceOrder` (T13) needs to assemble `PaymentGatewayTransaction`, minus the five\n * fields that come from the `Payment` read model. Every field is nullable because a payload carrying\n * `userErrors` nulls all of them (T18 Decision 4), so a complete descriptor is only guaranteed once\n * `userErrors` is empty *and* the payload passes the caller's completeness check.\n */\nexport type PaymentStartTransactionResult = Readonly<{\n transactionId: string | null;\n merchantName: string | null;\n /** Gateway origin. Nullable, and never interpolated into a URL before `isTrustedGatewayOrigin`. */\n gatewayUrl: string | null;\n orderGroup: string | null;\n /**\n * The Relay Node ID of the order, for `Query.order(id:)`. Null when the transaction carried no order\n * group. Optional so a provider written before this field existed still satisfies the type.\n */\n orderNodeId?: string | null;\n userProfileId: string | null;\n /** Display decimal. The gateway body's unit is `valueInCents`. */\n value: PaymentMoney | null;\n valueInCents: number | null;\n referenceValueInCents: number | null;\n userErrors: readonly PaymentUserError[];\n}>;\n\nexport type PaymentGatewayCallbackResult = Readonly<{\n orderId: string | null;\n /** The Relay Node ID of the finalized order, for `Query.order(id:)`. Null unless the callback succeeded. */\n orderNodeId?: string | null;\n /** The bank's challenge page. Set only when the server answered a challenge with a usable URL. */\n redirectUrl?: string | null;\n userErrors: readonly PaymentUserError[];\n}>;\n\nexport type PaymentActions = Readonly<{\n /** Select a payment method, optionally identifying a new card's BIN or a saved card's account. */\n setMethod: (input: PaymentMethodSelectInput) => Promise<readonly PaymentUserError[]>;\n /** Select an installment count for the current method. The response's `cart.total` is the greater of the order form's value and the selected payment's value. */\n setInstallments: (count: number) => Promise<readonly PaymentUserError[]>;\n /** Persist the billing address, or fall back to the delivery address (`sameAsDelivery: true`). */\n setBillingAddress: (input: PaymentBillingAddressUpdateInput) => Promise<readonly PaymentUserError[]>;\n /**\n * Record the data-storage consent a saved card requires, over the existing `clientPreferencesUpdate`.\n * This does not by itself save the card: the save flag and label travel on `sendPayments`'s card\n * argument (RFC D5's two halves). The boolean passes through unchanged — whether unchecking should\n * revoke a consent an unrelated opt-in component may have granted is T10's decision, and its spec must\n * state one (Gap 4 in specs/payment-action-namespace.md).\n */\n saveCard: (enabled: boolean) => Promise<readonly PaymentUserError[]>;\n /** Open a VTEX transaction from the persisted selection. Resolves the payload the gateway call needs. */\n startTransaction: () => Promise<PaymentStartTransactionResult>;\n /**\n * Finalize the transaction after the gateway accepted the card. `acceptChallenges: true` is sent only by\n * the page the bank returns the shopper to, and only then; omitted, the server asks for a challenge\n * instead of finishing the order.\n */\n gatewayCallback: (\n orderGroup: string,\n options?: Readonly<{ acceptChallenges?: boolean }>,\n ) => Promise<PaymentGatewayCallbackResult>;\n /**\n * Façade: post the card straight to the payment gateway. Issues no GraphQL operation and writes\n * nothing to the cache. Never rejects: resolves `{ reachedGateway, userErrors }`, with one `GATEWAY_ERROR`\n * userError when the gateway rejects the call or it could not be issued. `reachedGateway` is `false`\n * only when no request was issued; every outcome it cannot classify is `true`.\n */\n sendPayments: (request: SendPaymentsRequest) => Promise<PaymentGatewayResult>;\n}>;\n\nconst INVALID_BIN_ERROR: PaymentUserError = { code: 'INVALID_BIN_FORMAT', message: INVALID_BIN_MESSAGE };\n\n// Diagnostic `message` (logs, `onResult`); each reader words `NETWORK_ERROR` from its own content.\nconst NETWORK_ERROR: PaymentUserError = {\n code: PAYMENT_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\n/** Mirrors the resolver's own nulled-fields constant, so one added field is nulled in one place. */\nconst EMPTY_START_TRANSACTION = {\n transactionId: null,\n merchantName: null,\n gatewayUrl: null,\n orderGroup: null,\n orderNodeId: null,\n userProfileId: null,\n value: null,\n valueInCents: null,\n referenceValueInCents: null,\n} as const;\n\n/**\n * The `payment` namespace hook. Registered with the first-party action registry via `paymentActions`\n * below; the compiler-emitted `PaymentActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.payment`. Writes persist purely through the normalized-cache merge of each\n * mutation response — no refetch, no imperative cache write.\n */\nexport function usePaymentActions(): PaymentActions {\n const [methodSelectMutation] = useMutation(PAYMENT_METHOD_SELECT);\n const [installmentSelectMutation] = useMutation(PAYMENT_INSTALLMENT_SELECT);\n const [billingAddressMutation] = useMutation(PAYMENT_BILLING_ADDRESS_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [startTransactionMutation] = useMutation(PAYMENT_START_TRANSACTION);\n const [gatewayCallbackMutation] = useMutation(PAYMENT_GATEWAY_CALLBACK);\n\n const setMethod = useCallback<PaymentActions['setMethod']>(\n async (input) => {\n // Refused here, before the value can reach the network, the GraphQL variables or the Apollo cache.\n // Logs nothing: the input carries the value being refused.\n if (!isAcceptedBin(input)) return [INVALID_BIN_ERROR];\n try {\n const result = await methodSelectMutation({ variables: { input } });\n return result.data?.paymentMethodSelect.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the input carries the card's BIN, and a variable-coercion error's\n // message echoes the offending value (`got invalid value … at \"input.bin\"`).\n console.error('[payment.setMethod] paymentMethodSelect failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [methodSelectMutation],\n );\n\n const setInstallments = useCallback<PaymentActions['setInstallments']>(\n async (count) => {\n try {\n const result = await installmentSelectMutation({ variables: { input: { count } } });\n return result.data?.paymentInstallmentSelect.userErrors ?? [];\n } catch (error) {\n console.error('[payment.setInstallments] paymentInstallmentSelect failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [installmentSelectMutation],\n );\n\n const setBillingAddress = useCallback<PaymentActions['setBillingAddress']>(\n async (input) => {\n try {\n const result = await billingAddressMutation({ variables: { input } });\n return result.data?.paymentBillingAddressUpdate.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted address (PII).\n console.error('[payment.setBillingAddress] paymentBillingAddressUpdate failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [billingAddressMutation],\n );\n\n const saveCard = useCallback<PaymentActions['saveCard']>(\n async (enabled) => {\n try {\n const result = await preferencesMutation({ variables: { input: { savePersonalData: enabled } } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n console.error('[payment.saveCard] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const startTransaction = useCallback<PaymentActions['startTransaction']>(async () => {\n try {\n const result = await startTransactionMutation();\n const payload = result.data?.paymentStartTransaction;\n return {\n transactionId: payload?.transactionId ?? null,\n merchantName: payload?.merchantName ?? null,\n gatewayUrl: payload?.gatewayUrl ?? null,\n orderGroup: payload?.orderGroup ?? null,\n orderNodeId: payload?.orderNodeId ?? null,\n userProfileId: payload?.userProfileId ?? null,\n value: payload?.value ?? null,\n valueInCents: payload?.valueInCents ?? null,\n referenceValueInCents: payload?.referenceValueInCents ?? null,\n userErrors: payload?.userErrors ?? [],\n };\n } catch (error) {\n console.error('[payment.startTransaction] paymentStartTransaction failed', loggableErrorName(error));\n return { ...EMPTY_START_TRANSACTION, userErrors: [NETWORK_ERROR] };\n }\n }, [startTransactionMutation]);\n\n const gatewayCallback = useCallback<PaymentActions['gatewayCallback']>(\n async (orderGroup, options) => {\n try {\n const input = options?.acceptChallenges === true ? { orderGroup, acceptChallenges: true } : { orderGroup };\n const result = await gatewayCallbackMutation({ variables: { input } });\n const payload = result.data?.paymentGatewayCallback;\n return {\n orderId: payload?.orderId ?? null,\n orderNodeId: payload?.orderNodeId ?? null,\n ...(payload?.redirectUrl ? { redirectUrl: payload.redirectUrl } : {}),\n userErrors: payload?.userErrors ?? [],\n };\n } catch (error) {\n console.error('[payment.gatewayCallback] paymentGatewayCallback failed', loggableErrorName(error));\n return { orderId: null, orderNodeId: null, userErrors: [NETWORK_ERROR] };\n }\n },\n [gatewayCallbackMutation],\n );\n\n const sendPayments = useCallback<PaymentActions['sendPayments']>(async (request) => {\n try {\n return await postPaymentsToGateway(request);\n } catch (error) {\n // Log the error NAME ONLY. The request carries a card number and CVV, and a thrown fetch error's\n // message can echo the URL or the body — nothing on this path is ever serialized to a log.\n console.error('[payment.sendPayments] gateway request failed', loggableErrorName(error));\n // A rejected request is unclassified — it may have been processed — so it counts as reached.\n return { reachedGateway: true, userErrors: [PAYMENT_GATEWAY_USER_ERROR] };\n }\n }, []);\n\n return useMemo(\n () => ({\n setMethod,\n setInstallments,\n setBillingAddress,\n saveCard,\n startTransaction,\n gatewayCallback,\n sendPayments,\n }),\n [setMethod, setInstallments, setBillingAddress, saveCard, startTransaction, gatewayCallback, sendPayments],\n );\n}\n\n/**\n * Declares the `payment` action namespace — the single source of truth for its method/payload metadata,\n * runtime provider, and `use` hook (mirrors `cartActions`, `shippingActions`). The native catalog\n * builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `PaymentActionProvider` calls `usePaymentActions` directly.\n *\n * `sendPayments`'s `payload` lists only the non-sensitive transaction descriptor's identifiers.\n * `ActionPayloadField` is the surface a schema-bindable name would come from, so the card fields'\n * absence here is the mechanical form of RFC D13: card number and CVV are never expressed as a declared\n * action payload. The `SendPaymentsRequest` type in `gateway.ts` is the source of truth for the real\n * call shape.\n */\nexport const paymentActions = defineActions({\n namespace: 'payment',\n description:\n 'Mutation-backed payment writes against the VTEX orderForm paymentData/invoiceData, plus a façade that posts card data directly to the payment gateway (never through our GraphQL layer or cache).',\n provider: { name: 'PaymentActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setMethod: {\n description:\n 'Select a payment method, optionally identifying a new card by BIN or a saved card by account (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'methodId', type: 'string' },\n { name: 'bin', type: 'string', optional: true },\n { name: 'accountId', type: 'string', optional: true },\n ],\n },\n setInstallments: {\n description:\n 'Select an installment count for the current method (async/pessimistic). The response carries the cart, whose total is the greater of the order form value and the selected payment value, so it includes the interest of the picked tier. Resolves the payload userErrors.',\n payload: [{ name: 'count', type: 'number' }],\n },\n setBillingAddress: {\n description:\n 'Persist the billing address, or fall back to the delivery address with sameAsDelivery (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'sameAsDelivery', type: 'boolean' },\n { name: 'addressType', type: 'string', optional: true },\n { name: 'postalCode', type: 'string', optional: true },\n { name: 'country', type: 'string', optional: true },\n { name: 'street', type: 'string', optional: true },\n { name: 'number', type: 'string', optional: true },\n { name: 'complement', type: 'string', optional: true },\n { name: 'neighborhood', type: 'string', optional: true },\n { name: 'city', type: 'string', optional: true },\n { name: 'state', type: 'string', optional: true },\n { name: 'reference', type: 'string', optional: true },\n ],\n },\n saveCard: {\n description:\n 'Record the data-storage consent a saved card requires, reusing the existing clientPreferencesUpdate write. Does not itself save the card — the save flag and label travel on sendPayments.',\n payload: [{ name: 'enabled', type: 'boolean' }],\n },\n startTransaction: {\n description:\n 'Open a VTEX transaction from the persisted payment selection. Takes no arguments; resolves the transaction identifiers the gateway call needs.',\n payload: [],\n },\n gatewayCallback: {\n description: 'Finalize the transaction after the gateway accepted the card. Resolves the payload userErrors.',\n payload: [\n { name: 'orderGroup', type: 'string' },\n { name: 'acceptChallenges', type: 'boolean', optional: true },\n ],\n },\n sendPayments: {\n description:\n 'Façade: post the card directly from the browser to the payment gateway. Issues no GraphQL operation and writes nothing to the cache. Resolves { reachedGateway, userErrors }: reachedGateway is false only when no request was issued. The card number and CVV are runtime-only arguments and are deliberately absent from this payload — they are never a bindable field (RFC D13).',\n payload: [\n { name: 'gatewayUrl', type: 'string' },\n { name: 'transactionId', type: 'string' },\n { name: 'merchantName', type: 'string' },\n { name: 'orderGroup', type: 'string' },\n { name: 'userProfileId', type: 'string' },\n ],\n },\n },\n use: usePaymentActions,\n});\n"],"mappings":"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"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { PaymentMoney } from "./operations.js";
|
|
2
2
|
import "../actions/types.js";
|
|
3
|
+
import "./resumed-purchase.js";
|
|
3
4
|
//#region src/sdk/payment/use-place-order.d.ts
|
|
4
5
|
export type PlaceOrderInstallment = Readonly<{
|
|
5
6
|
count: number;
|
|
6
7
|
/** Per-installment amount, as a display decimal. The gateway's unit is minor units. */
|
|
7
8
|
value: PaymentMoney;
|
|
8
|
-
|
|
9
|
+
/** `null` when the order form did not say. The gateway body still gets a number: `?? 0` at the descriptor. */
|
|
10
|
+
interestRate: number | null;
|
|
9
11
|
}>;
|
|
10
12
|
export type PlaceOrderMethod = Readonly<{
|
|
11
13
|
id: string;
|
|
@@ -36,7 +38,8 @@ export type PlaceOrderAttemptPhase =
|
|
|
36
38
|
/** The continuation resolved with no userErrors — the card reached the gateway. */
|
|
37
39
|
'sent' |
|
|
38
40
|
/** The card's fate is unknown: the continuation threw, the POST was aborted, or a finalization got no
|
|
39
|
-
* answer or only a locked code (`REDIRECT_REQUIRED`, `MISSING_TRANSACTION_COOKIES
|
|
41
|
+
* answer or only a locked code (`REDIRECT_REQUIRED`, `MISSING_TRANSACTION_COOKIES`,
|
|
42
|
+
* `ORDER_GROUP_MISMATCH`). Resume-only.
|
|
40
43
|
* Treated exactly like `sent`. */
|
|
41
44
|
'unresolved' |
|
|
42
45
|
/** `gatewayCallback` is in flight for this attempt's order group. */
|
|
@@ -55,6 +58,11 @@ export type PlaceOrderAttempt = Readonly<{
|
|
|
55
58
|
* upstream success response body is discarded. So `orderId === orderGroup` on every success today.
|
|
56
59
|
*/
|
|
57
60
|
orderId: string | null;
|
|
61
|
+
/**
|
|
62
|
+
* The Relay Node ID of the placed order, from `gatewayCallback` (or from `startTransaction` when no
|
|
63
|
+
* callback runs). Absent until the attempt settles; opaque to this module.
|
|
64
|
+
*/
|
|
65
|
+
orderNodeId?: string | null;
|
|
58
66
|
}>;
|
|
59
67
|
/**
|
|
60
68
|
* Fix pass (High finding, race #2): widened past a plain value so a write can be made conditional on
|