@vtex/faststore 0.0.10 → 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 +42 -0
- package/README.md +0 -1
- package/dist/actions.json +6 -1
- package/dist/catalog.json +789 -1701
- 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 +63 -57
- package/dist/components.js +60 -54
- package/dist/content-types.json +5785 -754
- package/dist/core/dist/define-component.d.ts +1 -1
- 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-menu.md +14 -15
- package/dist/docs/account-saved-cards.md +44 -39
- 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 +5 -2
- package/dist/docs/buy-button.md +7 -8
- package/dist/docs/card-entry.md +39 -26
- package/dist/docs/card-summary.md +18 -8
- package/dist/docs/cardholder-document.md +5 -3
- package/dist/docs/carousel.md +5 -4
- package/dist/docs/cart-destination.md +39 -26
- package/dist/docs/cart-item.md +29 -14
- package/dist/docs/cart-totalizer.md +7 -5
- package/dist/docs/cart.md +135 -41
- 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/form.md +54 -18
- package/dist/docs/free-shipping-progress.md +6 -5
- package/dist/docs/identity-edit.md +8 -2
- package/dist/docs/identity-summary.md +18 -5
- package/dist/docs/installments.md +46 -32
- 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 +30 -4
- package/dist/docs/payment-methods.md +1 -1
- 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 +13 -9
- package/dist/docs/product-list.md +7 -6
- package/dist/docs/product-shelf.md +0 -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/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 +4 -2
- package/dist/docs/sign-in.md +173 -0
- package/dist/docs/toast.md +15 -4
- package/dist/docs/variant-selector.md +15 -11
- package/dist/graphql/types.d.ts +4 -14
- package/dist/index.d.ts +2 -2
- package/dist/internal/client.d.ts +1 -3
- package/dist/internal/client.js +1 -1
- package/dist/internal/server.d.ts +7 -4
- package/dist/internal/server.js +7 -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 +108 -28
- package/dist/matter/account-saved-cards/account-saved-cards.js +177 -122
- package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -1
- 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 +7 -1
- package/dist/matter/cart/cart-namespace.js +7 -1
- package/dist/matter/cart/cart-namespace.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +402 -61
- package/dist/matter/cart/cart.js +624 -153
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-destination/cart-destination.d.ts +30 -19
- package/dist/matter/cart-destination/cart-destination.js +160 -70
- package/dist/matter/cart-destination/cart-destination.js.map +1 -1
- package/dist/matter/cart-item/cart-item.d.ts +144 -17
- package/dist/matter/cart-item/cart-item.js +166 -49
- 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 +46 -17
- 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 +79 -7
- package/dist/matter/free-shipping-progress/free-shipping-progress.js +77 -20
- 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 +1 -3
- package/dist/matter/product-shelf/product-shelf.js +2 -15
- 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 +250 -24
- package/dist/matter/shipping-simulator/shipping-simulator.js +257 -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 +29 -8
- package/dist/particles/binding-switcher/binding-switcher.js +37 -26
- package/dist/particles/binding-switcher/binding-switcher.js.map +1 -1
- package/dist/particles/card-summary/card-summary.d.ts +38 -8
- package/dist/particles/card-summary/card-summary.js +55 -22
- package/dist/particles/card-summary/card-summary.js.map +1 -1
- 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/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/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/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 +29 -3
- package/dist/particles/toast/toast.js +34 -10
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +164 -56
- 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/cart/use-cart-actions.js.map +1 -1
- 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 +1 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +20 -5
- package/dist/sdk/generated/graphql.js +6 -0
- 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/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/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 +3 -2
- package/dist/sdk/seo/page-alternates.js +4 -2
- 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/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/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 +8 -0
- 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 -183
- package/dist/sdk/i18n/messages/en-US.js.map +0 -1
- package/dist/sdk/i18n/messages/en-US.json +0 -178
- package/dist/sdk/i18n/messages/en-US.json.d.ts +0 -182
- package/dist/sdk/i18n/messages/es-ES.js +0 -183
- package/dist/sdk/i18n/messages/es-ES.js.map +0 -1
- package/dist/sdk/i18n/messages/es-ES.json +0 -178
- package/dist/sdk/i18n/messages/pt-BR.js +0 -183
- package/dist/sdk/i18n/messages/pt-BR.js.map +0 -1
- package/dist/sdk/i18n/messages/pt-BR.json +0 -178
- 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,23 @@
|
|
|
1
|
+
import { logMessageEvent } from "./message-formatter.js";
|
|
2
|
+
import { ownValue } from "../../utils/own-value.js";
|
|
3
|
+
//#region src/sdk/i18n/format-error-code.ts
|
|
4
|
+
/**
|
|
5
|
+
* Words an upstream error from the component's own `$content`: the message field `fields` names for its
|
|
6
|
+
* `code`, or `fallbackField` for a code the map does not know (a newer server, or a code minted outside
|
|
7
|
+
* the map). The error's own `message` is an English diagnostic, so it is never shown; an unknown code
|
|
8
|
+
* logs `message.unknown-code` with the content type's id instead.
|
|
9
|
+
*/
|
|
10
|
+
function formatErrorCode(contentType, fields, error, format, fallbackField) {
|
|
11
|
+
const field = error.code == null ? void 0 : ownValue(fields, error.code);
|
|
12
|
+
if (field !== void 0) return format(field);
|
|
13
|
+
logMessageEvent("message.unknown-code", {
|
|
14
|
+
contentTypeId: contentType.id,
|
|
15
|
+
code: error.code ?? null,
|
|
16
|
+
field: fallbackField
|
|
17
|
+
});
|
|
18
|
+
return format(fallbackField);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { formatErrorCode };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=format-error-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-error-code.js","names":[],"sources":["../../../src/sdk/i18n/format-error-code.ts"],"sourcesContent":["import type { ContentTypeDefinition } from '@vtex/fs-core';\nimport { ownValue } from '../../utils/own-value.js';\nimport { logMessageEvent } from './message-formatter.js';\n\n/**\n * Words an upstream error from the component's own `$content`: the message field `fields` names for its\n * `code`, or `fallbackField` for a code the map does not know (a newer server, or a code minted outside\n * the map). The error's own `message` is an English diagnostic, so it is never shown; an unknown code\n * logs `message.unknown-code` with the content type's id instead.\n */\nexport function formatErrorCode<F extends string>(\n contentType: Pick<ContentTypeDefinition, 'id'>,\n fields: Readonly<Record<string, F>>,\n error: { code?: string | null },\n format: (field: F) => string,\n fallbackField: NoInfer<F>,\n): string {\n const field = error.code == null ? undefined : ownValue(fields, error.code);\n if (field !== undefined) return format(field);\n logMessageEvent('message.unknown-code', {\n contentTypeId: contentType.id,\n code: error.code ?? null,\n field: fallbackField,\n });\n return format(fallbackField);\n}\n"],"mappings":";;;;;;;;;AAUA,SAAgB,gBACd,aACA,QACA,OACA,QACA,eACQ;CACR,MAAM,QAAQ,MAAM,QAAQ,OAAO,KAAA,IAAY,SAAS,QAAQ,MAAM,IAAI;CAC1E,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,KAAK;CAC5C,gBAAgB,wBAAwB;EACtC,eAAe,YAAY;EAC3B,MAAM,MAAM,QAAQ;EACpB,OAAO;CACT,CAAC;CACD,OAAO,OAAO,aAAa;AAC7B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ContentTypeDefinition, ContentValue, MessageArguments, MessageFieldName, MessageTagName } from "../../core/dist/define-content-type.js";
|
|
2
|
+
import "../../core/dist/index.js";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
//#region src/sdk/i18n/message-formatter.d.ts
|
|
5
|
+
type MessageProperty<T extends ContentTypeDefinition, K> = K extends keyof T['schema']['properties'] ? T['schema']['properties'][K] : never;
|
|
6
|
+
/** Optional when the message declares no arguments, required otherwise. */
|
|
7
|
+
type ArgumentsParameter<P> = MessageArguments<P> extends Record<string, never> ? [args?: MessageArguments<P>] : [args: MessageArguments<P>];
|
|
8
|
+
/** Formats the message fields of one component's `$content`, typed by their message contract. */
|
|
9
|
+
export type MessageFormatter<T extends ContentTypeDefinition> = {
|
|
10
|
+
format<K extends MessageFieldName<T>>(field: K, ...args: ArgumentsParameter<MessageProperty<T, K>>): string;
|
|
11
|
+
rich<K extends MessageFieldName<T>>(field: K, args: MessageArguments<MessageProperty<T, K>>, tags: Record<MessageTagName<MessageProperty<T, K>>, (chunks: ReactNode[]) => ReactNode>): ReactNode;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The message formatter for a content type and its `$content`, in `locale`. Pure and side-neutral, so a
|
|
15
|
+
* Server Component formats without React context. Both methods are total: a missing message renders
|
|
16
|
+
* `''` and an invalid one renders the authored string, each logging an error (an optional message,
|
|
17
|
+
* `messageOptional`, renders `''` unwritten without logging). Without a locale (a
|
|
18
|
+
* Server Component rendered with no compiler-injected `$locale`) every message is invalid.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createMessageFormatter<T extends ContentTypeDefinition>(locale: string | undefined, contentType: T, content: ContentValue<T> | undefined): MessageFormatter<T>;
|
|
21
|
+
//#endregion
|
|
22
|
+
//# sourceMappingURL=message-formatter.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Children, Fragment, createElement } from "react";
|
|
2
|
+
import { TYPE, createNumberElement } from "@formatjs/icu-messageformat-parser";
|
|
3
|
+
import { FormatError, IntlMessageFormat } from "intl-messageformat";
|
|
4
|
+
//#region src/sdk/i18n/message-formatter.ts
|
|
5
|
+
/**
|
|
6
|
+
* The message formatter for a content type and its `$content`, in `locale`. Pure and side-neutral, so a
|
|
7
|
+
* Server Component formats without React context. Both methods are total: a missing message renders
|
|
8
|
+
* `''` and an invalid one renders the authored string, each logging an error (an optional message,
|
|
9
|
+
* `messageOptional`, renders `''` unwritten without logging). Without a locale (a
|
|
10
|
+
* Server Component rendered with no compiler-injected `$locale`) every message is invalid.
|
|
11
|
+
*/
|
|
12
|
+
function createMessageFormatter(locale, contentType, content) {
|
|
13
|
+
function resolve(field, values) {
|
|
14
|
+
const message = content?.[field];
|
|
15
|
+
const fields = {
|
|
16
|
+
contentTypeId: contentType.id,
|
|
17
|
+
field,
|
|
18
|
+
locale
|
|
19
|
+
};
|
|
20
|
+
if (typeof message !== "string" || message.trim() === "") {
|
|
21
|
+
if (!isOptionalMessage(contentType, field)) logMessageEvent("message.missing", {
|
|
22
|
+
...fields,
|
|
23
|
+
reason: typeof message === "string" ? "blank" : "absent"
|
|
24
|
+
});
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
if (!locale) {
|
|
28
|
+
logMessageEvent("message.invalid", {
|
|
29
|
+
...fields,
|
|
30
|
+
reason: "missing-locale"
|
|
31
|
+
});
|
|
32
|
+
return message;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return formatIcu(locale, message, values);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
logMessageEvent("message.invalid", {
|
|
38
|
+
...fields,
|
|
39
|
+
reason: invalidReason(error)
|
|
40
|
+
});
|
|
41
|
+
return message;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
format(field, ...[args]) {
|
|
46
|
+
return joinText(resolve(field, withoutPrototype(args)));
|
|
47
|
+
},
|
|
48
|
+
rich(field, args, tags) {
|
|
49
|
+
const values = withoutPrototype(args);
|
|
50
|
+
for (const [name, tag] of Object.entries(tags)) values[name] = (chunks) => tag(Children.toArray(chunks));
|
|
51
|
+
const result = resolve(field, values);
|
|
52
|
+
if (typeof result === "string") return result;
|
|
53
|
+
return createElement(Fragment, null, ...Array.isArray(result) ? result : [result]);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `intl-messageformat` renders a plain argument as `String(value)`, and a name can be both a plural
|
|
59
|
+
* selector and a plain argument in one message. So a plain argument holding a number is rewritten to
|
|
60
|
+
* a `number` element, which formats with `Intl.NumberFormat` in `locale`, and selectors stay raw.
|
|
61
|
+
*/
|
|
62
|
+
function formatIcu(locale, message, values) {
|
|
63
|
+
return compiledMessage(locale, message, Object.keys(values).filter((name) => typeof values[name] === "number")).format(values);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parsing dominates a format call, and the same authored message renders on every row and every
|
|
67
|
+
* render, so the compiled message is kept per locale and set of number arguments. Authored
|
|
68
|
+
* copy is finite; the cap only guards against unbounded templates.
|
|
69
|
+
*/
|
|
70
|
+
const COMPILED_MESSAGES = /* @__PURE__ */ new Map();
|
|
71
|
+
const COMPILED_MESSAGES_LIMIT = 1e3;
|
|
72
|
+
function compiledMessage(locale, message, numberArguments) {
|
|
73
|
+
const key = [
|
|
74
|
+
locale,
|
|
75
|
+
numberArguments.join(","),
|
|
76
|
+
message
|
|
77
|
+
].join("\0");
|
|
78
|
+
const cached = COMPILED_MESSAGES.get(key);
|
|
79
|
+
if (cached) return cached;
|
|
80
|
+
const parsed = new IntlMessageFormat(message, locale);
|
|
81
|
+
const compiled = numberArguments.length === 0 ? parsed : new IntlMessageFormat(localizeNumberArguments(parsed.getAst(), new Set(numberArguments)), locale);
|
|
82
|
+
if (COMPILED_MESSAGES.size >= COMPILED_MESSAGES_LIMIT) COMPILED_MESSAGES.clear();
|
|
83
|
+
COMPILED_MESSAGES.set(key, compiled);
|
|
84
|
+
return compiled;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The argument values in an object with no prototype, so a message argument named after an
|
|
88
|
+
* `Object.prototype` member (`{toString}`, `{constructor}`) is a missing value, not an inherited one.
|
|
89
|
+
*/
|
|
90
|
+
function withoutPrototype(values) {
|
|
91
|
+
return Object.assign(Object.create(null), values);
|
|
92
|
+
}
|
|
93
|
+
/** Whether the content type declares `field` a message a store may leave unwritten. */
|
|
94
|
+
function isOptionalMessage(contentType, field) {
|
|
95
|
+
return contentType.schema.properties[field]?.messageOptional === true;
|
|
96
|
+
}
|
|
97
|
+
/** Without tag functions every part is a string, and `intl-messageformat` joins them into one. */
|
|
98
|
+
function joinText(result) {
|
|
99
|
+
return Array.isArray(result) ? result.join("") : result;
|
|
100
|
+
}
|
|
101
|
+
function localizeNumberArguments(elements, numberArguments) {
|
|
102
|
+
return elements.map((element) => {
|
|
103
|
+
switch (element.type) {
|
|
104
|
+
case TYPE.argument: return numberArguments.has(element.value) ? createNumberElement(element.value) : element;
|
|
105
|
+
case TYPE.plural:
|
|
106
|
+
case TYPE.select: return {
|
|
107
|
+
...element,
|
|
108
|
+
options: Object.fromEntries(Object.entries(element.options).map(([key, option]) => [key, {
|
|
109
|
+
...option,
|
|
110
|
+
value: localizeNumberArguments(option.value, numberArguments)
|
|
111
|
+
}]))
|
|
112
|
+
};
|
|
113
|
+
case TYPE.tag: return {
|
|
114
|
+
...element,
|
|
115
|
+
children: localizeNumberArguments(element.children, numberArguments)
|
|
116
|
+
};
|
|
117
|
+
default: return element;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* A code or kind name, never an error message: `InvalidValueError`'s message embeds the argument
|
|
123
|
+
* value, which can carry shopper data.
|
|
124
|
+
*/
|
|
125
|
+
function invalidReason(error) {
|
|
126
|
+
if (error instanceof FormatError) return error.code;
|
|
127
|
+
if (error instanceof SyntaxError) return error.message;
|
|
128
|
+
return error instanceof Error ? error.name : "unknown";
|
|
129
|
+
}
|
|
130
|
+
/** One log line in every environment. Never the message text or an argument value. */
|
|
131
|
+
function logMessageEvent(event, fields) {
|
|
132
|
+
console.error("[message]", {
|
|
133
|
+
...fields,
|
|
134
|
+
event
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { createMessageFormatter, logMessageEvent };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=message-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-formatter.js","names":[],"sources":["../../../src/sdk/i18n/message-formatter.ts"],"sourcesContent":["import { createNumberElement, type MessageFormatElement, TYPE } from '@formatjs/icu-messageformat-parser';\nimport type {\n ContentTypeDefinition,\n ContentValue,\n MessageArguments,\n MessageFieldName,\n MessageTagName,\n} from '@vtex/fs-core';\nimport { FormatError, type FormatXMLElementFn, IntlMessageFormat, type PrimitiveType } from 'intl-messageformat';\nimport { Children, createElement, Fragment, type ReactNode } from 'react';\n\ntype MessageProperty<T extends ContentTypeDefinition, K> = K extends keyof T['schema']['properties']\n ? T['schema']['properties'][K]\n : never;\n\n/** Optional when the message declares no arguments, required otherwise. */\ntype ArgumentsParameter<P> =\n MessageArguments<P> extends Record<string, never> ? [args?: MessageArguments<P>] : [args: MessageArguments<P>];\n\n/** `R` is what a tag renders: `ReactNode` for rich messages, `string` when there are no tags. */\ntype MessageValues<R = ReactNode> = Record<string, PrimitiveType | R | FormatXMLElementFn<R>>;\n\ntype FormatResult<R> = string | R | (string | R)[];\n\ntype MessageEvent = 'message.missing' | 'message.invalid' | 'message.unknown-code';\n\n/** Formats the message fields of one component's `$content`, typed by their message contract. */\nexport type MessageFormatter<T extends ContentTypeDefinition> = {\n format<K extends MessageFieldName<T>>(field: K, ...args: ArgumentsParameter<MessageProperty<T, K>>): string;\n rich<K extends MessageFieldName<T>>(\n field: K,\n args: MessageArguments<MessageProperty<T, K>>,\n tags: Record<MessageTagName<MessageProperty<T, K>>, (chunks: ReactNode[]) => ReactNode>,\n ): ReactNode;\n};\n\n/**\n * The message formatter for a content type and its `$content`, in `locale`. Pure and side-neutral, so a\n * Server Component formats without React context. Both methods are total: a missing message renders\n * `''` and an invalid one renders the authored string, each logging an error (an optional message,\n * `messageOptional`, renders `''` unwritten without logging). Without a locale (a\n * Server Component rendered with no compiler-injected `$locale`) every message is invalid.\n */\nexport function createMessageFormatter<T extends ContentTypeDefinition>(\n locale: string | undefined,\n contentType: T,\n content: ContentValue<T> | undefined,\n): MessageFormatter<T> {\n function resolve<R>(field: string, values: MessageValues<R>): FormatResult<R> {\n const message = (content as Record<string, unknown> | undefined)?.[field];\n const fields = { contentTypeId: contentType.id, field, locale };\n if (typeof message !== 'string' || message.trim() === '') {\n if (!isOptionalMessage(contentType, field)) {\n logMessageEvent('message.missing', { ...fields, reason: typeof message === 'string' ? 'blank' : 'absent' });\n }\n return '';\n }\n if (!locale) {\n logMessageEvent('message.invalid', { ...fields, reason: 'missing-locale' });\n return message;\n }\n try {\n return formatIcu(locale, message, values);\n } catch (error) {\n logMessageEvent('message.invalid', { ...fields, reason: invalidReason(error) });\n return message;\n }\n }\n\n return {\n format(field, ...[args]) {\n return joinText(resolve<string>(field, withoutPrototype(args)));\n },\n rich(field, args, tags) {\n const values: MessageValues = withoutPrototype(args);\n for (const [name, tag] of Object.entries<(chunks: ReactNode[]) => ReactNode>(tags)) {\n values[name] = (chunks: ReactNode[]) => tag(Children.toArray(chunks));\n }\n const result = resolve<ReactNode>(field, values);\n if (typeof result === 'string') {\n return result;\n }\n // Positional children, so React asks for no keys.\n return createElement(Fragment, null, ...(Array.isArray(result) ? result : [result]));\n },\n };\n}\n\n/**\n * `intl-messageformat` renders a plain argument as `String(value)`, and a name can be both a plural\n * selector and a plain argument in one message. So a plain argument holding a number is rewritten to\n * a `number` element, which formats with `Intl.NumberFormat` in `locale`, and selectors stay raw.\n */\nfunction formatIcu<R>(locale: string, message: string, values: MessageValues<R>): FormatResult<R> {\n const numberArguments = Object.keys(values).filter((name) => typeof values[name] === 'number');\n return compiledMessage(locale, message, numberArguments).format<R>(values);\n}\n\n/**\n * Parsing dominates a format call, and the same authored message renders on every row and every\n * render, so the compiled message is kept per locale and set of number arguments. Authored\n * copy is finite; the cap only guards against unbounded templates.\n */\nconst COMPILED_MESSAGES = new Map<string, IntlMessageFormat>();\nconst COMPILED_MESSAGES_LIMIT = 1000;\n\nfunction compiledMessage(locale: string, message: string, numberArguments: readonly string[]): IntlMessageFormat {\n const key = [locale, numberArguments.join(','), message].join('\\u0000');\n const cached = COMPILED_MESSAGES.get(key);\n if (cached) return cached;\n const parsed = new IntlMessageFormat(message, locale);\n const compiled =\n numberArguments.length === 0\n ? parsed\n : new IntlMessageFormat(localizeNumberArguments(parsed.getAst(), new Set(numberArguments)), locale);\n if (COMPILED_MESSAGES.size >= COMPILED_MESSAGES_LIMIT) COMPILED_MESSAGES.clear();\n COMPILED_MESSAGES.set(key, compiled);\n return compiled;\n}\n\n/**\n * The argument values in an object with no prototype, so a message argument named after an\n * `Object.prototype` member (`{toString}`, `{constructor}`) is a missing value, not an inherited one.\n */\nfunction withoutPrototype<V>(values: Readonly<Record<string, V>> | undefined): Record<string, V> {\n return Object.assign(Object.create(null), values);\n}\n\n/** Whether the content type declares `field` a message a store may leave unwritten. */\nfunction isOptionalMessage(contentType: ContentTypeDefinition, field: string): boolean {\n const property = (contentType.schema.properties as Record<string, { messageOptional?: boolean } | undefined>)[field];\n return property?.messageOptional === true;\n}\n\n/** Without tag functions every part is a string, and `intl-messageformat` joins them into one. */\nfunction joinText(result: FormatResult<string>): string {\n return Array.isArray(result) ? result.join('') : result;\n}\n\nfunction localizeNumberArguments(\n elements: MessageFormatElement[],\n numberArguments: ReadonlySet<string>,\n): MessageFormatElement[] {\n return elements.map((element) => {\n switch (element.type) {\n case TYPE.argument:\n return numberArguments.has(element.value) ? createNumberElement(element.value) : element;\n case TYPE.plural:\n case TYPE.select:\n return {\n ...element,\n options: Object.fromEntries(\n Object.entries(element.options).map(([key, option]) => [\n key,\n { ...option, value: localizeNumberArguments(option.value, numberArguments) },\n ]),\n ),\n };\n case TYPE.tag:\n return { ...element, children: localizeNumberArguments(element.children, numberArguments) };\n default:\n return element;\n }\n });\n}\n\n/**\n * A code or kind name, never an error message: `InvalidValueError`'s message embeds the argument\n * value, which can carry shopper data.\n */\nfunction invalidReason(error: unknown): string {\n if (error instanceof FormatError) return error.code;\n // The parser throws a `SyntaxError` whose message is its `ErrorKind` name.\n if (error instanceof SyntaxError) return error.message;\n return error instanceof Error ? error.name : 'unknown';\n}\n\n/** One log line in every environment. Never the message text or an argument value. */\nexport function logMessageEvent(event: MessageEvent, fields: Record<string, unknown>): void {\n // `event` spreads last so a `fields` key of the same name cannot displace the discriminator.\n console.error('[message]', { ...fields, event });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ContentTypeDefinition, ContentValue } from "../../core/dist/define-content-type.js";
|
|
2
|
+
import "../../core/dist/index.js";
|
|
3
|
+
import { MessageFormatter } from "./message-formatter.js";
|
|
4
|
+
//#region src/sdk/i18n/use-message-formatter.d.ts
|
|
5
|
+
/** The message formatter for a Client Component, in the locale `StorefrontProvider` published. */
|
|
6
|
+
export declare function useMessageFormatter<T extends ContentTypeDefinition>(contentType: T, content: ContentValue<T> | undefined): MessageFormatter<T>;
|
|
7
|
+
//#endregion
|
|
8
|
+
//# sourceMappingURL=use-message-formatter.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useStorefrontContext } from "../context/storefront-context.js";
|
|
3
|
+
import { createMessageFormatter } from "./message-formatter.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
//#region src/sdk/i18n/use-message-formatter.ts
|
|
6
|
+
/** The message formatter for a Client Component, in the locale `StorefrontProvider` published. */
|
|
7
|
+
function useMessageFormatter(contentType, content) {
|
|
8
|
+
const { locale } = useStorefrontContext();
|
|
9
|
+
return useMemo(() => createMessageFormatter(locale, contentType, content), [
|
|
10
|
+
locale,
|
|
11
|
+
contentType,
|
|
12
|
+
content
|
|
13
|
+
]);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { useMessageFormatter };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=use-message-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-message-formatter.js","names":[],"sources":["../../../src/sdk/i18n/use-message-formatter.ts"],"sourcesContent":["'use client';\n\nimport type { ContentTypeDefinition, ContentValue } from '@vtex/fs-core';\nimport { useMemo } from 'react';\nimport { useStorefrontContext } from '../context/storefront-context.js';\nimport { createMessageFormatter, type MessageFormatter } from './message-formatter.js';\n\n/** The message formatter for a Client Component, in the locale `StorefrontProvider` published. */\nexport function useMessageFormatter<T extends ContentTypeDefinition>(\n contentType: T,\n content: ContentValue<T> | undefined,\n): MessageFormatter<T> {\n const { locale } = useStorefrontContext();\n return useMemo(() => createMessageFormatter(locale, contentType, content), [locale, contentType, content]);\n}\n"],"mappings":";;;;;;AAQA,SAAgB,oBACd,aACA,SACqB;CACrB,MAAM,EAAE,WAAW,qBAAqB;CACxC,OAAO,cAAc,uBAAuB,QAAQ,aAAa,OAAO,GAAG;EAAC;EAAQ;EAAa;CAAO,CAAC;AAC3G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\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 {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile write answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError` (the read answers an anonymous one with a null profile instead). Collapsing it into\n * `NETWORK_ERROR` would offer a retry that cannot succeed, so it gets its own code and the caller can\n * send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error('[identity.clientProfileUpdate] clientProfileUpdate failed', loggableErrorName(error));\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error('[identity.clientPreferencesUpdate] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error('[identity.customerProfileUpdate] customerProfileUpdate failed', loggableErrorName(error));\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\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 {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\n// A diagnostic message: components word this code from their own `$content`.\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\n// A diagnostic message: components word this code from their own `$content`.\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\n// A diagnostic message: components word this code from their own `$content`.\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\n// A diagnostic message: components word this code from their own `$content`.\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile write answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError` (the read answers an anonymous one with a null profile instead). Collapsing it into\n * `NETWORK_ERROR` would offer a retry that cannot succeed, so it gets its own code and the caller can\n * send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error('[identity.clientProfileUpdate] clientProfileUpdate failed', loggableErrorName(error));\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error('[identity.clientPreferencesUpdate] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error('[identity.customerProfileUpdate] customerProfileUpdate failed', loggableErrorName(error));\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":";;;;;;;;;AAgFA,MAAM,wBAAgD;CACpD,MAAM;CACN,SAAS;AACX;AAGA,MAAM,2BAAmD;CACvD,MAAM;CACN,SAAS;AACX;AAGA,MAAM,iCAA2D;CAC/D,MAAM;CACN,SAAS;AACX;AAGA,MAAM,sCAAgE;CACpE,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAS,uBAAuB,OAA0C;CACxE,IAAI,sBAAsB,GAAG,KAAK,GACX;MAAA,MAAM,OAAO,MAAM,EAAE,iBAAiB,YAAY,SAAS,cACjE,GAAG,OAAO;CAAA;CAE3B,OAAO;AACT;;;;;;AAOA,SAAgB,qBAAsC;CACpD,MAAM,CAAC,mBAAmB,YAAY,qBAAqB;CAC3D,MAAM,CAAC,uBAAuB,YAAY,yBAAyB;CACnE,MAAM,CAAC,2BAA2B,YAAY,uBAAuB;CAErE,MAAM,sBAAsB,YAC1B,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACxD,MAAM,qBAAqB,cAAc,CAAC;EAC1D,SAAS,OAAO;GAEd,QAAQ,MAAM,6DAA6D,kBAAkB,KAAK,CAAC;GACnG,OAAO,CAAC,qBAAqB;EAC/B;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,0BAA0B,YAC9B,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,oBAAoB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CAC5D,MAAM,yBAAyB,cAAc,CAAC;EAC9D,SAAS,OAAO;GAEd,QAAQ,MAAM,qEAAqE,kBAAkB,KAAK,CAAC;GAC3G,OAAO,CAAC,wBAAwB;EAClC;CACF,GACA,CAAC,mBAAmB,CACtB;CAEA,MAAM,wBAAwB,YAC5B,OAAO,YAAY;EACjB,IAAI;GAGF,QAAO,MADc,wBAAwB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CAChE,MAAM,uBAAuB,cAAc,CAAC;EAC5D,SAAS,OAAO;GAEd,QAAQ,MAAM,iEAAiE,kBAAkB,KAAK,CAAC;GACvG,OAAO,CAAC,uBAAuB,KAAK,CAAC;EACvC;CACF,GACA,CAAC,uBAAuB,CAC1B;CAEA,OAAO,eACE;EAAE;EAAqB;EAAyB;CAAsB,IAC7E;EAAC;EAAqB;EAAyB;CAAqB,CACtE;AACF;AAQ+B,cAAc;CAC3C,WAAW;CACX,aACE;CACF,UAAU;EAAE,MAAM;EAA0B,YAAY;CAAkC;CAC1F,SAAS;EACP,qBAAqB;GACnB,aACE;GACF,SAAS;IACP;KAAE,MAAM;KAAS,MAAM;KAAU,UAAU;IAAK;IAChD;KAAE,MAAM;KAAa,MAAM;KAAU,UAAU;IAAK;IACpD;KAAE,MAAM;KAAY,MAAM;KAAU,UAAU;IAAK;IACnD;KAAE,MAAM;KAAS,MAAM;KAAU,UAAU;IAAK;IAChD;KAAE,MAAM;KAAY,MAAM;KAAU,UAAU;IAAK;GACrD;EACF;EACA,yBAAyB;GACvB,aACE;GACF,SAAS,CACP;IAAE,MAAM;IAAmB,MAAM;IAAW,UAAU;GAAK,GAC3D;IAAE,MAAM;IAAoB,MAAM;IAAW,UAAU;GAAK,CAC9D;EACF;EACA,uBAAuB;GACrB,aACE;GACF,SAAS;IACP;KAAE,MAAM;KAAa,MAAM;KAAU,UAAU;IAAK;IACpD;KAAE,MAAM;KAAY,MAAM;KAAU,UAAU;IAAK;IACnD;KAAE,MAAM;KAAa,MAAM;KAAU,UAAU;IAAK;IACpD;KAAE,MAAM;KAAe,MAAM;KAAU,UAAU;IAAK;IACtD;KAAE,MAAM;KAAY,MAAM;KAAU,UAAU;IAAK;IACnD;KAAE,MAAM;KAAgB,MAAM;KAAU,UAAU;IAAK;IACvD;KAAE,MAAM;KAAa,MAAM;KAAU,UAAU;IAAK;IACpD;KAAE,MAAM;KAAU,MAAM;KAAU,UAAU;IAAK;GACnD;EACF;CACF;CACA,KAAK;AACP,CAAC"}
|
|
@@ -7,5 +7,7 @@ type BindingContext = Pick<StorefrontContext, 'bindingId' | 'basePath'>;
|
|
|
7
7
|
export declare function redirectToStorefrontPage(context: BindingContext, routeMap: RouteMap, target: PageRef | string): never;
|
|
8
8
|
/** Next's `permanentRedirect` to a page reference or a logical path, resolved for the binding. */
|
|
9
9
|
export declare function permanentRedirectToStorefrontPage(context: BindingContext, routeMap: RouteMap, target: PageRef | string): never;
|
|
10
|
+
/** Next's `redirect` to `resolveSignInHref`: the session gate's answer to an anonymous request. */
|
|
11
|
+
export declare function redirectToSignIn(context: BindingContext, routeMap: RouteMap, returnPath: string): never;
|
|
10
12
|
//#endregion
|
|
11
13
|
//# sourceMappingURL=redirect.d.ts.map
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { RETURN_URL_PARAM, resolveSiteRelativeHref, signInTarget } from "../../utils/safe-href.js";
|
|
1
2
|
import { resolveStorefrontHref } from "./resolve-storefront-href.js";
|
|
2
3
|
import { reportUnresolved } from "./report.js";
|
|
4
|
+
import { MOCK_SESSION_ROUTE, mockSessionToken } from "../session/mock-session.js";
|
|
3
5
|
import { permanentRedirect, redirect } from "next/navigation";
|
|
4
6
|
//#region src/sdk/navigation/redirect.ts
|
|
5
7
|
function resolveOrThrow(context, routeMap, target) {
|
|
@@ -16,7 +18,23 @@ function redirectToStorefrontPage(context, routeMap, target) {
|
|
|
16
18
|
function permanentRedirectToStorefrontPage(context, routeMap, target) {
|
|
17
19
|
return permanentRedirect(resolveOrThrow(context, routeMap, target));
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Where the session gate sends an anonymous request: the binding's sign-in page carrying `returnPath`, a
|
|
23
|
+
* logical path. With `FS_MOCK_SESSION` set it is the mock session handler instead, which lives outside
|
|
24
|
+
* every binding, so the return it carries is already the public path.
|
|
25
|
+
*/
|
|
26
|
+
function resolveSignInHref(context, routeMap, returnPath) {
|
|
27
|
+
if (mockSessionToken() === null) return resolveOrThrow(context, routeMap, signInTarget(returnPath));
|
|
28
|
+
const back = resolveStorefrontHref(context, routeMap, returnPath).href;
|
|
29
|
+
const destination = back === null ? null : resolveSiteRelativeHref(back);
|
|
30
|
+
if (!destination?.safe) return MOCK_SESSION_ROUTE;
|
|
31
|
+
return `${MOCK_SESSION_ROUTE}?${new URLSearchParams({ [RETURN_URL_PARAM]: destination.href })}`;
|
|
32
|
+
}
|
|
33
|
+
/** Next's `redirect` to `resolveSignInHref`: the session gate's answer to an anonymous request. */
|
|
34
|
+
function redirectToSignIn(context, routeMap, returnPath) {
|
|
35
|
+
return redirect(resolveSignInHref(context, routeMap, returnPath));
|
|
36
|
+
}
|
|
19
37
|
//#endregion
|
|
20
|
-
export { permanentRedirectToStorefrontPage, redirectToStorefrontPage };
|
|
38
|
+
export { permanentRedirectToStorefrontPage, redirectToSignIn, redirectToStorefrontPage, resolveSignInHref };
|
|
21
39
|
|
|
22
40
|
//# sourceMappingURL=redirect.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect.js","names":[],"sources":["../../../src/sdk/navigation/redirect.ts"],"sourcesContent":["import type { StorefrontContext } from '@vtex/fs-core';\nimport { permanentRedirect, redirect } from 'next/navigation';\nimport { reportUnresolved } from './report.js';\nimport { resolveStorefrontHref } from './resolve-storefront-href.js';\nimport type { PageRef, RouteMap } from './types.js';\n\ntype BindingContext = Pick<StorefrontContext, 'bindingId' | 'basePath'>;\n\nfunction resolveOrThrow(context: BindingContext, routeMap: RouteMap, target: PageRef | string): string {\n const result = resolveStorefrontHref(context, routeMap, target);\n if (result.href !== null) return result.href;\n reportUnresolved(result.reason, target);\n throw new Error(\n `Cannot redirect: ${JSON.stringify(target)} resolved to no href (${result.reason}) on ` +\n `binding ${JSON.stringify(context.bindingId)}.`,\n );\n}\n\n/** Next's `redirect` to a page reference or a logical path, resolved for the binding. */\nexport function redirectToStorefrontPage(context: BindingContext, routeMap: RouteMap, target: PageRef | string): never {\n return redirect(resolveOrThrow(context, routeMap, target));\n}\n\n/** Next's `permanentRedirect` to a page reference or a logical path, resolved for the binding. */\nexport function permanentRedirectToStorefrontPage(\n context: BindingContext,\n routeMap: RouteMap,\n target: PageRef | string,\n): never {\n return permanentRedirect(resolveOrThrow(context, routeMap, target));\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"redirect.js","names":[],"sources":["../../../src/sdk/navigation/redirect.ts"],"sourcesContent":["import type { StorefrontContext } from '@vtex/fs-core';\nimport { permanentRedirect, redirect } from 'next/navigation';\nimport { RETURN_URL_PARAM, resolveSiteRelativeHref, signInTarget } from '../../utils/safe-href.js';\nimport { MOCK_SESSION_ROUTE, mockSessionToken } from '../session/mock-session.js';\nimport { reportUnresolved } from './report.js';\nimport { resolveStorefrontHref } from './resolve-storefront-href.js';\nimport type { PageRef, RouteMap } from './types.js';\n\ntype BindingContext = Pick<StorefrontContext, 'bindingId' | 'basePath'>;\n\nfunction resolveOrThrow(context: BindingContext, routeMap: RouteMap, target: PageRef | string): string {\n const result = resolveStorefrontHref(context, routeMap, target);\n if (result.href !== null) return result.href;\n reportUnresolved(result.reason, target);\n throw new Error(\n `Cannot redirect: ${JSON.stringify(target)} resolved to no href (${result.reason}) on ` +\n `binding ${JSON.stringify(context.bindingId)}.`,\n );\n}\n\n/** Next's `redirect` to a page reference or a logical path, resolved for the binding. */\nexport function redirectToStorefrontPage(context: BindingContext, routeMap: RouteMap, target: PageRef | string): never {\n return redirect(resolveOrThrow(context, routeMap, target));\n}\n\n/** Next's `permanentRedirect` to a page reference or a logical path, resolved for the binding. */\nexport function permanentRedirectToStorefrontPage(\n context: BindingContext,\n routeMap: RouteMap,\n target: PageRef | string,\n): never {\n return permanentRedirect(resolveOrThrow(context, routeMap, target));\n}\n\n/**\n * Where the session gate sends an anonymous request: the binding's sign-in page carrying `returnPath`, a\n * logical path. With `FS_MOCK_SESSION` set it is the mock session handler instead, which lives outside\n * every binding, so the return it carries is already the public path.\n */\nexport function resolveSignInHref(context: BindingContext, routeMap: RouteMap, returnPath: string): string {\n if (mockSessionToken() === null) {\n return resolveOrThrow(context, routeMap, signInTarget(returnPath));\n }\n const back = resolveStorefrontHref(context, routeMap, returnPath).href;\n const destination = back === null ? null : resolveSiteRelativeHref(back);\n if (!destination?.safe) return MOCK_SESSION_ROUTE;\n return `${MOCK_SESSION_ROUTE}?${new URLSearchParams({ [RETURN_URL_PARAM]: destination.href })}`;\n}\n\n/** Next's `redirect` to `resolveSignInHref`: the session gate's answer to an anonymous request. */\nexport function redirectToSignIn(context: BindingContext, routeMap: RouteMap, returnPath: string): never {\n return redirect(resolveSignInHref(context, routeMap, returnPath));\n}\n"],"mappings":";;;;;;AAUA,SAAS,eAAe,SAAyB,UAAoB,QAAkC;CACrG,MAAM,SAAS,sBAAsB,SAAS,UAAU,MAAM;CAC9D,IAAI,OAAO,SAAS,MAAM,OAAO,OAAO;CACxC,iBAAiB,OAAO,QAAQ,MAAM;CACtC,MAAM,IAAI,MACR,oBAAoB,KAAK,UAAU,MAAM,EAAE,wBAAwB,OAAO,OAAO,eACpE,KAAK,UAAU,QAAQ,SAAS,EAAE,EACjD;AACF;;AAGA,SAAgB,yBAAyB,SAAyB,UAAoB,QAAiC;CACrH,OAAO,SAAS,eAAe,SAAS,UAAU,MAAM,CAAC;AAC3D;;AAGA,SAAgB,kCACd,SACA,UACA,QACO;CACP,OAAO,kBAAkB,eAAe,SAAS,UAAU,MAAM,CAAC;AACpE;;;;;;AAOA,SAAgB,kBAAkB,SAAyB,UAAoB,YAA4B;CACzG,IAAI,iBAAiB,MAAM,MACzB,OAAO,eAAe,SAAS,UAAU,aAAa,UAAU,CAAC;CAEnE,MAAM,OAAO,sBAAsB,SAAS,UAAU,UAAU,CAAC,CAAC;CAClE,MAAM,cAAc,SAAS,OAAO,OAAO,wBAAwB,IAAI;CACvE,IAAI,CAAC,aAAa,MAAM,OAAO;CAC/B,OAAO,GAAG,mBAAmB,GAAG,IAAI,gBAAgB,GAAG,mBAAmB,YAAY,KAAK,CAAC;AAC9F;;AAGA,SAAgB,iBAAiB,SAAyB,UAAoB,YAA2B;CACvG,OAAO,SAAS,kBAAkB,SAAS,UAAU,UAAU,CAAC;AAClE"}
|
|
@@ -26,6 +26,19 @@ export type RouteMapEntry = {
|
|
|
26
26
|
params?: string[];
|
|
27
27
|
aliases?: Record<string, string>;
|
|
28
28
|
bindings?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Set on a Search Landing Page: the term a singleton pins, as authored, or the content type and route
|
|
31
|
+
* parameter of the page over CMS term entries, whose item slug is the normalized term.
|
|
32
|
+
*/
|
|
33
|
+
searchTerm?: string | {
|
|
34
|
+
contentType: string;
|
|
35
|
+
param: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Set on an Entity Landing Page: the Relay node ID of the collection, category, or brand whose standard
|
|
39
|
+
* listing points its canonical here, the ID `catalogRoute` returns for that listing.
|
|
40
|
+
*/
|
|
41
|
+
canonicalFor?: string;
|
|
29
42
|
};
|
|
30
43
|
/** Keyed by page name. */
|
|
31
44
|
export type RouteMap = Record<string, RouteMapEntry>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isAcceptedCardBin } from "@vtex/fs-domain-logic/checkout/rules";
|
|
2
|
+
//#region src/sdk/payment/bin-format.ts
|
|
3
|
+
/**
|
|
4
|
+
* The browser-side use of the rule `paymentMethodSelect` applies to `bin`, so a malformed value never leaves
|
|
5
|
+
* through `payment.setMethod`. The rule itself lives in `@vtex/fs-domain-logic/checkout/rules`, shared with the
|
|
6
|
+
* server, so the two can no longer drift; the fixed refusal text lives there too. A new card (no `accountId`,
|
|
7
|
+
* or an empty one) carries nothing or exactly eight digits; a saved card carries nothing or one to eight,
|
|
8
|
+
* because the server compares it to the card's own stored BIN. `null` counts as nothing, like the server; any
|
|
9
|
+
* other value that is not a string is refused. Reads the value and returns a boolean: it never stores, logs or
|
|
10
|
+
* interpolates it.
|
|
11
|
+
*/
|
|
12
|
+
function isAcceptedBin({ bin, accountId }) {
|
|
13
|
+
if (bin === void 0 || bin === null || bin === "") return true;
|
|
14
|
+
if (typeof bin !== "string") return false;
|
|
15
|
+
return isAcceptedCardBin(bin, Boolean(accountId));
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { isAcceptedBin };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=bin-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin-format.js","names":[],"sources":["../../../src/sdk/payment/bin-format.ts"],"sourcesContent":["import { isAcceptedCardBin } from '@vtex/fs-domain-logic/checkout/rules';\n\n/**\n * The browser-side use of the rule `paymentMethodSelect` applies to `bin`, so a malformed value never leaves\n * through `payment.setMethod`. The rule itself lives in `@vtex/fs-domain-logic/checkout/rules`, shared with the\n * server, so the two can no longer drift; the fixed refusal text lives there too. A new card (no `accountId`,\n * or an empty one) carries nothing or exactly eight digits; a saved card carries nothing or one to eight,\n * because the server compares it to the card's own stored BIN. `null` counts as nothing, like the server; any\n * other value that is not a string is refused. Reads the value and returns a boolean: it never stores, logs or\n * interpolates it.\n */\nexport function isAcceptedBin({ bin, accountId }: Readonly<{ bin?: string | null; accountId?: string }>): boolean {\n if (bin === undefined || bin === null || bin === '') return true;\n if (typeof bin !== 'string') return false;\n return isAcceptedCardBin(bin, Boolean(accountId));\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,cAAc,EAAE,KAAK,aAA6E;CAChH,IAAI,QAAQ,KAAA,KAAa,QAAQ,QAAQ,QAAQ,IAAI,OAAO;CAC5D,IAAI,OAAO,QAAQ,UAAU,OAAO;CACpC,OAAO,kBAAkB,KAAK,QAAQ,SAAS,CAAC;AAClD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/sdk/payment/challenge-return.ts
|
|
2
|
+
/**
|
|
3
|
+
* The contract between the two ends of the 3D Secure round trip (T208, Decision 2): `usePlaceOrder` builds
|
|
4
|
+
* the return URL's query before the card is posted, and the `ChallengeReturn` page reads it back when the
|
|
5
|
+
* bank sends the shopper home. Both ends live here so they cannot drift apart.
|
|
6
|
+
*
|
|
7
|
+
* The query is the order group and a literal flag, nothing else. The group is the only key the gateway
|
|
8
|
+
* callback needs and it exists before the card is posted. The reader is strict because the page it feeds
|
|
9
|
+
* issues a write: exactly one `orderGroup` that fits `ORDER_GROUP_PATTERN` (which excludes `.`, so a dot
|
|
10
|
+
* segment cannot arrive) and `redirect` equal to the string `true`. Anything else the gateway or the bank
|
|
11
|
+
* appends is ignored, and never returned.
|
|
12
|
+
*/
|
|
13
|
+
const ORDER_GROUP_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
14
|
+
const GROUP_PARAM = "orderGroup";
|
|
15
|
+
const FLAG_PARAM = "redirect";
|
|
16
|
+
const FLAG_VALUE = "true";
|
|
17
|
+
/** The query for a group's return URL, or `null` when the group is not one a return page would accept. */
|
|
18
|
+
function buildChallengeReturnQuery(orderGroup) {
|
|
19
|
+
if (!ORDER_GROUP_PATTERN.test(orderGroup)) return null;
|
|
20
|
+
return {
|
|
21
|
+
[GROUP_PARAM]: orderGroup,
|
|
22
|
+
[FLAG_PARAM]: FLAG_VALUE
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** The order group a return URL's query names, or `null` for anything that is not exactly a return query. */
|
|
26
|
+
function readChallengeReturn(search) {
|
|
27
|
+
const params = new URLSearchParams(search);
|
|
28
|
+
const groups = params.getAll(GROUP_PARAM);
|
|
29
|
+
const [orderGroup] = groups;
|
|
30
|
+
if (groups.length !== 1 || orderGroup === void 0 || !ORDER_GROUP_PATTERN.test(orderGroup)) return null;
|
|
31
|
+
if (params.get(FLAG_PARAM) !== FLAG_VALUE) return null;
|
|
32
|
+
return { orderGroup };
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { buildChallengeReturnQuery, readChallengeReturn };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=challenge-return.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge-return.js","names":[],"sources":["../../../src/sdk/payment/challenge-return.ts"],"sourcesContent":["/**\n * The contract between the two ends of the 3D Secure round trip (T208, Decision 2): `usePlaceOrder` builds\n * the return URL's query before the card is posted, and the `ChallengeReturn` page reads it back when the\n * bank sends the shopper home. Both ends live here so they cannot drift apart.\n *\n * The query is the order group and a literal flag, nothing else. The group is the only key the gateway\n * callback needs and it exists before the card is posted. The reader is strict because the page it feeds\n * issues a write: exactly one `orderGroup` that fits `ORDER_GROUP_PATTERN` (which excludes `.`, so a dot\n * segment cannot arrive) and `redirect` equal to the string `true`. Anything else the gateway or the bank\n * appends is ignored, and never returned.\n */\n\nconst ORDER_GROUP_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;\n\nconst GROUP_PARAM = 'orderGroup';\nconst FLAG_PARAM = 'redirect';\nconst FLAG_VALUE = 'true';\n\n/** The query for a group's return URL, or `null` when the group is not one a return page would accept. */\nexport function buildChallengeReturnQuery(orderGroup: string): Record<string, string> | null {\n if (!ORDER_GROUP_PATTERN.test(orderGroup)) return null;\n return { [GROUP_PARAM]: orderGroup, [FLAG_PARAM]: FLAG_VALUE };\n}\n\n/** The order group a return URL's query names, or `null` for anything that is not exactly a return query. */\nexport function readChallengeReturn(search: string): { orderGroup: string } | null {\n const params = new URLSearchParams(search);\n const groups = params.getAll(GROUP_PARAM);\n const [orderGroup] = groups;\n if (groups.length !== 1 || orderGroup === undefined || !ORDER_GROUP_PATTERN.test(orderGroup)) return null;\n if (params.get(FLAG_PARAM) !== FLAG_VALUE) return null;\n return { orderGroup };\n}\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,sBAAsB;AAE5B,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,aAAa;;AAGnB,SAAgB,0BAA0B,YAAmD;CAC3F,IAAI,CAAC,oBAAoB,KAAK,UAAU,GAAG,OAAO;CAClD,OAAO;GAAG,cAAc;GAAa,aAAa;CAAW;AAC/D;;AAGA,SAAgB,oBAAoB,QAA+C;CACjF,MAAM,SAAS,IAAI,gBAAgB,MAAM;CACzC,MAAM,SAAS,OAAO,OAAO,WAAW;CACxC,MAAM,CAAC,cAAc;CACrB,IAAI,OAAO,WAAW,KAAK,eAAe,KAAA,KAAa,CAAC,oBAAoB,KAAK,UAAU,GAAG,OAAO;CACrG,IAAI,OAAO,IAAI,UAAU,MAAM,YAAY,OAAO;CAClD,OAAO,EAAE,WAAW;AACtB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/sdk/payment/confirmation-last-four.ts
|
|
3
|
+
const FOUR_ASCII_DIGITS = /^\d{4}$/;
|
|
4
|
+
const NOT_AN_ASCII_DIGIT = /\D/g;
|
|
5
|
+
const SHORTEST_NUMBER_LENGTH = 8;
|
|
6
|
+
let record = null;
|
|
7
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
8
|
+
function notify() {
|
|
9
|
+
for (const listener of listeners) listener();
|
|
10
|
+
}
|
|
11
|
+
function subscribe(listener) {
|
|
12
|
+
listeners.add(listener);
|
|
13
|
+
return () => {
|
|
14
|
+
listeners.delete(listener);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** The last four ASCII digits of `rawDigits` once every non-digit is removed; null below 8 digits. */
|
|
18
|
+
function lastFourOf(rawDigits) {
|
|
19
|
+
const digits = rawDigits.replaceAll(NOT_AN_ASCII_DIGIT, "");
|
|
20
|
+
return digits.length >= SHORTEST_NUMBER_LENGTH ? digits.slice(-4) : null;
|
|
21
|
+
}
|
|
22
|
+
/** Stores one record. Refuses (no-op) unless `lastFour` is exactly four ASCII digits and `orderGroup` is non-empty. */
|
|
23
|
+
function rememberConfirmationLastFour(orderGroup, lastFour) {
|
|
24
|
+
if (typeof orderGroup !== "string" || orderGroup === "") return;
|
|
25
|
+
if (typeof lastFour !== "string" || !FOUR_ASCII_DIGITS.test(lastFour)) return;
|
|
26
|
+
record = {
|
|
27
|
+
orderGroup,
|
|
28
|
+
lastFour
|
|
29
|
+
};
|
|
30
|
+
notify();
|
|
31
|
+
}
|
|
32
|
+
/** The four digits for this order group, or null. The server snapshot is always null. */
|
|
33
|
+
function useConfirmationLastFour(orderGroup) {
|
|
34
|
+
return useSyncExternalStore(subscribe, () => record !== null && orderGroup != null && record.orderGroup === orderGroup ? record.lastFour : null, () => null);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { lastFourOf, rememberConfirmationLastFour, useConfirmationLastFour };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=confirmation-last-four.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirmation-last-four.js","names":[],"sources":["../../../src/sdk/payment/confirmation-last-four.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react';\n\n/**\n * The masked last four of a newly typed payment instrument, carried in module memory from the place-order\n * step to the confirmation recap (T82, US-8). It holds one record: four ASCII digits and the order group\n * they belong to. It is never written to a storage API, a cookie, a URL, a header, a log, an analytics\n * event, a GraphQL variable or an error, and it is empty on the server and on first load.\n */\ntype ConfirmationLastFour = Readonly<{ orderGroup: string; lastFour: string }>;\n\nconst FOUR_ASCII_DIGITS = /^\\d{4}$/;\nconst NOT_AN_ASCII_DIGIT = /\\D/g;\nconst SHORTEST_NUMBER_LENGTH = 8;\n\nlet record: ConfirmationLastFour | null = null;\nconst listeners = new Set<() => void>();\n\nfunction notify(): void {\n for (const listener of listeners) listener();\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\n/** The last four ASCII digits of `rawDigits` once every non-digit is removed; null below 8 digits. */\nexport function lastFourOf(rawDigits: string): string | null {\n const digits = rawDigits.replaceAll(NOT_AN_ASCII_DIGIT, '');\n return digits.length >= SHORTEST_NUMBER_LENGTH ? digits.slice(-4) : null;\n}\n\n/** Stores one record. Refuses (no-op) unless `lastFour` is exactly four ASCII digits and `orderGroup` is non-empty. */\nexport function rememberConfirmationLastFour(orderGroup: string, lastFour: string): void {\n if (typeof orderGroup !== 'string' || orderGroup === '') return;\n if (typeof lastFour !== 'string' || !FOUR_ASCII_DIGITS.test(lastFour)) return;\n record = { orderGroup, lastFour };\n notify();\n}\n\n/** The current record, or null. */\nexport function readConfirmationLastFour(): ConfirmationLastFour | null {\n return record;\n}\n\n/** The four digits for this order group, or null. The server snapshot is always null. */\nexport function useConfirmationLastFour(orderGroup: string | null | undefined): string | null {\n return useSyncExternalStore(\n subscribe,\n () => (record !== null && orderGroup != null && record.orderGroup === orderGroup ? record.lastFour : null),\n () => null,\n );\n}\n\n/** Test seam: empties the record. */\nexport function clearConfirmationLastFour(): void {\n record = null;\n notify();\n}\n"],"mappings":";;AAUA,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B,MAAM,yBAAyB;AAE/B,IAAI,SAAsC;AAC1C,MAAM,4BAAY,IAAI,IAAgB;AAEtC,SAAS,SAAe;CACtB,KAAK,MAAM,YAAY,WAAW,SAAS;AAC7C;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CACtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;;AAGA,SAAgB,WAAW,WAAkC;CAC3D,MAAM,SAAS,UAAU,WAAW,oBAAoB,EAAE;CAC1D,OAAO,OAAO,UAAU,yBAAyB,OAAO,MAAM,EAAE,IAAI;AACtE;;AAGA,SAAgB,6BAA6B,YAAoB,UAAwB;CACvF,IAAI,OAAO,eAAe,YAAY,eAAe,IAAI;CACzD,IAAI,OAAO,aAAa,YAAY,CAAC,kBAAkB,KAAK,QAAQ,GAAG;CACvE,SAAS;EAAE;EAAY;CAAS;CAChC,OAAO;AACT;;AAQA,SAAgB,wBAAwB,YAAsD;CAC5F,OAAO,qBACL,iBACO,WAAW,QAAQ,cAAc,QAAQ,OAAO,eAAe,aAAa,OAAO,WAAW,YAC/F,IACR;AACF"}
|
|
@@ -38,7 +38,7 @@ export type PaymentGatewayTransaction = Readonly<{
|
|
|
38
38
|
installmentsValueInCents: number;
|
|
39
39
|
/** `PaymentInstallment.interestRate`; 0 for the interest-free 1x default. */
|
|
40
40
|
interestRate: number;
|
|
41
|
-
/** Absolute return URL.
|
|
41
|
+
/** Absolute return URL for the 3D Secure challenge. Omitted when the store authored no return page. */
|
|
42
42
|
callbackUrl?: string;
|
|
43
43
|
/**
|
|
44
44
|
* Billing differs from the delivery address. Defaults to `false`, because `setBillingAddress` persists
|
|
@@ -23,7 +23,10 @@ import { isTrustedGatewayOrigin } from "./gateway-origin.js";
|
|
|
23
23
|
*/
|
|
24
24
|
/** Client-synthesized code for a failed gateway leg — distinct from the BFF's `NETWORK_ERROR`. */
|
|
25
25
|
const PAYMENT_GATEWAY_ERROR_CODE = "GATEWAY_ERROR";
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* The single userError a rejected request, a non-2xx response and a request the builder refused all resolve to.
|
|
28
|
+
* Its `message` is diagnostic; `PlaceOrder` words the code.
|
|
29
|
+
*/
|
|
27
30
|
const PAYMENT_GATEWAY_USER_ERROR = {
|
|
28
31
|
code: PAYMENT_GATEWAY_ERROR_CODE,
|
|
29
32
|
message: "Unable to complete the payment. Please try again."
|
|
@@ -85,7 +88,10 @@ function buildGatewayPaymentsRequest({ transaction, card }) {
|
|
|
85
88
|
if (!isTrustedGatewayOrigin(transaction.gatewayUrl)) throw new Error("Refusing to post card data: the transaction carries no trusted https gateway origin.");
|
|
86
89
|
const params = new URLSearchParams({ orderId: transaction.orderGroup });
|
|
87
90
|
if (transaction.userProfileId !== null) params.append("userProfileId", transaction.userProfileId);
|
|
88
|
-
if (transaction.callbackUrl !== void 0)
|
|
91
|
+
if (transaction.callbackUrl !== void 0) {
|
|
92
|
+
params.append("callbackUrl", transaction.callbackUrl);
|
|
93
|
+
params.append("redirect", "false");
|
|
94
|
+
}
|
|
89
95
|
const transactionId = encodeURIComponent(transaction.transactionId);
|
|
90
96
|
const url = `${transaction.gatewayUrl}/api/payments/transactions/${transactionId}/payments?${params}`;
|
|
91
97
|
const { bin, fields } = toCardBody(card);
|