@vtex/faststore 0.0.6 → 0.0.8
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 +99 -0
- package/dist/actions.json +152 -1
- package/dist/catalog.json +2541 -1278
- package/dist/cli/UnreachableCaseError-Crd168Vu.js +10 -0
- package/dist/cli/UnreachableCaseError-Crd168Vu.js.map +1 -0
- package/dist/cli/cacheControl-CEojH_TM.js +158 -0
- package/dist/cli/cacheControl-CEojH_TM.js.map +1 -0
- package/dist/cli/cachePolicy-m2vASMRW.js +26 -0
- package/dist/cli/cachePolicy-m2vASMRW.js.map +1 -0
- package/dist/cli/computeCoreSchemaHash-DPJZj-qJ.js +10 -0
- package/dist/cli/computeCoreSchemaHash-DPJZj-qJ.js.map +1 -0
- package/dist/cli/default-BCQHcwbL.js +253 -0
- package/dist/cli/default-BCQHcwbL.js.map +1 -0
- package/dist/cli/disableSuggestions-yO9UqiWn.js +21 -0
- package/dist/cli/disableSuggestions-yO9UqiWn.js.map +1 -0
- package/dist/cli/dist-C1JhdHfo.js +2001 -0
- package/dist/cli/dist-C1JhdHfo.js.map +1 -0
- package/dist/cli/graphql-DG9thCDG.js +14589 -0
- package/dist/cli/graphql-DG9thCDG.js.map +1 -0
- package/dist/cli/index.d.ts +799 -0
- package/dist/cli/index.js +36459 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.min-BsIHDfFK.js +613 -0
- package/dist/cli/index.min-BsIHDfFK.js.map +1 -0
- package/dist/cli/inlineTrace-uLgOJ3TH.js +52 -0
- package/dist/cli/inlineTrace-uLgOJ3TH.js.map +1 -0
- package/dist/cli/internalPlugin-DnuwN4_4.js +11 -0
- package/dist/cli/internalPlugin-DnuwN4_4.js.map +1 -0
- package/dist/cli/packageVersion-DQAnIEil.js +6 -0
- package/dist/cli/packageVersion-DQAnIEil.js.map +1 -0
- package/dist/cli/rolldown-runtime-BMI-E3GI.js +44 -0
- package/dist/cli/schemaIsSubgraph-DoGh3OYj.js +17 -0
- package/dist/cli/schemaIsSubgraph-DoGh3OYj.js.map +1 -0
- package/dist/cli/schemaReporting-K-me-3-v.js +199 -0
- package/dist/cli/schemaReporting-K-me-3-v.js.map +1 -0
- package/dist/cli/server-runtime.js +49879 -0
- package/dist/cli/server-runtime.js.map +1 -0
- package/dist/cli/traceTreeBuilder-BIcV2U7b.js +9118 -0
- package/dist/cli/traceTreeBuilder-BIcV2U7b.js.map +1 -0
- package/dist/cli/usageReporting-Bpl8vSZX.js +10201 -0
- package/dist/cli/usageReporting-Bpl8vSZX.js.map +1 -0
- package/dist/cli/v4-CBhFvC49.js +42 -0
- package/dist/cli/v4-CBhFvC49.js.map +1 -0
- package/dist/client.d.ts +5 -1
- package/dist/client.js +5 -1
- package/dist/components.d.ts +38 -9
- package/dist/components.js +42 -13
- package/dist/content-types.json +616 -0
- package/dist/core/dist/define-component.d.ts +43 -1
- package/dist/core/dist/index.d.ts +2 -2
- package/dist/docs/account-access-gate.md +4 -4
- package/dist/docs/account-address-book.md +519 -0
- package/dist/docs/account-entry-point.md +1 -1
- package/dist/docs/account-menu-identity.md +160 -0
- package/dist/docs/account-menu.md +107 -24
- package/dist/docs/alert-dialog.md +2 -2
- package/dist/docs/avatar.md +103 -0
- package/dist/docs/billing-address.md +17 -9
- package/dist/docs/card-entry.md +37 -6
- package/dist/docs/cardholder-document.md +16 -14
- package/dist/docs/cart-item.md +1 -1
- package/dist/docs/cart.md +8 -8
- package/dist/docs/client-profile-fieldset.md +7 -5
- package/dist/docs/copy-text.md +84 -0
- package/dist/docs/document-field.md +8 -8
- package/dist/docs/footer-link-group.md +2 -2
- package/dist/docs/header-root.md +1 -1
- package/dist/docs/incentives.md +2 -2
- package/dist/docs/logo.md +5 -5
- package/dist/docs/my-account-profile.md +5 -5
- package/dist/docs/navigation-link-list.md +2 -2
- package/dist/docs/navigation-link.md +3 -3
- package/dist/docs/order-cancel.md +52 -0
- package/dist/docs/order-delivery-address.md +63 -0
- package/dist/docs/order-delivery-group.md +83 -0
- package/dist/docs/order-details-back.md +41 -0
- package/dist/docs/order-details-header.md +48 -0
- package/dist/docs/order-list-row.md +46 -0
- package/dist/docs/order-list-search.md +101 -0
- package/dist/docs/order-list-views.md +97 -0
- package/dist/docs/order-list.md +94 -0
- package/dist/docs/order-payment.md +94 -0
- package/dist/docs/order-placed-date.md +49 -0
- package/dist/docs/order-placed-payment-summary.md +13 -15
- package/dist/docs/order-placed.md +225 -0
- package/dist/docs/order-progress.md +88 -0
- package/dist/docs/order-status-badge.md +91 -0
- package/dist/docs/order-summary.md +53 -0
- package/dist/docs/payment-method-badges.md +14 -3
- package/dist/docs/place-order.md +13 -9
- package/dist/docs/product-shelf.md +20 -13
- package/dist/docs/saved-cards.md +2 -2
- package/dist/docs/select.md +19 -6
- package/dist/docs/session.md +1 -1
- package/dist/docs/shipping-address.md +1 -1
- package/dist/docs/sign-in-redirect.md +6 -6
- package/dist/docs/toast.md +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +2 -1
- package/dist/internal/client.d.ts +6 -1
- package/dist/internal/client.js +8 -3
- package/dist/internal/content.d.ts +2 -2
- package/dist/internal/server.d.ts +8 -1
- package/dist/internal/server.js +8 -1
- package/dist/matter/account-access-gate/account-access-gate.d.ts +2 -1
- package/dist/matter/account-access-gate/account-access-gate.js +19 -16
- package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
- package/dist/matter/account-address-book/account-address-book-delete.d.ts +60 -0
- package/dist/matter/account-address-book/account-address-book-delete.js +184 -0
- package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +19 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.js +50 -0
- package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +42 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.js +146 -0
- package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +25 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.js +72 -0
- package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -0
- package/dist/matter/account-address-book/account-address-book.d.ts +120 -0
- package/dist/matter/account-address-book/account-address-book.js +469 -0
- package/dist/matter/account-address-book/account-address-book.js.map +1 -0
- package/dist/matter/account-address-book/account-address-country-switch.js +59 -0
- package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -0
- package/dist/matter/account-address-book/account-address-country.d.ts +36 -0
- package/dist/matter/account-address-book/account-address-country.js +151 -0
- package/dist/matter/account-address-book/account-address-country.js.map +1 -0
- package/dist/matter/account-address-book/account-address-first-line.js +11 -0
- package/dist/matter/account-address-book/account-address-first-line.js.map +1 -0
- package/dist/matter/account-address-book/account-address-form-context.d.ts +55 -0
- package/dist/matter/account-address-book/account-address-form-context.js +14 -0
- package/dist/matter/account-address-book/account-address-form-context.js.map +1 -0
- package/dist/matter/account-address-book/account-address-form.d.ts +85 -0
- package/dist/matter/account-address-book/account-address-form.js +946 -0
- package/dist/matter/account-address-book/account-address-form.js.map +1 -0
- package/dist/matter/account-address-book/account-address-postal-autofill.js +189 -0
- package/dist/matter/account-address-book/account-address-postal-autofill.js.map +1 -0
- package/dist/matter/account-address-book/account-address-record.d.ts +26 -0
- package/dist/matter/account-address-book/account-address-record.js +138 -0
- package/dist/matter/account-address-book/account-address-record.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.js +11 -11
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +77 -3
- package/dist/matter/account-menu/account-menu.js +252 -19
- package/dist/matter/account-menu/account-menu.js.map +1 -1
- package/dist/matter/account-menu/sign-out-failure.js +50 -0
- package/dist/matter/account-menu/sign-out-failure.js.map +1 -0
- package/dist/matter/account-menu-identity/account-menu-identity.d.ts +21 -0
- package/dist/matter/account-menu-identity/account-menu-identity.js +88 -0
- package/dist/matter/account-menu-identity/account-menu-identity.js.map +1 -0
- package/dist/matter/billing-address/billing-address.d.ts +30 -17
- package/dist/matter/billing-address/billing-address.js +128 -33
- package/dist/matter/billing-address/billing-address.js.map +1 -1
- package/dist/matter/breadcrumb/breadcrumb.js +2 -2
- package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/matter/card-entry/card-capture.js +4 -3
- package/dist/matter/card-entry/card-capture.js.map +1 -1
- package/dist/matter/card-entry/card-entry.d.ts +5 -3
- package/dist/matter/card-entry/card-entry.js +78 -27
- package/dist/matter/card-entry/card-entry.js.map +1 -1
- package/dist/matter/cardholder-document/cardholder-document.d.ts +10 -9
- package/dist/matter/cardholder-document/cardholder-document.js +36 -16
- package/dist/matter/cardholder-document/cardholder-document.js.map +1 -1
- package/dist/matter/cart/cart.d.ts +7 -2
- package/dist/matter/cart/cart.js +29 -26
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/cart-item/cart-item.js +2 -2
- package/dist/matter/cart-item/cart-item.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences-fieldset.js +2 -2
- package/dist/matter/client-profile-form/client-profile-fieldset.js +9 -6
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.js +3 -3
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.js +4 -3
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/my-account-profile/my-account-profile.d.ts +6 -3
- package/dist/matter/my-account-profile/my-account-profile.js +6 -5
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-cancel/order-cancel.d.ts +110 -0
- package/dist/matter/order-cancel/order-cancel.js +344 -0
- package/dist/matter/order-cancel/order-cancel.js.map +1 -0
- package/dist/matter/order-delivery-address/order-delivery-address.d.ts +73 -0
- package/dist/matter/order-delivery-address/order-delivery-address.js +172 -0
- package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -0
- package/dist/matter/order-delivery-group/order-delivery-group.d.ts +128 -0
- package/dist/matter/order-delivery-group/order-delivery-group.js +408 -0
- package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -0
- package/dist/matter/order-details-header/order-details-header.d.ts +104 -0
- package/dist/matter/order-details-header/order-details-header.js +190 -0
- package/dist/matter/order-details-header/order-details-header.js.map +1 -0
- package/dist/matter/order-list/customer-orders-filter.d.ts +12 -0
- package/dist/matter/order-list/customer-orders-filter.js +30 -0
- package/dist/matter/order-list/customer-orders-filter.js.map +1 -0
- package/dist/matter/order-list/order-list.d.ts +121 -0
- package/dist/matter/order-list/order-list.js +395 -0
- package/dist/matter/order-list/order-list.js.map +1 -0
- package/dist/matter/order-list-row/order-list-row.d.ts +44 -0
- package/dist/matter/order-list-row/order-list-row.js +127 -0
- package/dist/matter/order-list-row/order-list-row.js.map +1 -0
- package/dist/matter/order-list-search/order-list-search.d.ts +72 -0
- package/dist/matter/order-list-search/order-list-search.js +296 -0
- package/dist/matter/order-list-search/order-list-search.js.map +1 -0
- package/dist/matter/order-list-views/order-list-views.d.ts +65 -0
- package/dist/matter/order-list-views/order-list-views.js +154 -0
- package/dist/matter/order-list-views/order-list-views.js.map +1 -0
- package/dist/matter/order-payment/order-payment.d.ts +83 -0
- package/dist/matter/order-payment/order-payment.js +258 -0
- package/dist/matter/order-payment/order-payment.js.map +1 -0
- package/dist/matter/order-placed/order-placed-deliveries.d.ts +145 -0
- package/dist/matter/order-placed/order-placed-deliveries.js +380 -0
- package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -0
- package/dist/matter/order-placed/order-placed.d.ts +122 -0
- package/dist/matter/order-placed/order-placed.js +452 -0
- package/dist/matter/order-placed/order-placed.js.map +1 -0
- package/dist/matter/order-placed-date/order-placed-date.d.ts +45 -0
- package/dist/matter/order-placed-date/order-placed-date.js +92 -0
- package/dist/matter/order-placed-date/order-placed-date.js.map +1 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +5 -8
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +29 -81
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
- package/dist/matter/order-progress/order-progress.d.ts +85 -0
- package/dist/matter/order-progress/order-progress.js +203 -0
- package/dist/matter/order-progress/order-progress.js.map +1 -0
- package/dist/matter/order-summary/order-summary.d.ts +81 -0
- package/dist/matter/order-summary/order-summary.js +192 -0
- package/dist/matter/order-summary/order-summary.js.map +1 -0
- package/dist/matter/payment/cardholder-document-rule.d.ts +35 -0
- package/dist/matter/payment/cardholder-document-rule.js +35 -0
- package/dist/matter/payment/cardholder-document-rule.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.js +38 -23
- package/dist/matter/payment/payment-card-capture.js.map +1 -1
- package/dist/matter/payment/payment-controller.js +12 -0
- package/dist/matter/payment/payment-controller.js.map +1 -1
- package/dist/matter/payment/payment-method-badges.js +4 -2
- package/dist/matter/payment/payment-method-badges.js.map +1 -1
- package/dist/matter/payment/payment.js +12 -0
- package/dist/matter/payment/payment.js.map +1 -1
- package/dist/matter/payment/use-payment-method-selection.d.ts +39 -0
- package/dist/matter/payment/use-payment-method-selection.js +30 -2
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
- package/dist/matter/payment/use-payment-submit-gate.d.ts +16 -2
- package/dist/matter/payment/use-payment-submit-gate.js +42 -14
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
- package/dist/matter/place-order/place-order.d.ts +12 -7
- package/dist/matter/place-order/place-order.js +126 -103
- package/dist/matter/place-order/place-order.js.map +1 -1
- package/dist/matter/pricing/pricing.js +5 -5
- package/dist/matter/pricing/pricing.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +61 -31
- package/dist/matter/product-shelf/product-shelf.js +157 -57
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.js +1 -1
- package/dist/matter/saved-cards/saved-cards.js +27 -15
- package/dist/matter/saved-cards/saved-cards.js.map +1 -1
- package/dist/matter/session/session.js +2 -2
- package/dist/matter/session/session.js.map +1 -1
- package/dist/matter/shipping-address/country-descriptors.d.ts +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +23 -1
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.js +63 -15
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.d.ts +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/sign-in-redirect/sign-in-redirect.js +48 -10
- package/dist/matter/sign-in-redirect/sign-in-redirect.js.map +1 -1
- package/dist/matter/variant-selector/variant-selector.js +2 -2
- package/dist/matter/variant-selector/variant-selector.js.map +1 -1
- package/dist/particles/address-summary/address-summary.js +2 -2
- package/dist/particles/address-summary/address-summary.js.map +1 -1
- package/dist/particles/alert-dialog/alert-dialog.d.ts +5 -1
- package/dist/particles/alert-dialog/alert-dialog.js +5 -2
- package/dist/particles/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/particles/avatar/avatar.d.ts +17 -0
- package/dist/particles/avatar/avatar.js +65 -0
- package/dist/particles/avatar/avatar.js.map +1 -0
- package/dist/particles/copy-text/copy-text.d.ts +28 -0
- package/dist/particles/copy-text/copy-text.js +140 -0
- package/dist/particles/copy-text/copy-text.js.map +1 -0
- package/dist/particles/document-field/document-field.d.ts +34 -5
- package/dist/particles/document-field/document-field.js +115 -19
- package/dist/particles/document-field/document-field.js.map +1 -1
- package/dist/particles/field/field.js +1 -1
- package/dist/particles/field/field.js.map +1 -1
- package/dist/particles/footer-link-group/footer-link-group.d.ts +6 -2
- package/dist/particles/footer-link-group/footer-link-group.js +18 -7
- package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
- package/dist/particles/incentives/incentives.d.ts +6 -2
- package/dist/particles/incentives/incentives.js +7 -2
- package/dist/particles/incentives/incentives.js.map +1 -1
- package/dist/particles/logo/logo.d.ts +3 -2
- package/dist/particles/logo/logo.js +20 -8
- package/dist/particles/logo/logo.js.map +1 -1
- package/dist/particles/navigation-link/navigation-link.d.ts +2 -3
- package/dist/particles/navigation-link/navigation-link.js +4 -4
- package/dist/particles/navigation-link/navigation-link.js.map +1 -1
- package/dist/particles/navigation-link-list/navigation-link-list.d.ts +6 -2
- package/dist/particles/navigation-link-list/navigation-link-list.js +18 -7
- package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -1
- package/dist/particles/order-details-back/order-details-back.d.ts +28 -0
- package/dist/particles/order-details-back/order-details-back.js +52 -0
- package/dist/particles/order-details-back/order-details-back.js.map +1 -0
- package/dist/particles/order-status-badge/order-status-badge.d.ts +19 -0
- package/dist/particles/order-status-badge/order-status-badge.js +50 -0
- package/dist/particles/order-status-badge/order-status-badge.js.map +1 -0
- package/dist/particles/phone-field/phone-field.js +2 -2
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/select/select.js +6 -6
- package/dist/particles/select/select.js.map +1 -1
- package/dist/particles/toast/toast.d.ts +1 -1
- package/dist/particles/toast/toast.js +32 -6
- package/dist/particles/toast/toast.js.map +1 -1
- package/dist/schema.graphql +1079 -54
- package/dist/sdk/actions/address-action-provider.d.ts +16 -0
- package/dist/sdk/actions/address-action-provider.js +20 -0
- package/dist/sdk/actions/address-action-provider.js.map +1 -0
- package/dist/sdk/actions/analytics-action-provider.js +1 -1
- package/dist/sdk/actions/index.d.ts +3 -1
- package/dist/sdk/actions/index.js +3 -1
- package/dist/sdk/actions/order-action-provider.d.ts +12 -0
- package/dist/sdk/actions/order-action-provider.js +16 -0
- package/dist/sdk/actions/order-action-provider.js.map +1 -0
- package/dist/sdk/actions/types.d.ts +6 -2
- package/dist/sdk/address/address-fields.js +38 -0
- package/dist/sdk/address/address-fields.js.map +1 -0
- package/dist/sdk/address/checkout-readiness.js +17 -0
- package/dist/sdk/address/checkout-readiness.js.map +1 -0
- package/dist/sdk/address/constants.js +60 -0
- package/dist/sdk/address/constants.js.map +1 -0
- package/dist/sdk/address/country-display.js +19 -0
- package/dist/sdk/address/country-display.js.map +1 -0
- package/dist/sdk/address/country-rules.js +30 -0
- package/dist/sdk/address/country-rules.js.map +1 -0
- package/dist/sdk/address/format-address.js +18 -0
- package/dist/sdk/address/format-address.js.map +1 -0
- package/dist/sdk/address/iso-countries.js +262 -0
- package/dist/sdk/address/iso-countries.js.map +1 -0
- package/dist/sdk/address/layouts.js +56 -0
- package/dist/sdk/address/layouts.js.map +1 -0
- package/dist/sdk/address/messages.js +97 -0
- package/dist/sdk/address/messages.js.map +1 -0
- package/dist/sdk/address/operations.d.ts +54 -0
- package/dist/sdk/address/operations.js +83 -0
- package/dist/sdk/address/operations.js.map +1 -0
- package/dist/sdk/address/postal-code-lookup-operations.js +23 -0
- package/dist/sdk/address/postal-code-lookup-operations.js.map +1 -0
- package/dist/sdk/address/postal-code.js +11 -0
- package/dist/sdk/address/postal-code.js.map +1 -0
- package/dist/sdk/address/schema.js +14 -0
- package/dist/sdk/address/schema.js.map +1 -0
- package/dist/sdk/address/server-fields.js +25 -0
- package/dist/sdk/address/server-fields.js.map +1 -0
- package/dist/sdk/address/switch-country.js +57 -0
- package/dist/sdk/address/switch-country.js.map +1 -0
- package/dist/sdk/address/types.d.ts +26 -0
- package/dist/sdk/address/use-address-actions.d.ts +29 -0
- package/dist/sdk/address/use-address-actions.js +247 -0
- package/dist/sdk/address/use-address-actions.js.map +1 -0
- package/dist/sdk/address/use-address-by-postal-code.js +57 -0
- package/dist/sdk/address/use-address-by-postal-code.js.map +1 -0
- package/dist/sdk/address/validate-address.js +62 -0
- package/dist/sdk/address/validate-address.js.map +1 -0
- package/dist/sdk/analytics/use-analytics-actions.js +2 -1
- package/dist/sdk/analytics/use-analytics-actions.js.map +1 -1
- package/dist/sdk/cache/storefront-cache.js +29 -4
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.js +9 -8
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js +2 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
- package/dist/sdk/client/fetch-page-data.d.ts +11 -0
- package/dist/sdk/client/fetch-page-data.js +12 -1
- package/dist/sdk/client/fetch-page-data.js.map +1 -1
- package/dist/sdk/content/create-content-runtime.d.ts +22 -1
- package/dist/sdk/content/create-content-runtime.js +90 -9
- package/dist/sdk/content/create-content-runtime.js.map +1 -1
- package/dist/sdk/data/empty-content-value.js +16 -0
- package/dist/sdk/data/empty-content-value.js.map +1 -0
- package/dist/sdk/data/failed-fields.js +23 -0
- package/dist/sdk/data/failed-fields.js.map +1 -0
- package/dist/sdk/data/hot-data-provider.js +2 -1
- package/dist/sdk/data/hot-data-provider.js.map +1 -1
- package/dist/sdk/data/index.js +1 -1
- package/dist/sdk/data/page-reactive-data-root.d.ts +45 -7
- package/dist/sdk/data/page-reactive-data-root.js +88 -12
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
- package/dist/sdk/data/variables-from-content.d.ts +43 -0
- package/dist/sdk/data/variables-from-content.js +57 -0
- package/dist/sdk/data/variables-from-content.js.map +1 -0
- package/dist/sdk/generated/fragment-types.js +2 -0
- package/dist/sdk/generated/fragment-types.js.map +1 -1
- package/dist/sdk/generated/gql.js +4 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.d.ts +8 -0
- package/dist/sdk/generated/graphql.js +296 -1
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/messages/en-US.js +138 -1
- package/dist/sdk/i18n/messages/en-US.json +138 -1
- package/dist/sdk/i18n/messages/en-US.json.d.ts +137 -0
- package/dist/sdk/i18n/messages/es-ES.js +138 -1
- package/dist/sdk/i18n/messages/es-ES.json +138 -1
- package/dist/sdk/i18n/messages/pt-BR.js +138 -1
- package/dist/sdk/i18n/messages/pt-BR.json +138 -1
- package/dist/sdk/identity/use-identity-actions.js +5 -4
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/navigation/current-page.js +30 -0
- package/dist/sdk/navigation/current-page.js.map +1 -0
- package/dist/sdk/navigation/not-found-log.d.ts +28 -0
- package/dist/sdk/navigation/not-found-log.js +133 -0
- package/dist/sdk/navigation/not-found-log.js.map +1 -0
- package/dist/sdk/navigation/path.js +25 -0
- package/dist/sdk/navigation/path.js.map +1 -0
- package/dist/sdk/navigation/redirect.d.ts +11 -0
- package/dist/sdk/navigation/redirect.js +22 -0
- package/dist/sdk/navigation/redirect.js.map +1 -0
- package/dist/sdk/navigation/report.js +70 -0
- package/dist/sdk/navigation/report.js.map +1 -0
- package/dist/sdk/navigation/resolve-storefront-href.d.ts +12 -0
- package/dist/sdk/navigation/resolve-storefront-href.js +214 -0
- package/dist/sdk/navigation/resolve-storefront-href.js.map +1 -0
- package/dist/sdk/navigation/route-identity-provider.d.ts +11 -0
- package/dist/sdk/navigation/route-identity-provider.js +20 -0
- package/dist/sdk/navigation/route-identity-provider.js.map +1 -0
- package/dist/sdk/navigation/route-map-provider.d.ts +19 -0
- package/dist/sdk/navigation/route-map-provider.js +29 -0
- package/dist/sdk/navigation/route-map-provider.js.map +1 -0
- package/dist/sdk/navigation/storefront-link.d.ts +16 -0
- package/dist/sdk/navigation/storefront-link.js +66 -0
- package/dist/sdk/navigation/storefront-link.js.map +1 -0
- package/dist/sdk/navigation/types.d.ts +45 -0
- package/dist/sdk/navigation/use-storefront-navigation.d.ts +26 -0
- package/dist/sdk/navigation/use-storefront-navigation.js +73 -0
- package/dist/sdk/navigation/use-storefront-navigation.js.map +1 -0
- package/dist/sdk/navigation/use-storefront-route.d.ts +26 -0
- package/dist/sdk/navigation/use-storefront-route.js +87 -0
- package/dist/sdk/navigation/use-storefront-route.js.map +1 -0
- package/dist/sdk/navigation/use-storefront-search-params.d.ts +11 -0
- package/dist/sdk/navigation/use-storefront-search-params.js +16 -0
- package/dist/sdk/navigation/use-storefront-search-params.js.map +1 -0
- package/dist/sdk/orders/completion-badge.d.ts +8 -0
- package/dist/sdk/orders/completion-badge.js +47 -0
- package/dist/sdk/orders/completion-badge.js.map +1 -0
- package/dist/sdk/orders/order-operations.d.ts +19 -0
- package/dist/sdk/orders/order-operations.js +21 -0
- package/dist/sdk/orders/order-operations.js.map +1 -0
- package/dist/sdk/orders/use-order-actions.d.ts +23 -0
- package/dist/sdk/orders/use-order-actions.js +62 -0
- package/dist/sdk/orders/use-order-actions.js.map +1 -0
- package/dist/sdk/payment/gateway-origin.js +26 -13
- package/dist/sdk/payment/gateway-origin.js.map +1 -1
- package/dist/sdk/payment/gateway.d.ts +14 -2
- package/dist/sdk/payment/gateway.js +32 -14
- package/dist/sdk/payment/gateway.js.map +1 -1
- package/dist/sdk/payment/operations.js +11 -0
- package/dist/sdk/payment/operations.js.map +1 -1
- package/dist/sdk/payment/submission-registry.d.ts +2 -1
- package/dist/sdk/payment/submission-registry.js +12 -8
- package/dist/sdk/payment/submission-registry.js.map +1 -1
- package/dist/sdk/payment/use-payment-actions.d.ts +5 -3
- package/dist/sdk/payment/use-payment-actions.js +6 -3
- package/dist/sdk/payment/use-payment-actions.js.map +1 -1
- package/dist/sdk/payment/use-place-order.d.ts +6 -3
- package/dist/sdk/payment/use-place-order.js +334 -144
- package/dist/sdk/payment/use-place-order.js.map +1 -1
- package/dist/sdk/region/use-region-actions.js +2 -1
- package/dist/sdk/region/use-region-actions.js.map +1 -1
- package/dist/sdk/seo/page-alternates.d.ts +55 -0
- package/dist/sdk/seo/page-alternates.js +132 -0
- package/dist/sdk/seo/page-alternates.js.map +1 -0
- package/dist/sdk/session/read-server-session.d.ts +21 -0
- package/dist/sdk/session/read-server-session.js +61 -0
- package/dist/sdk/session/read-server-session.js.map +1 -0
- package/dist/sdk/session/use-session-actions.js +5 -4
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/session/use-session-revalidation.js +2 -1
- package/dist/sdk/session/use-session-revalidation.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.js +3 -2
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/utils/own-value.js +19 -0
- package/dist/utils/own-value.js.map +1 -0
- package/dist/utils/safe-href.d.ts +11 -0
- package/dist/utils/safe-href.js +31 -22
- package/dist/utils/safe-href.js.map +1 -1
- package/package.json +17 -2
- package/skills/storefront-asset/SKILL.md +111 -0
- package/skills/storefront-asset/references/api-side.md +153 -0
- package/skills/storefront-asset/references/findings.md +40 -0
- package/skills/storefront-asset/references/ui-side.md +94 -0
- package/src/styles/tailwind.css +27 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-alternates.js","names":[],"sources":["../../../src/sdk/seo/page-alternates.ts"],"sourcesContent":["import { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { graphql } from '../generated/gql.js';\nimport type { CatalogRouteAlternatesQuery } from '../generated/graphql.js';\n\nexport type AlternateBinding = { bindingId: string; locale: string };\n\nexport type RouteVariant = NonNullable<CatalogRouteAlternatesQuery['catalogRoute']>['variants'][number];\n\n/** Structurally assignable to Next.js `Metadata['alternates']`. */\nexport type PageAlternates = {\n canonical: string;\n /** BCP 47 tag or `x-default` -> absolute URL. */\n languages?: Record<string, string>;\n};\n\nexport type RouteParams = Readonly<Record<string, string | string[] | undefined>>;\n\nexport type BuildPageAlternatesOptions = {\n bindingId: string;\n defaultBindingId: string;\n /** Every declared binding, in authoring order. */\n bindings: readonly AlternateBinding[];\n /** Decoded logical path of the request. */\n selfPath: string;\n /** Binding id -> decoded logical path, for the cluster members only. `null` means no cluster source. */\n clusterPaths: Readonly<Record<string, string>> | null;\n buildUrl: (bindingId: string, logicalPath: string) => string;\n};\n\n/**\n * The only GraphQL text the alternates feature owns. `catalogClusterPaths` reads its result, and the\n * package tests validate it against the Storefront API schema.\n */\nexport const CATALOG_ROUTE_ALTERNATES_QUERY = graphql(`\n query CatalogRouteAlternates($path: String!) {\n catalogRoute(input: { path: $path }) {\n variants {\n locale\n path\n }\n }\n }\n`);\n\n/** Encodes each segment and keeps `/` literal, so a decoded path is encoded exactly once. */\nfunction encodePath(path: string): string {\n return path.split('/').map(encodeURIComponent).join('/');\n}\n\n/**\n * One binding per locale: `hreflang` maps a tag to a single URL. The default binding represents a\n * locale it declares; otherwise the first binding declaring it does.\n */\nfunction representatives(bindings: readonly AlternateBinding[], defaultBindingId: string): AlternateBinding[] {\n const byLocale = new Map<string, AlternateBinding>();\n for (const binding of bindings) {\n const key = binding.locale.toLowerCase();\n const current = byLocale.get(key);\n if (!current || binding.bindingId === defaultBindingId) byLocale.set(key, binding);\n }\n return bindings.filter((binding) => byLocale.get(binding.locale.toLowerCase()) === binding);\n}\n\n/**\n * The canonical URL plus, when a reciprocal cluster exists, `languages`. A cluster needs two members\n * and must include the rendered binding: search engines ignore a set that does not reference itself.\n */\nexport function buildPageAlternates({\n bindingId,\n defaultBindingId,\n bindings,\n selfPath,\n clusterPaths,\n buildUrl,\n}: BuildPageAlternatesOptions): PageAlternates {\n const url = (id: string, path: string) => buildUrl(id, encodePath(path));\n const pathOf = (id: string) => (clusterPaths && Object.hasOwn(clusterPaths, id) ? clusterPaths[id] : undefined);\n const canonical = url(bindingId, pathOf(bindingId) ?? selfPath);\n\n const members = representatives(bindings, defaultBindingId).flatMap((binding) => {\n const path = pathOf(binding.bindingId);\n return path === undefined ? [] : [{ ...binding, href: url(binding.bindingId, path) }];\n });\n if (members.length < 2 || !members.some((member) => member.bindingId === bindingId)) return { canonical };\n\n const languages: Record<string, string> = {};\n for (const member of members) languages[member.locale] = member.href;\n const defaultMember = members.find((member) => member.bindingId === defaultBindingId);\n if (defaultMember) languages['x-default'] = defaultMember.href;\n return { canonical, languages };\n}\n\nfunction decodeSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/** `.` and `..` would make the URL a crawler resolves differ from the page that states it. */\nfunction isPathSegment(segment: string): boolean {\n return segment !== '' && segment !== '.' && segment !== '..';\n}\n\n/**\n * The decoded logical path a route pattern names under these params:\n * `('/[slug]/p', { slug: 'caf%C3%A9' })` -> `'/café/p'`. Catch-alls join with `/`; empty -> `'/'`.\n * Empty, `.` and `..` values are dropped.\n */\nexport function routeLogicalPath(route: string, params: RouteParams): string {\n const segments = route\n .split('/')\n .filter(Boolean)\n .flatMap((segment) => {\n const dynamic = /^\\[{1,2}(?:\\.\\.\\.)?([^\\]]+)\\]{1,2}$/.exec(segment);\n if (!dynamic) return [segment];\n return [params[dynamic[1] as string] ?? []].flat().map(decodeSegment);\n })\n .filter(isPathSegment);\n return `/${segments.join('/')}`;\n}\n\nfunction readVariants(data: unknown): RouteVariant[] {\n const variants = (data as { catalogRoute?: { variants?: unknown } | null } | null)?.catalogRoute?.variants;\n if (!Array.isArray(variants)) return [];\n return variants.filter(\n (variant): variant is RouteVariant => typeof variant?.locale === 'string' && typeof variant?.path === 'string',\n );\n}\n\n/** Binding id -> confirmed variant path, matching BCP 47 tags case-insensitively and nothing looser. */\nfunction variantPathsByBinding(\n bindings: readonly AlternateBinding[],\n variants: readonly RouteVariant[],\n): Record<string, string> {\n const paths: Record<string, string> = {};\n for (const binding of bindings) {\n const locale = binding.locale.toLowerCase();\n const variant = variants.find((candidate) => candidate.locale.toLowerCase() === locale);\n if (variant) paths[binding.bindingId] = variant.path;\n }\n return paths;\n}\n\n/**\n * Why a lookup degraded, safe to log: the GraphQL error code, else the allow-listed error name. `null`\n * for `BAD_USER_INPUT`, which a path `catalogRoute` cannot parse (a slug with a dot) always answers.\n */\nfunction degradedReason(error: unknown): string | null {\n if (!CombinedGraphQLErrors.is(error)) return loggableErrorName(error);\n const codes = error.errors.map(({ extensions }) => extensions?.code);\n if (codes.length > 0 && codes.every((candidate) => candidate === 'BAD_USER_INPUT')) return null;\n const code = codes.find(\n (candidate): candidate is string => typeof candidate === 'string' && candidate !== 'BAD_USER_INPUT',\n );\n return code ?? 'GRAPHQL_ERROR';\n}\n\nfunction warnDegraded(error: unknown): null {\n const reason = degradedReason(error);\n if (reason) console.warn('[seo.catalogClusterPaths] catalogRoute lookup degraded to no cluster', reason);\n return null;\n}\n\n/**\n * Binding id -> variant path for the bindings whose locale a confirmed variant matches. Never\n * rejects: a thrown loader, an `error`, a missing or `null` `catalogRoute`, or no matching variant\n * all resolve to `null`, so a catalog lookup can never fail the page it describes. A thrown loader\n * or an `error` is logged by code or error name only, never with the path or the upstream message.\n */\nexport async function catalogClusterPaths(\n bindings: readonly AlternateBinding[],\n load: () => Promise<{ data: unknown; error?: unknown }>,\n): Promise<Record<string, string> | null> {\n try {\n const { data, error } = await load();\n if (error) return warnDegraded(error);\n const paths = variantPathsByBinding(bindings, readVariants(data));\n return Object.keys(paths).length > 0 ? paths : null;\n } catch (error) {\n return warnDegraded(error);\n }\n}\n"],"mappings":";;;;;;;;AAkCA,MAAa,iCAAiC,QAAQ;;;;;;;;;CASrD;;AAGD,SAAS,WAAW,MAAsB;CACxC,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;AACzD;;;;;AAMA,SAAS,gBAAgB,UAAuC,kBAA8C;CAC5G,MAAM,2BAAW,IAAI,IAA8B;CACnD,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,MAAM,QAAQ,OAAO,YAAY;EAEvC,IAAI,CADY,SAAS,IAAI,GAClB,KAAK,QAAQ,cAAc,kBAAkB,SAAS,IAAI,KAAK,OAAO;CACnF;CACA,OAAO,SAAS,QAAQ,YAAY,SAAS,IAAI,QAAQ,OAAO,YAAY,CAAC,MAAM,OAAO;AAC5F;;;;;AAMA,SAAgB,oBAAoB,EAClC,WACA,kBACA,UACA,UACA,cACA,YAC6C;CAC7C,MAAM,OAAO,IAAY,SAAiB,SAAS,IAAI,WAAW,IAAI,CAAC;CACvE,MAAM,UAAU,OAAgB,gBAAgB,OAAO,OAAO,cAAc,EAAE,IAAI,aAAa,MAAM,KAAA;CACrG,MAAM,YAAY,IAAI,WAAW,OAAO,SAAS,KAAK,QAAQ;CAE9D,MAAM,UAAU,gBAAgB,UAAU,gBAAgB,CAAC,CAAC,SAAS,YAAY;EAC/E,MAAM,OAAO,OAAO,QAAQ,SAAS;EACrC,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC;GAAE,GAAG;GAAS,MAAM,IAAI,QAAQ,WAAW,IAAI;EAAE,CAAC;CACtF,CAAC;CACD,IAAI,QAAQ,SAAS,KAAK,CAAC,QAAQ,MAAM,WAAW,OAAO,cAAc,SAAS,GAAG,OAAO,EAAE,UAAU;CAExG,MAAM,YAAoC,CAAC;CAC3C,KAAK,MAAM,UAAU,SAAS,UAAU,OAAO,UAAU,OAAO;CAChE,MAAM,gBAAgB,QAAQ,MAAM,WAAW,OAAO,cAAc,gBAAgB;CACpF,IAAI,eAAe,UAAU,eAAe,cAAc;CAC1D,OAAO;EAAE;EAAW;CAAU;AAChC;AAEA,SAAS,cAAc,SAAyB;CAC9C,IAAI;EACF,OAAO,mBAAmB,OAAO;CACnC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAS,cAAc,SAA0B;CAC/C,OAAO,YAAY,MAAM,YAAY,OAAO,YAAY;AAC1D;;;;;;AAOA,SAAgB,iBAAiB,OAAe,QAA6B;CAU3E,OAAO,IATU,MACd,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,SAAS,YAAY;EACpB,MAAM,UAAU,sCAAsC,KAAK,OAAO;EAClE,IAAI,CAAC,SAAS,OAAO,CAAC,OAAO;EAC7B,OAAO,CAAC,OAAO,QAAQ,OAAiB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,aAAa;CACtE,CAAC,CAAC,CACD,OAAO,aACQ,CAAC,CAAC,KAAK,GAAG;AAC9B;AAEA,SAAS,aAAa,MAA+B;CACnD,MAAM,WAAY,MAAkE,cAAc;CAClG,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,CAAC;CACtC,OAAO,SAAS,QACb,YAAqC,OAAO,SAAS,WAAW,YAAY,OAAO,SAAS,SAAS,QACxG;AACF;;AAGA,SAAS,sBACP,UACA,UACwB;CACxB,MAAM,QAAgC,CAAC;CACvC,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,SAAS,QAAQ,OAAO,YAAY;EAC1C,MAAM,UAAU,SAAS,MAAM,cAAc,UAAU,OAAO,YAAY,MAAM,MAAM;EACtF,IAAI,SAAS,MAAM,QAAQ,aAAa,QAAQ;CAClD;CACA,OAAO;AACT;;;;;AAMA,SAAS,eAAe,OAA+B;CACrD,IAAI,CAAC,sBAAsB,GAAG,KAAK,GAAG,OAAO,kBAAkB,KAAK;CACpE,MAAM,QAAQ,MAAM,OAAO,KAAK,EAAE,iBAAiB,YAAY,IAAI;CACnE,IAAI,MAAM,SAAS,KAAK,MAAM,OAAO,cAAc,cAAc,gBAAgB,GAAG,OAAO;CAI3F,OAHa,MAAM,MAChB,cAAmC,OAAO,cAAc,YAAY,cAAc,gBAE3E,KAAK;AACjB;AAEA,SAAS,aAAa,OAAsB;CAC1C,MAAM,SAAS,eAAe,KAAK;CACnC,IAAI,QAAQ,QAAQ,KAAK,wEAAwE,MAAM;CACvG,OAAO;AACT;;;;;;;AAQA,eAAsB,oBACpB,UACA,MACwC;CACxC,IAAI;EACF,MAAM,EAAE,MAAM,UAAU,MAAM,KAAK;EACnC,IAAI,OAAO,OAAO,aAAa,KAAK;EACpC,MAAM,QAAQ,sBAAsB,UAAU,aAAa,IAAI,CAAC;EAChE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ;CACjD,SAAS,OAAO;EACd,OAAO,aAAa,KAAK;CAC3B;AACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CreateClientOptions } from "../client/create-client.js";
|
|
2
|
+
//#region src/sdk/session/read-server-session.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Classifies `Query.session` for a server caller.
|
|
5
|
+
*
|
|
6
|
+
* Always resolves. `signed-in` is `loggedIn === true`. An identified guest is `anonymous`. A
|
|
7
|
+
* throw, a GraphQL error, a missing `session`, or a timeout is `failed`, including a partial
|
|
8
|
+
* payload that says `loggedIn: true`. The result carries no session payload. No `Cookie` header
|
|
9
|
+
* is set here, so `createClient` keeps forwarding `cookies()`.
|
|
10
|
+
*/
|
|
11
|
+
export type ServerSessionRead = {
|
|
12
|
+
status: 'signed-in';
|
|
13
|
+
} | {
|
|
14
|
+
status: 'anonymous';
|
|
15
|
+
} | {
|
|
16
|
+
status: 'failed';
|
|
17
|
+
reason: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function readServerSession(options?: CreateClientOptions): Promise<ServerSessionRead>;
|
|
20
|
+
//#endregion
|
|
21
|
+
//# sourceMappingURL=read-server-session.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ServerSessionReadDocument } from "../generated/graphql.js";
|
|
2
|
+
import { createClient } from "../client/create-client.js";
|
|
3
|
+
import { CombinedGraphQLErrors } from "@apollo/client/errors";
|
|
4
|
+
//#region src/sdk/session/read-server-session.ts
|
|
5
|
+
/**
|
|
6
|
+
* Local bound for the session read. Not the content runtime's request timeout: that module must
|
|
7
|
+
* stay off the server barrel.
|
|
8
|
+
*/
|
|
9
|
+
const SERVER_SESSION_READ_TIMEOUT_MS = 5e3;
|
|
10
|
+
async function readServerSession(options) {
|
|
11
|
+
try {
|
|
12
|
+
const result = await createClient(options).query({
|
|
13
|
+
query: ServerSessionReadDocument,
|
|
14
|
+
errorPolicy: "all",
|
|
15
|
+
fetchPolicy: "no-cache",
|
|
16
|
+
context: { fetchOptions: { signal: AbortSignal.timeout(SERVER_SESSION_READ_TIMEOUT_MS) } }
|
|
17
|
+
});
|
|
18
|
+
if (isTimeoutError(result.error)) return {
|
|
19
|
+
status: "failed",
|
|
20
|
+
reason: "timeout"
|
|
21
|
+
};
|
|
22
|
+
if (result.error || result.data?.session == null) return {
|
|
23
|
+
status: "failed",
|
|
24
|
+
reason: graphqlFailureReason(result.error)
|
|
25
|
+
};
|
|
26
|
+
if (result.data.session.loggedIn === true) return { status: "signed-in" };
|
|
27
|
+
return { status: "anonymous" };
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (isTimeoutError(error)) return {
|
|
30
|
+
status: "failed",
|
|
31
|
+
reason: "timeout"
|
|
32
|
+
};
|
|
33
|
+
if (error instanceof Error && error.message.length > 0) return {
|
|
34
|
+
status: "failed",
|
|
35
|
+
reason: error.message
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
status: "failed",
|
|
39
|
+
reason: "network error"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function graphqlFailureReason(error) {
|
|
44
|
+
if (CombinedGraphQLErrors.is(error)) {
|
|
45
|
+
const message = error.errors[0]?.message;
|
|
46
|
+
if (typeof message === "string" && message.length > 0) return message;
|
|
47
|
+
}
|
|
48
|
+
return "graphql error";
|
|
49
|
+
}
|
|
50
|
+
function isTimeoutError(error) {
|
|
51
|
+
if (hasAbortName(error)) return true;
|
|
52
|
+
if (typeof error === "object" && error !== null && "cause" in error) return hasAbortName(error.cause);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function hasAbortName(error) {
|
|
56
|
+
return typeof error === "object" && error !== null && "name" in error && (error.name === "TimeoutError" || error.name === "AbortError");
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { readServerSession };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=read-server-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-server-session.js","names":[],"sources":["../../../src/sdk/session/read-server-session.ts"],"sourcesContent":["import { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport type { CreateClientOptions } from '../client/create-client.js';\nimport { createClient } from '../client/create-client.js';\nimport { ServerSessionReadDocument } from '../generated/graphql.js';\n\n/**\n * Local bound for the session read. Not the content runtime's request timeout: that module must\n * stay off the server barrel.\n */\nconst SERVER_SESSION_READ_TIMEOUT_MS = 5_000;\n\n/**\n * Classifies `Query.session` for a server caller.\n *\n * Always resolves. `signed-in` is `loggedIn === true`. An identified guest is `anonymous`. A\n * throw, a GraphQL error, a missing `session`, or a timeout is `failed`, including a partial\n * payload that says `loggedIn: true`. The result carries no session payload. No `Cookie` header\n * is set here, so `createClient` keeps forwarding `cookies()`.\n */\nexport type ServerSessionRead =\n | { status: 'signed-in' }\n | { status: 'anonymous' }\n | { status: 'failed'; reason: string };\n\nexport async function readServerSession(options?: CreateClientOptions): Promise<ServerSessionRead> {\n try {\n const client = createClient(options);\n const result = await client.query({\n query: ServerSessionReadDocument,\n errorPolicy: 'all',\n fetchPolicy: 'no-cache',\n context: { fetchOptions: { signal: AbortSignal.timeout(SERVER_SESSION_READ_TIMEOUT_MS) } },\n });\n\n // A timeout lands on `result.error` under `errorPolicy: 'all'` rather than rejecting.\n if (isTimeoutError(result.error)) {\n return { status: 'failed', reason: 'timeout' };\n }\n\n if (result.error || result.data?.session == null) {\n return { status: 'failed', reason: graphqlFailureReason(result.error) };\n }\n\n if (result.data.session.loggedIn === true) {\n return { status: 'signed-in' };\n }\n\n return { status: 'anonymous' };\n } catch (error) {\n if (isTimeoutError(error)) {\n return { status: 'failed', reason: 'timeout' };\n }\n if (error instanceof Error && error.message.length > 0) {\n return { status: 'failed', reason: error.message };\n }\n return { status: 'failed', reason: 'network error' };\n }\n}\n\nfunction graphqlFailureReason(error: unknown): string {\n if (CombinedGraphQLErrors.is(error)) {\n const message = error.errors[0]?.message;\n if (typeof message === 'string' && message.length > 0) return message;\n }\n return 'graphql error';\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (hasAbortName(error)) return true;\n if (typeof error === 'object' && error !== null && 'cause' in error) {\n return hasAbortName(error.cause);\n }\n return false;\n}\n\nfunction hasAbortName(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'name' in error &&\n (error.name === 'TimeoutError' || error.name === 'AbortError')\n );\n}\n"],"mappings":";;;;;;;;AASA,MAAM,iCAAiC;AAevC,eAAsB,kBAAkB,SAA2D;CACjG,IAAI;EAEF,MAAM,SAAS,MADA,aAAa,OACF,CAAC,CAAC,MAAM;GAChC,OAAO;GACP,aAAa;GACb,aAAa;GACb,SAAS,EAAE,cAAc,EAAE,QAAQ,YAAY,QAAQ,8BAA8B,EAAE,EAAE;EAC3F,CAAC;EAGD,IAAI,eAAe,OAAO,KAAK,GAC7B,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAU;EAG/C,IAAI,OAAO,SAAS,OAAO,MAAM,WAAW,MAC1C,OAAO;GAAE,QAAQ;GAAU,QAAQ,qBAAqB,OAAO,KAAK;EAAE;EAGxE,IAAI,OAAO,KAAK,QAAQ,aAAa,MACnC,OAAO,EAAE,QAAQ,YAAY;EAG/B,OAAO,EAAE,QAAQ,YAAY;CAC/B,SAAS,OAAO;EACd,IAAI,eAAe,KAAK,GACtB,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAU;EAE/C,IAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,GACnD,OAAO;GAAE,QAAQ;GAAU,QAAQ,MAAM;EAAQ;EAEnD,OAAO;GAAE,QAAQ;GAAU,QAAQ;EAAgB;CACrD;AACF;AAEA,SAAS,qBAAqB,OAAwB;CACpD,IAAI,sBAAsB,GAAG,KAAK,GAAG;EACnC,MAAM,UAAU,MAAM,OAAO,EAAE,EAAE;EACjC,IAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG,OAAO;CAChE;CACA,OAAO;AACT;AAEA,SAAS,eAAe,OAAyB;CAC/C,IAAI,aAAa,KAAK,GAAG,OAAO;CAChC,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,OAC5D,OAAO,aAAa,MAAM,KAAK;CAEjC,OAAO;AACT;AAEA,SAAS,aAAa,OAAyB;CAC7C,OACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,UACT,MAAM,SAAS,kBAAkB,MAAM,SAAS;AAErD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { defineActions } from "../../core/dist/actions/registry.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
+
import { loggableErrorName } from "../../utils/loggable-error-name.js";
|
|
4
5
|
import { SESSION_LOGIN_WITH_PASSWORD, SESSION_LOGOUT, SESSION_REQUEST_ACCESS_CODE, SESSION_VALIDATE_ACCESS_CODE } from "./auth-operations.js";
|
|
5
6
|
import { useMutation } from "@apollo/client/react";
|
|
6
7
|
import { useCallback, useMemo } from "react";
|
|
@@ -24,7 +25,7 @@ function useSessionActions() {
|
|
|
24
25
|
try {
|
|
25
26
|
return (await loginMutation({ variables: { input: payload } })).data?.sessionLoginWithPassword.userErrors ?? [];
|
|
26
27
|
} catch (error) {
|
|
27
|
-
console.error("[session.loginWithPassword] sessionLoginWithPassword failed", error);
|
|
28
|
+
console.error("[session.loginWithPassword] sessionLoginWithPassword failed", loggableErrorName(error));
|
|
28
29
|
return [NETWORK_USER_ERROR];
|
|
29
30
|
}
|
|
30
31
|
}, [loginMutation]);
|
|
@@ -36,7 +37,7 @@ function useSessionActions() {
|
|
|
36
37
|
userErrors: data?.userErrors ?? []
|
|
37
38
|
};
|
|
38
39
|
} catch (error) {
|
|
39
|
-
console.error("[session.requestAccessCode] sessionRequestAccessCode failed", error);
|
|
40
|
+
console.error("[session.requestAccessCode] sessionRequestAccessCode failed", loggableErrorName(error));
|
|
40
41
|
return {
|
|
41
42
|
authenticationToken: null,
|
|
42
43
|
userErrors: [NETWORK_USER_ERROR]
|
|
@@ -47,7 +48,7 @@ function useSessionActions() {
|
|
|
47
48
|
try {
|
|
48
49
|
return (await validateMutation({ variables: { input: payload } })).data?.sessionValidateAccessCode.userErrors ?? [];
|
|
49
50
|
} catch (error) {
|
|
50
|
-
console.error("[session.validateAccessCode] sessionValidateAccessCode failed", error);
|
|
51
|
+
console.error("[session.validateAccessCode] sessionValidateAccessCode failed", loggableErrorName(error));
|
|
51
52
|
return [NETWORK_USER_ERROR];
|
|
52
53
|
}
|
|
53
54
|
}, [validateMutation]);
|
|
@@ -55,7 +56,7 @@ function useSessionActions() {
|
|
|
55
56
|
try {
|
|
56
57
|
return (await logoutMutation()).data?.sessionLogout.userErrors ?? [];
|
|
57
58
|
} catch (error) {
|
|
58
|
-
console.error("[session.logout] sessionLogout failed", error);
|
|
59
|
+
console.error("[session.logout] sessionLogout failed", loggableErrorName(error));
|
|
59
60
|
return [NETWORK_USER_ERROR];
|
|
60
61
|
}
|
|
61
62
|
}, [logoutMutation]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-session-actions.js","names":[],"sources":["../../../src/sdk/session/use-session-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport {\n SESSION_LOGIN_WITH_PASSWORD,\n SESSION_LOGOUT,\n SESSION_REQUEST_ACCESS_CODE,\n SESSION_VALIDATE_ACCESS_CODE,\n type SessionAccessCodeRequestResult,\n type SessionPasswordLoginPayload,\n type SessionRequestAccessCodePayload,\n type SessionUserError,\n type SessionValidateAccessCodePayload,\n} from './auth-operations.js';\n\n/**\n * The `session` action namespace — the one sanctioned client write surface for authentication\n * (docs/storefront-core/reference-free-particle-model.md § Write side — actions, docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Every action is async/pessimistic (Decision 1): the handler awaits the mutation and only the\n * server-confirmed payload changes the cache — authentication cannot be guessed client-side. The\n * handlers are stateless: no reactive vars, no module state; the access-code `authenticationToken`\n * is returned to the caller, which owns it as UI flow state (Decision 4). Each action resolves its\n * payload `userErrors` (empty on success) and never throws for expected outcomes; infrastructure\n * failures resolve as the synthetic `NETWORK_ERROR` (Decision 5). The credentials pass through\n * mutation variables only — never logged, never stored.\n */\nexport type SessionActions = Readonly<{\n /** Password sign-in. Async/pessimistic; resolves the payload userErrors (empty on success). */\n loginWithPassword: (payload: SessionPasswordLoginPayload) => Promise<readonly SessionUserError[]>;\n /** Email an access code; resolves the opaque authenticationToken to round-trip into validate. */\n requestAccessCode: (payload: SessionRequestAccessCodePayload) => Promise<SessionAccessCodeRequestResult>;\n /** Validate an access code + token; logs the shopper in exactly as a password login would. */\n validateAccessCode: (payload: SessionValidateAccessCodePayload) => Promise<readonly SessionUserError[]>;\n /** Sign out. Idempotent for guests. */\n logout: () => Promise<readonly SessionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: SessionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to complete the request. Please try again.',\n};\n\n/**\n * The `session` namespace hook. Registered with the first-party action registry via `sessionActions`\n * below; the compiler-emitted `SessionActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.session`. Login/validate/logout refresh the session purely through the\n * normalized-cache merge of the mutation response (Decision 2) — no refetch, no imperative write.\n */\nexport function useSessionActions(): SessionActions {\n const [loginMutation] = useMutation(SESSION_LOGIN_WITH_PASSWORD);\n const [requestMutation] = useMutation(SESSION_REQUEST_ACCESS_CODE);\n const [validateMutation] = useMutation(SESSION_VALIDATE_ACCESS_CODE);\n const [logoutMutation] = useMutation(SESSION_LOGOUT);\n\n const loginWithPassword = useCallback<SessionActions['loginWithPassword']>(\n async (payload) => {\n try {\n const result = await loginMutation({ variables: { input: payload } });\n return result.data?.sessionLoginWithPassword.userErrors ?? [];\n } catch (error) {\n console.error('[session.loginWithPassword] sessionLoginWithPassword failed', error);\n return [NETWORK_USER_ERROR];\n }\n },\n [loginMutation],\n );\n\n const requestAccessCode = useCallback<SessionActions['requestAccessCode']>(\n async (payload) => {\n try {\n const result = await requestMutation({ variables: { input: payload } });\n const data = result.data?.sessionRequestAccessCode;\n return { authenticationToken: data?.authenticationToken ?? null, userErrors: data?.userErrors ?? [] };\n } catch (error) {\n console.error('[session.requestAccessCode] sessionRequestAccessCode failed', error);\n return { authenticationToken: null, userErrors: [NETWORK_USER_ERROR] };\n }\n },\n [requestMutation],\n );\n\n const validateAccessCode = useCallback<SessionActions['validateAccessCode']>(\n async (payload) => {\n try {\n const result = await validateMutation({ variables: { input: payload } });\n return result.data?.sessionValidateAccessCode.userErrors ?? [];\n } catch (error) {\n console.error('[session.validateAccessCode] sessionValidateAccessCode failed', error);\n return [NETWORK_USER_ERROR];\n }\n },\n [validateMutation],\n );\n\n const logout = useCallback<SessionActions['logout']>(async () => {\n try {\n const result = await logoutMutation();\n return result.data?.sessionLogout.userErrors ?? [];\n } catch (error) {\n console.error('[session.logout] sessionLogout failed', error);\n return [NETWORK_USER_ERROR];\n }\n }, [logoutMutation]);\n\n return useMemo(\n () => ({ loginWithPassword, requestAccessCode, validateAccessCode, logout }),\n [loginWithPassword, requestAccessCode, validateAccessCode, logout],\n );\n}\n\n/**\n * Declares the `session` 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 * `SessionActionProvider` calls `useSessionActions` directly.\n */\nexport const sessionActions = defineActions({\n namespace: 'session',\n description: 'Mutation-backed authentication writes against the VTEX ID session (login, access code, logout).',\n provider: { name: 'SessionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n loginWithPassword: {\n description: 'Sign in with email and password (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'password', type: 'string' },\n ],\n },\n requestAccessCode: {\n description: 'Email the shopper an access code; resolves the opaque authenticationToken to round-trip.',\n payload: [{ name: 'email', type: 'string' }],\n },\n validateAccessCode: {\n description: 'Validate an access code with its authenticationToken (async/pessimistic); logs the shopper in.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'accessCode', type: 'string' },\n { name: 'authenticationToken', type: 'string' },\n ],\n },\n logout: {\n description: 'Sign out, clearing the auth cookies (async/pessimistic). Idempotent for guests.',\n payload: [],\n },\n },\n use: useSessionActions,\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-session-actions.js","names":[],"sources":["../../../src/sdk/session/use-session-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport {\n SESSION_LOGIN_WITH_PASSWORD,\n SESSION_LOGOUT,\n SESSION_REQUEST_ACCESS_CODE,\n SESSION_VALIDATE_ACCESS_CODE,\n type SessionAccessCodeRequestResult,\n type SessionPasswordLoginPayload,\n type SessionRequestAccessCodePayload,\n type SessionUserError,\n type SessionValidateAccessCodePayload,\n} from './auth-operations.js';\n\n/**\n * The `session` action namespace — the one sanctioned client write surface for authentication\n * (docs/storefront-core/reference-free-particle-model.md § Write side — actions, docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * Every action is async/pessimistic (Decision 1): the handler awaits the mutation and only the\n * server-confirmed payload changes the cache — authentication cannot be guessed client-side. The\n * handlers are stateless: no reactive vars, no module state; the access-code `authenticationToken`\n * is returned to the caller, which owns it as UI flow state (Decision 4). Each action resolves its\n * payload `userErrors` (empty on success) and never throws for expected outcomes; infrastructure\n * failures resolve as the synthetic `NETWORK_ERROR` (Decision 5). The credentials pass through\n * mutation variables only — never logged, never stored.\n */\nexport type SessionActions = Readonly<{\n /** Password sign-in. Async/pessimistic; resolves the payload userErrors (empty on success). */\n loginWithPassword: (payload: SessionPasswordLoginPayload) => Promise<readonly SessionUserError[]>;\n /** Email an access code; resolves the opaque authenticationToken to round-trip into validate. */\n requestAccessCode: (payload: SessionRequestAccessCodePayload) => Promise<SessionAccessCodeRequestResult>;\n /** Validate an access code + token; logs the shopper in exactly as a password login would. */\n validateAccessCode: (payload: SessionValidateAccessCodePayload) => Promise<readonly SessionUserError[]>;\n /** Sign out. Idempotent for guests. */\n logout: () => Promise<readonly SessionUserError[]>;\n}>;\n\nconst NETWORK_USER_ERROR: SessionUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to complete the request. Please try again.',\n};\n\n/**\n * The `session` namespace hook. Registered with the first-party action registry via `sessionActions`\n * below; the compiler-emitted `SessionActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.session`. Login/validate/logout refresh the session purely through the\n * normalized-cache merge of the mutation response (Decision 2) — no refetch, no imperative write.\n */\nexport function useSessionActions(): SessionActions {\n const [loginMutation] = useMutation(SESSION_LOGIN_WITH_PASSWORD);\n const [requestMutation] = useMutation(SESSION_REQUEST_ACCESS_CODE);\n const [validateMutation] = useMutation(SESSION_VALIDATE_ACCESS_CODE);\n const [logoutMutation] = useMutation(SESSION_LOGOUT);\n\n const loginWithPassword = useCallback<SessionActions['loginWithPassword']>(\n async (payload) => {\n try {\n const result = await loginMutation({ variables: { input: payload } });\n return result.data?.sessionLoginWithPassword.userErrors ?? [];\n } catch (error) {\n console.error('[session.loginWithPassword] sessionLoginWithPassword failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n },\n [loginMutation],\n );\n\n const requestAccessCode = useCallback<SessionActions['requestAccessCode']>(\n async (payload) => {\n try {\n const result = await requestMutation({ variables: { input: payload } });\n const data = result.data?.sessionRequestAccessCode;\n return { authenticationToken: data?.authenticationToken ?? null, userErrors: data?.userErrors ?? [] };\n } catch (error) {\n console.error('[session.requestAccessCode] sessionRequestAccessCode failed', loggableErrorName(error));\n return { authenticationToken: null, userErrors: [NETWORK_USER_ERROR] };\n }\n },\n [requestMutation],\n );\n\n const validateAccessCode = useCallback<SessionActions['validateAccessCode']>(\n async (payload) => {\n try {\n const result = await validateMutation({ variables: { input: payload } });\n return result.data?.sessionValidateAccessCode.userErrors ?? [];\n } catch (error) {\n console.error('[session.validateAccessCode] sessionValidateAccessCode failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n },\n [validateMutation],\n );\n\n const logout = useCallback<SessionActions['logout']>(async () => {\n try {\n const result = await logoutMutation();\n return result.data?.sessionLogout.userErrors ?? [];\n } catch (error) {\n console.error('[session.logout] sessionLogout failed', loggableErrorName(error));\n return [NETWORK_USER_ERROR];\n }\n }, [logoutMutation]);\n\n return useMemo(\n () => ({ loginWithPassword, requestAccessCode, validateAccessCode, logout }),\n [loginWithPassword, requestAccessCode, validateAccessCode, logout],\n );\n}\n\n/**\n * Declares the `session` 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 * `SessionActionProvider` calls `useSessionActions` directly.\n */\nexport const sessionActions = defineActions({\n namespace: 'session',\n description: 'Mutation-backed authentication writes against the VTEX ID session (login, access code, logout).',\n provider: { name: 'SessionActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n loginWithPassword: {\n description: 'Sign in with email and password (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'password', type: 'string' },\n ],\n },\n requestAccessCode: {\n description: 'Email the shopper an access code; resolves the opaque authenticationToken to round-trip.',\n payload: [{ name: 'email', type: 'string' }],\n },\n validateAccessCode: {\n description: 'Validate an access code with its authenticationToken (async/pessimistic); logs the shopper in.',\n payload: [\n { name: 'email', type: 'string' },\n { name: 'accessCode', type: 'string' },\n { name: 'authenticationToken', type: 'string' },\n ],\n },\n logout: {\n description: 'Sign out, clearing the auth cookies (async/pessimistic). Idempotent for guests.',\n payload: [],\n },\n },\n use: useSessionActions,\n});\n"],"mappings":";;;;;;;;AAyCA,MAAM,qBAAuC;CAC3C,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,oBAAoC;CAClD,MAAM,CAAC,iBAAiB,YAAY,2BAA2B;CAC/D,MAAM,CAAC,mBAAmB,YAAY,2BAA2B;CACjE,MAAM,CAAC,oBAAoB,YAAY,4BAA4B;CACnE,MAAM,CAAC,kBAAkB,YAAY,cAAc;CAEnD,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,cAAc,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACtD,MAAM,yBAAyB,cAAc,CAAC;EAC9D,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,kBAAkB,KAAK,CAAC;GACrG,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,aAAa,CAChB;CAEA,MAAM,oBAAoB,YACxB,OAAO,YAAY;EACjB,IAAI;GAEF,MAAM,QAAO,MADQ,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CAClD,MAAM;GAC1B,OAAO;IAAE,qBAAqB,MAAM,uBAAuB;IAAM,YAAY,MAAM,cAAc,CAAC;GAAE;EACtG,SAAS,OAAO;GACd,QAAQ,MAAM,+DAA+D,kBAAkB,KAAK,CAAC;GACrG,OAAO;IAAE,qBAAqB;IAAM,YAAY,CAAC,kBAAkB;GAAE;EACvE;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,qBAAqB,YACzB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,iBAAiB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACzD,MAAM,0BAA0B,cAAc,CAAC;EAC/D,SAAS,OAAO;GACd,QAAQ,MAAM,iEAAiE,kBAAkB,KAAK,CAAC;GACvG,OAAO,CAAC,kBAAkB;EAC5B;CACF,GACA,CAAC,gBAAgB,CACnB;CAEA,MAAM,SAAS,YAAsC,YAAY;EAC/D,IAAI;GAEF,QAAO,MADc,eAAe,EAAA,CACtB,MAAM,cAAc,cAAc,CAAC;EACnD,SAAS,OAAO;GACd,QAAQ,MAAM,yCAAyC,kBAAkB,KAAK,CAAC;GAC/E,OAAO,CAAC,kBAAkB;EAC5B;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,OAAO,eACE;EAAE;EAAmB;EAAmB;EAAoB;CAAO,IAC1E;EAAC;EAAmB;EAAmB;EAAoB;CAAM,CACnE;AACF;AAQ8B,cAAc;CAC1C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAyB,YAAY;CAAkC;CACzF,SAAS;EACP,mBAAmB;GACjB,aAAa;GACb,SAAS,CACP;IAAE,MAAM;IAAS,MAAM;GAAS,GAChC;IAAE,MAAM;IAAY,MAAM;GAAS,CACrC;EACF;EACA,mBAAmB;GACjB,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAS,MAAM;GAAS,CAAC;EAC7C;EACA,oBAAoB;GAClB,aAAa;GACb,SAAS;IACP;KAAE,MAAM;KAAS,MAAM;IAAS;IAChC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAuB,MAAM;IAAS;GAChD;EACF;EACA,QAAQ;GACN,aAAa;GACb,SAAS,CAAC;EACZ;CACF;CACA,KAAK;AACP,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { graphql } from "../generated/gql.js";
|
|
3
|
+
import { loggableErrorName } from "../../utils/loggable-error-name.js";
|
|
3
4
|
import { getApolloContext } from "@apollo/client/react";
|
|
4
5
|
import { useCallback, useContext } from "react";
|
|
5
6
|
//#region src/sdk/session/use-session-revalidation.ts
|
|
@@ -54,7 +55,7 @@ function useSessionRevalidation() {
|
|
|
54
55
|
});
|
|
55
56
|
return "revalidated";
|
|
56
57
|
} catch (error) {
|
|
57
|
-
console.error("[useSessionRevalidation] session re-read failed", error);
|
|
58
|
+
console.error("[useSessionRevalidation] session re-read failed", loggableErrorName(error));
|
|
58
59
|
return "failed";
|
|
59
60
|
}
|
|
60
61
|
}, [client]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-session-revalidation.js","names":[],"sources":["../../../src/sdk/session/use-session-revalidation.ts"],"sourcesContent":["'use client';\n\nimport { getApolloContext } from '@apollo/client/react';\nimport { useCallback, useContext } from 'react';\nimport { graphql } from '../generated/gql.js';\n\n/**\n * The imperative re-read of the session, for the one case the reactive path cannot serve: a document\n * the browser restored from its back-forward cache. A restored document resumes its heap without\n * remounting, so `PageReactiveDataRoot` never re-runs its `cache-first` query and\n * `useReactiveEntity` never issues a request — the session comes back exactly as stale as the frame\n * around it.\n *\n * Selects the same field set as `SessionFragment`, so the response writes over the entity the layout\n * query already references and every `SessionRoot` below it reacts.\n */\nexport const ACCOUNT_SESSION_REVALIDATE = graphql(`\n query AccountSessionRevalidate {\n session {\n ...SessionFragment\n }\n }\n`);\n\n/**\n * What a revalidation is able to say about the session afterwards.\n *\n * `unavailable` is not a failure. With no Apollo client there is no cache to hold a stale session and\n * nothing to re-read: the session in the tree came from a `$data` prop, and a prop cannot go stale\n * behind the caller's back. A caller that treats it as a failure is distrusting an answer that was\n * never checkable — which is every story and test composed without a provider.\n */\nexport type SessionRevalidation = 'revalidated' | 'failed' | 'unavailable';\n\n/**\n * Discards the cached session and re-reads it from the network, resolving what it was able to find\n * out. Only `failed` means the caller is holding an answer it has reason to distrust: the session was\n * discarded and the query that should have replaced it rejected.\n *\n * **The discard comes first, and that ordering is the contract.** For the whole of the re-read there\n * must be no session in the cache for anything to read: a re-read that merely overwrote would leave\n * the restored `loggedIn` answering every consumer in the tree until the network replied. What has to\n * go is the normalized entity, not the root field that points at it — the reactive read subscribes to\n * `Session:<id>` through `useFragment`, so a root field cleared from under a live entity leaves that\n * read complete and the consumer resolved.\n *\n * The consumers follow asynchronously, once the watched query has re-read: a component that must\n * withhold something in the same frame the discard happens has to hold that state itself, and\n * `AccountAccessGate` does.\n *\n * The client is resolved through Apollo's context rather than `useApolloClient()`, which throws when\n * there is none: every session-aware story and test in this package renders `SessionRoot` bare, and a\n * revalidation that cannot run is not a reason for a component to fail to render.\n */\nexport function useSessionRevalidation(): () => Promise<SessionRevalidation> {\n const { client } = useContext(getApolloContext());\n\n return useCallback(async (): Promise<SessionRevalidation> => {\n if (!client) {\n return 'unavailable';\n }\n\n try {\n // The document about to be re-read is also what names the entity to discard: it selects the\n // same field, so it resolves whichever Session the cache is currently holding. An incomplete\n // read means there is nothing cached to discard, and the re-read below is all that is needed.\n const cached = client.cache.readQuery({ query: ACCOUNT_SESSION_REVALIDATE });\n const entity = cached?.session ? client.cache.identify(cached.session) : undefined;\n if (entity) {\n client.cache.evict({ id: entity });\n }\n\n await client.query({ query: ACCOUNT_SESSION_REVALIDATE, fetchPolicy: 'network-only' });\n return 'revalidated';\n } catch (error) {\n // The discard is inside this guard along with the re-read, so a cache that refused either one\n // resolves rather than rejecting. A caller left awaiting a promise that never settles would\n // hold its shopper in the wait forever, which is the one outcome worse than saying no.\n console.error('[useSessionRevalidation] session re-read failed', error);\n return 'failed';\n }\n }, [client]);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-session-revalidation.js","names":[],"sources":["../../../src/sdk/session/use-session-revalidation.ts"],"sourcesContent":["'use client';\n\nimport { getApolloContext } from '@apollo/client/react';\nimport { useCallback, useContext } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { graphql } from '../generated/gql.js';\n\n/**\n * The imperative re-read of the session, for the one case the reactive path cannot serve: a document\n * the browser restored from its back-forward cache. A restored document resumes its heap without\n * remounting, so `PageReactiveDataRoot` never re-runs its `cache-first` query and\n * `useReactiveEntity` never issues a request — the session comes back exactly as stale as the frame\n * around it.\n *\n * Selects the same field set as `SessionFragment`, so the response writes over the entity the layout\n * query already references and every `SessionRoot` below it reacts.\n */\nexport const ACCOUNT_SESSION_REVALIDATE = graphql(`\n query AccountSessionRevalidate {\n session {\n ...SessionFragment\n }\n }\n`);\n\n/**\n * What a revalidation is able to say about the session afterwards.\n *\n * `unavailable` is not a failure. With no Apollo client there is no cache to hold a stale session and\n * nothing to re-read: the session in the tree came from a `$data` prop, and a prop cannot go stale\n * behind the caller's back. A caller that treats it as a failure is distrusting an answer that was\n * never checkable — which is every story and test composed without a provider.\n */\nexport type SessionRevalidation = 'revalidated' | 'failed' | 'unavailable';\n\n/**\n * Discards the cached session and re-reads it from the network, resolving what it was able to find\n * out. Only `failed` means the caller is holding an answer it has reason to distrust: the session was\n * discarded and the query that should have replaced it rejected.\n *\n * **The discard comes first, and that ordering is the contract.** For the whole of the re-read there\n * must be no session in the cache for anything to read: a re-read that merely overwrote would leave\n * the restored `loggedIn` answering every consumer in the tree until the network replied. What has to\n * go is the normalized entity, not the root field that points at it — the reactive read subscribes to\n * `Session:<id>` through `useFragment`, so a root field cleared from under a live entity leaves that\n * read complete and the consumer resolved.\n *\n * The consumers follow asynchronously, once the watched query has re-read: a component that must\n * withhold something in the same frame the discard happens has to hold that state itself, and\n * `AccountAccessGate` does.\n *\n * The client is resolved through Apollo's context rather than `useApolloClient()`, which throws when\n * there is none: every session-aware story and test in this package renders `SessionRoot` bare, and a\n * revalidation that cannot run is not a reason for a component to fail to render.\n */\nexport function useSessionRevalidation(): () => Promise<SessionRevalidation> {\n const { client } = useContext(getApolloContext());\n\n return useCallback(async (): Promise<SessionRevalidation> => {\n if (!client) {\n return 'unavailable';\n }\n\n try {\n // The document about to be re-read is also what names the entity to discard: it selects the\n // same field, so it resolves whichever Session the cache is currently holding. An incomplete\n // read means there is nothing cached to discard, and the re-read below is all that is needed.\n const cached = client.cache.readQuery({ query: ACCOUNT_SESSION_REVALIDATE });\n const entity = cached?.session ? client.cache.identify(cached.session) : undefined;\n if (entity) {\n client.cache.evict({ id: entity });\n }\n\n await client.query({ query: ACCOUNT_SESSION_REVALIDATE, fetchPolicy: 'network-only' });\n return 'revalidated';\n } catch (error) {\n // The discard is inside this guard along with the re-read, so a cache that refused either one\n // resolves rather than rejecting. A caller left awaiting a promise that never settles would\n // hold its shopper in the wait forever, which is the one outcome worse than saying no.\n console.error('[useSessionRevalidation] session re-read failed', loggableErrorName(error));\n return 'failed';\n }\n }, [client]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAa,6BAA6B,QAAQ;;;;;;CAMjD;;;;;;;;;;;;;;;;;;;;;AAgCD,SAAgB,yBAA6D;CAC3E,MAAM,EAAE,WAAW,WAAW,iBAAiB,CAAC;CAEhD,OAAO,YAAY,YAA0C;EAC3D,IAAI,CAAC,QACH,OAAO;EAGT,IAAI;GAIF,MAAM,SAAS,OAAO,MAAM,UAAU,EAAE,OAAO,2BAA2B,CAAC;GAC3E,MAAM,SAAS,QAAQ,UAAU,OAAO,MAAM,SAAS,OAAO,OAAO,IAAI,KAAA;GACzE,IAAI,QACF,OAAO,MAAM,MAAM,EAAE,IAAI,OAAO,CAAC;GAGnC,MAAM,OAAO,MAAM;IAAE,OAAO;IAA4B,aAAa;GAAe,CAAC;GACrF,OAAO;EACT,SAAS,OAAO;GAId,QAAQ,MAAM,mDAAmD,kBAAkB,KAAK,CAAC;GACzF,OAAO;EACT;CACF,GAAG,CAAC,MAAM,CAAC;AACb"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { defineActions } from "../../core/dist/actions/registry.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
+
import { loggableErrorName } from "../../utils/loggable-error-name.js";
|
|
4
5
|
import { SHIPPING_OPTION_SELECT } from "./option-select-operations.js";
|
|
5
6
|
import { SHIPPING_ADDRESS_UPDATE, SHIPPING_NETWORK_ERROR_CODE } from "./shipping-operations.js";
|
|
6
7
|
import { useMutation } from "@apollo/client/react";
|
|
@@ -27,7 +28,7 @@ function useShippingActions() {
|
|
|
27
28
|
try {
|
|
28
29
|
return (await addressMutation({ variables: { input: address } })).data?.shippingAddressUpdate.userErrors ?? [];
|
|
29
30
|
} catch (error) {
|
|
30
|
-
console.error("[shipping.setAddress] shippingAddressUpdate failed", error);
|
|
31
|
+
console.error("[shipping.setAddress] shippingAddressUpdate failed", loggableErrorName(error));
|
|
31
32
|
return [SET_ADDRESS_NETWORK_ERROR];
|
|
32
33
|
}
|
|
33
34
|
}, [addressMutation]);
|
|
@@ -35,7 +36,7 @@ function useShippingActions() {
|
|
|
35
36
|
try {
|
|
36
37
|
return (await selectOptionMutation({ variables: { input: { optionId } } })).data?.shippingOptionSelect.userErrors ?? [];
|
|
37
38
|
} catch (error) {
|
|
38
|
-
console.error("[shipping.selectOption] shippingOptionSelect failed", error);
|
|
39
|
+
console.error("[shipping.selectOption] shippingOptionSelect failed", loggableErrorName(error));
|
|
39
40
|
return [SELECT_OPTION_NETWORK_ERROR];
|
|
40
41
|
}
|
|
41
42
|
}, [selectOptionMutation]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-shipping-actions.js","names":[],"sources":["../../../src/sdk/shipping/use-shipping-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { SHIPPING_OPTION_SELECT, type ShippingOptionSelectUserError } from './option-select-operations.js';\nimport {\n SHIPPING_ADDRESS_UPDATE,\n SHIPPING_NETWORK_ERROR_CODE,\n type ShippingAddressInput,\n type ShippingAddressUpdateErrorEntity,\n} from './shipping-operations.js';\n\n/**\n * The `shipping` action namespace — the sanctioned client write surface against the VTEX orderForm\n * shippingData: delivery-address updates (docs/storefront-core/reference-free-particle-model.md § The cart write contract;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md) and cart-scoped delivery-option\n * selection (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Per Decision 4 the two tasks share this one\n * namespace — T2 (`setAddress`) merged first and owns the registration, T3 extends it with\n * `selectOption` here.\n *\n * Both actions are async/pessimistic (Decision 1 of the address spec): the handler awaits the\n * mutation and only the server-confirmed payload changes the cache. Each is stateless (no reactive\n * vars, no module state), resolves its payload `userErrors` (empty on success), and never throws for\n * expected outcomes; an infrastructure failure (network or an upstream GraphQLError) is caught and\n * collapsed to one synthetic network `userError` — no per-code branching (US-4, FR-5). Inputs pass\n * through mutation variables only — never logged, never stored beyond the cache.\n */\nexport type ShippingActions = Readonly<{\n /** Persist the single delivery address (async/pessimistic). Resolves the payload userErrors. */\n setAddress: (address: ShippingAddressInput) => Promise<readonly ShippingAddressUpdateErrorEntity[]>;\n /** Select a delivery option for the whole cart. Resolves the payload userErrors (empty on success). */\n selectOption: (optionId: string) => Promise<readonly ShippingOptionSelectUserError[]>;\n}>;\n\nconst SET_ADDRESS_NETWORK_ERROR: ShippingAddressUpdateErrorEntity = {\n code: SHIPPING_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\nconst SELECT_OPTION_NETWORK_ERROR: ShippingOptionSelectUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to update the delivery option. Please try again.',\n};\n\n/**\n * The `shipping` namespace hook. Registered with the first-party action registry via `shippingActions`\n * below; the compiler-emitted `ShippingActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.shipping`. Writes persist purely through the normalized-cache merge of\n * each mutation response (Decision 2 of the address spec) — no refetch, no imperative write.\n */\nexport function useShippingActions(): ShippingActions {\n const [addressMutation] = useMutation(SHIPPING_ADDRESS_UPDATE);\n const [selectOptionMutation] = useMutation(SHIPPING_OPTION_SELECT);\n\n const setAddress = useCallback<ShippingActions['setAddress']>(\n async (address) => {\n try {\n const result = await addressMutation({ variables: { input: address } });\n return result.data?.shippingAddressUpdate.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.setAddress] shippingAddressUpdate failed', error);\n return [SET_ADDRESS_NETWORK_ERROR];\n }\n },\n [addressMutation],\n );\n\n const selectOption = useCallback<ShippingActions['selectOption']>(\n async (optionId) => {\n try {\n const result = await selectOptionMutation({ variables: { input: { optionId } } });\n return result.data?.shippingOptionSelect.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.selectOption] shippingOptionSelect failed', error);\n return [SELECT_OPTION_NETWORK_ERROR];\n }\n },\n [selectOptionMutation],\n );\n\n return useMemo(() => ({ setAddress, selectOption }), [setAddress, selectOption]);\n}\n\n/**\n * Declares the `shipping` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`, `sessionActions`). The native\n * catalog builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`;\n * at runtime `ShippingActionProvider` calls `useShippingActions` directly.\n */\nexport const shippingActions = defineActions({\n namespace: 'shipping',\n description: 'Mutation-backed delivery writes against the VTEX orderForm shippingData (address in T2; option in T3).',\n provider: { name: 'ShippingActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setAddress: {\n description:\n 'Persist the single delivery address in one submit (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'savedAddressId', type: 'string' },\n { name: 'recipientName', type: 'string' },\n { name: 'postalCode', type: 'string' },\n { name: 'country', type: 'string' },\n { name: 'street', type: 'string' },\n { name: 'number', type: 'string' },\n { name: 'complement', type: 'string' },\n { name: 'neighborhood', type: 'string' },\n { name: 'city', type: 'string' },\n { name: 'state', type: 'string' },\n ],\n },\n selectOption: {\n description: 'Select a delivery option for the whole cart (async/pessimistic). Resolves the payload userErrors.',\n payload: [{ name: 'optionId', type: 'string' }],\n },\n },\n use: useShippingActions,\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-shipping-actions.js","names":[],"sources":["../../../src/sdk/shipping/use-shipping-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { SHIPPING_OPTION_SELECT, type ShippingOptionSelectUserError } from './option-select-operations.js';\nimport {\n SHIPPING_ADDRESS_UPDATE,\n SHIPPING_NETWORK_ERROR_CODE,\n type ShippingAddressInput,\n type ShippingAddressUpdateErrorEntity,\n} from './shipping-operations.js';\n\n/**\n * The `shipping` action namespace — the sanctioned client write surface against the VTEX orderForm\n * shippingData: delivery-address updates (docs/storefront-core/reference-free-particle-model.md § The cart write contract;\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md) and cart-scoped delivery-option\n * selection (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Per Decision 4 the two tasks share this one\n * namespace — T2 (`setAddress`) merged first and owns the registration, T3 extends it with\n * `selectOption` here.\n *\n * Both actions are async/pessimistic (Decision 1 of the address spec): the handler awaits the\n * mutation and only the server-confirmed payload changes the cache. Each is stateless (no reactive\n * vars, no module state), resolves its payload `userErrors` (empty on success), and never throws for\n * expected outcomes; an infrastructure failure (network or an upstream GraphQLError) is caught and\n * collapsed to one synthetic network `userError` — no per-code branching (US-4, FR-5). Inputs pass\n * through mutation variables only — never logged, never stored beyond the cache.\n */\nexport type ShippingActions = Readonly<{\n /** Persist the single delivery address (async/pessimistic). Resolves the payload userErrors. */\n setAddress: (address: ShippingAddressInput) => Promise<readonly ShippingAddressUpdateErrorEntity[]>;\n /** Select a delivery option for the whole cart. Resolves the payload userErrors (empty on success). */\n selectOption: (optionId: string) => Promise<readonly ShippingOptionSelectUserError[]>;\n}>;\n\nconst SET_ADDRESS_NETWORK_ERROR: ShippingAddressUpdateErrorEntity = {\n code: SHIPPING_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\nconst SELECT_OPTION_NETWORK_ERROR: ShippingOptionSelectUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to update the delivery option. Please try again.',\n};\n\n/**\n * The `shipping` namespace hook. Registered with the first-party action registry via `shippingActions`\n * below; the compiler-emitted `ShippingActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.shipping`. Writes persist purely through the normalized-cache merge of\n * each mutation response (Decision 2 of the address spec) — no refetch, no imperative write.\n */\nexport function useShippingActions(): ShippingActions {\n const [addressMutation] = useMutation(SHIPPING_ADDRESS_UPDATE);\n const [selectOptionMutation] = useMutation(SHIPPING_OPTION_SELECT);\n\n const setAddress = useCallback<ShippingActions['setAddress']>(\n async (address) => {\n try {\n const result = await addressMutation({ variables: { input: address } });\n return result.data?.shippingAddressUpdate.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.setAddress] shippingAddressUpdate failed', loggableErrorName(error));\n return [SET_ADDRESS_NETWORK_ERROR];\n }\n },\n [addressMutation],\n );\n\n const selectOption = useCallback<ShippingActions['selectOption']>(\n async (optionId) => {\n try {\n const result = await selectOptionMutation({ variables: { input: { optionId } } });\n return result.data?.shippingOptionSelect.userErrors ?? [];\n } catch (error) {\n console.error('[shipping.selectOption] shippingOptionSelect failed', loggableErrorName(error));\n return [SELECT_OPTION_NETWORK_ERROR];\n }\n },\n [selectOptionMutation],\n );\n\n return useMemo(() => ({ setAddress, selectOption }), [setAddress, selectOption]);\n}\n\n/**\n * Declares the `shipping` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`, `sessionActions`). The native\n * catalog builder (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`;\n * at runtime `ShippingActionProvider` calls `useShippingActions` directly.\n */\nexport const shippingActions = defineActions({\n namespace: 'shipping',\n description: 'Mutation-backed delivery writes against the VTEX orderForm shippingData (address in T2; option in T3).',\n provider: { name: 'ShippingActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n setAddress: {\n description:\n 'Persist the single delivery address in one submit (async/pessimistic). Resolves the payload userErrors.',\n payload: [\n { name: 'savedAddressId', type: 'string' },\n { name: 'recipientName', type: 'string' },\n { name: 'postalCode', type: 'string' },\n { name: 'country', type: 'string' },\n { name: 'street', type: 'string' },\n { name: 'number', type: 'string' },\n { name: 'complement', type: 'string' },\n { name: 'neighborhood', type: 'string' },\n { name: 'city', type: 'string' },\n { name: 'state', type: 'string' },\n ],\n },\n selectOption: {\n description: 'Select a delivery option for the whole cart (async/pessimistic). Resolves the payload userErrors.',\n payload: [{ name: 'optionId', type: 'string' }],\n },\n },\n use: useShippingActions,\n});\n"],"mappings":";;;;;;;;;AAoCA,MAAM,4BAA8D;CAClE,MAAM;CACN,SAAS;AACX;AAEA,MAAM,8BAA6D;CACjE,MAAM;CACN,SAAS;AACX;;;;;;;AAQA,SAAgB,qBAAsC;CACpD,MAAM,CAAC,mBAAmB,YAAY,uBAAuB;CAC7D,MAAM,CAAC,wBAAwB,YAAY,sBAAsB;CAEjE,MAAM,aAAa,YACjB,OAAO,YAAY;EACjB,IAAI;GAEF,QAAO,MADc,gBAAgB,EAAE,WAAW,EAAE,OAAO,QAAQ,EAAE,CAAC,EAAA,CACxD,MAAM,sBAAsB,cAAc,CAAC;EAC3D,SAAS,OAAO;GACd,QAAQ,MAAM,sDAAsD,kBAAkB,KAAK,CAAC;GAC5F,OAAO,CAAC,yBAAyB;EACnC;CACF,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,eAAe,YACnB,OAAO,aAAa;EAClB,IAAI;GAEF,QAAO,MADc,qBAAqB,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,EAAA,CAClE,MAAM,qBAAqB,cAAc,CAAC;EAC1D,SAAS,OAAO;GACd,QAAQ,MAAM,uDAAuD,kBAAkB,KAAK,CAAC;GAC7F,OAAO,CAAC,2BAA2B;EACrC;CACF,GACA,CAAC,oBAAoB,CACvB;CAEA,OAAO,eAAe;EAAE;EAAY;CAAa,IAAI,CAAC,YAAY,YAAY,CAAC;AACjF;AAQ+B,cAAc;CAC3C,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAA0B,YAAY;CAAkC;CAC1F,SAAS;EACP,YAAY;GACV,aACE;GACF,SAAS;IACP;KAAE,MAAM;KAAkB,MAAM;IAAS;IACzC;KAAE,MAAM;KAAiB,MAAM;IAAS;IACxC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAW,MAAM;IAAS;IAClC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAU,MAAM;IAAS;IACjC;KAAE,MAAM;KAAc,MAAM;IAAS;IACrC;KAAE,MAAM;KAAgB,MAAM;IAAS;IACvC;KAAE,MAAM;KAAQ,MAAM;IAAS;IAC/B;KAAE,MAAM;KAAS,MAAM;IAAS;GAClC;EACF;EACA,cAAc;GACZ,aAAa;GACb,SAAS,CAAC;IAAE,MAAM;IAAY,MAAM;GAAS,CAAC;EAChD;CACF;CACA,KAAK;AACP,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/utils/own-value.ts
|
|
2
|
+
/**
|
|
3
|
+
* Own-property read. `Object.hasOwn`, not a bare index lookup or `key in source`: every plain object
|
|
4
|
+
* inherits from `Object.prototype`, so `source['constructor']` resolves to
|
|
5
|
+
* `Object.prototype.constructor` — a function, therefore never `undefined` — and `__proto__` to the
|
|
6
|
+
* prototype itself, and the absent-key branch of the caller would never be taken. Every keyed
|
|
7
|
+
* lookup here is fed an authored or user-typed key (an element id from `JSON.parse`, a card network
|
|
8
|
+
* or payment method name), so an inherited name must read as missing, never as a value.
|
|
9
|
+
*
|
|
10
|
+
* Lives in `utils/` because its callers span peer domains (`sdk/content`, `matter/card-entry`,
|
|
11
|
+
* `matter/payment`), none of which should import a lookup helper from another.
|
|
12
|
+
*/
|
|
13
|
+
function ownValue(source, key) {
|
|
14
|
+
return Object.hasOwn(source, key) ? source[key] : void 0;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ownValue };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=own-value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"own-value.js","names":[],"sources":["../../src/utils/own-value.ts"],"sourcesContent":["/**\n * Own-property read. `Object.hasOwn`, not a bare index lookup or `key in source`: every plain object\n * inherits from `Object.prototype`, so `source['constructor']` resolves to\n * `Object.prototype.constructor` — a function, therefore never `undefined` — and `__proto__` to the\n * prototype itself, and the absent-key branch of the caller would never be taken. Every keyed\n * lookup here is fed an authored or user-typed key (an element id from `JSON.parse`, a card network\n * or payment method name), so an inherited name must read as missing, never as a value.\n *\n * Lives in `utils/` because its callers span peer domains (`sdk/content`, `matter/card-entry`,\n * `matter/payment`), none of which should import a lookup helper from another.\n */\nexport function ownValue<T>(source: Record<string, T>, key: string): T | undefined {\n return Object.hasOwn(source, key) ? source[key] : undefined;\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,SAAY,QAA2B,KAA4B;CACjF,OAAO,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,KAAA;AACpD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PageRef } from "../sdk/navigation/types.js";
|
|
2
|
+
//#region src/utils/safe-href.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The sign-in page, carrying the current logical path so the shopper can be returned where they
|
|
5
|
+
* started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow
|
|
6
|
+
* the parameter again on arrival. A path the narrowing refuses drops the parameter instead of
|
|
7
|
+
* travelling encoded, and so does a router reporting no path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function signInTarget(path: string | null): PageRef;
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=safe-href.d.ts.map
|
package/dist/utils/safe-href.js
CHANGED
|
@@ -49,9 +49,8 @@ function resolveSafeHref(raw) {
|
|
|
49
49
|
reason: "forbidden-scheme"
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
/** The storefront's own sign-in
|
|
53
|
-
|
|
54
|
-
const SIGN_IN_ROUTE = "/login";
|
|
52
|
+
/** The storefront's own sign-in page, which forwards to the platform's login. Never an authored value. */
|
|
53
|
+
const SIGN_IN_PAGE = { standard: "sign-in" };
|
|
55
54
|
/** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */
|
|
56
55
|
const RETURN_URL_PARAM = "returnUrl";
|
|
57
56
|
/**
|
|
@@ -61,7 +60,7 @@ const RETURN_URL_PARAM = "returnUrl";
|
|
|
61
60
|
* unchanged, so a caller logging the reason still sees which spelling arrived.
|
|
62
61
|
*
|
|
63
62
|
* Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch
|
|
64
|
-
* for a URL the shopper typed: the account button builds the destination through `
|
|
63
|
+
* for a URL the shopper typed: the account button builds the destination through `signInTarget`, and
|
|
65
64
|
* the sign-in route revalidates what arrives through `resolveReturnHref`.
|
|
66
65
|
*/
|
|
67
66
|
function resolveSiteRelativeHref(raw) {
|
|
@@ -92,50 +91,60 @@ function resolveNavigableHref(raw) {
|
|
|
92
91
|
* `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route
|
|
93
92
|
* itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which
|
|
94
93
|
* hands them to the platform a second time — a sign-in that never lands where the parameter promised.
|
|
94
|
+
*
|
|
95
|
+
* `signInPath` is the sign-in page's logical path, since a return is one; `null` when the store has no
|
|
96
|
+
* sign-in page, and then no return is the route.
|
|
95
97
|
*/
|
|
96
|
-
function resolveReturnHref(raw) {
|
|
98
|
+
function resolveReturnHref(raw, signInPath) {
|
|
97
99
|
const destination = resolveSiteRelativeHref(raw);
|
|
98
100
|
if (!destination.safe) return destination;
|
|
99
|
-
return isSignInRoute(destination.href) ? {
|
|
101
|
+
return isSignInRoute(destination.href, signInPath) ? {
|
|
100
102
|
safe: false,
|
|
101
103
|
reason: "sign-in-route"
|
|
102
104
|
} : destination;
|
|
103
105
|
}
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Whether a site-relative value names the sign-in page at `signInPath`, in any of its spellings. `null`
|
|
108
|
+
* is a store without a sign-in page, where nothing is the route.
|
|
109
|
+
*/
|
|
110
|
+
function isSignInRoute(href, signInPath) {
|
|
111
|
+
return signInPath !== null && pathOf(href) === pathOf(signInPath);
|
|
107
112
|
}
|
|
108
113
|
/**
|
|
109
114
|
* `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in
|
|
110
|
-
* route is refused. Sending
|
|
115
|
+
* route is refused. Sending the route to itself reloads the same document, which mounts the same
|
|
111
116
|
* handover again — a loop the shopper never gets past, and the mirror of the refusal
|
|
112
117
|
* `resolveReturnHref` already makes on the way back.
|
|
113
118
|
*
|
|
114
119
|
* Only the site-relative spelling is decidable here, being same-origin by construction. An absolute
|
|
115
120
|
* address needs the document's own origin to compare against, which this module does not have and a
|
|
116
121
|
* prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin
|
|
117
|
-
* login page whose path happens to be
|
|
122
|
+
* login page whose path happens to be the route's is a different page and is left alone.
|
|
123
|
+
*
|
|
124
|
+
* `signInPath` is the sign-in page's public path, since the address is a document URL.
|
|
118
125
|
*/
|
|
119
|
-
function resolveLoginAddressHref(raw) {
|
|
126
|
+
function resolveLoginAddressHref(raw, signInPath) {
|
|
120
127
|
const address = resolveNavigableHref(raw);
|
|
121
128
|
if (!address.safe || !address.href.startsWith("/")) return address;
|
|
122
|
-
return isSignInRoute(address.href) ? {
|
|
129
|
+
return isSignInRoute(address.href, signInPath) ? {
|
|
123
130
|
safe: false,
|
|
124
131
|
reason: "sign-in-route"
|
|
125
132
|
} : address;
|
|
126
133
|
}
|
|
127
134
|
/**
|
|
128
|
-
*
|
|
135
|
+
* The sign-in page, carrying the current logical path so the shopper can be returned where they
|
|
129
136
|
* started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow
|
|
130
137
|
* the parameter again on arrival. A path the narrowing refuses drops the parameter instead of
|
|
131
|
-
* travelling encoded, and so does a router reporting no path
|
|
132
|
-
* a nullable one.
|
|
138
|
+
* travelling encoded, and so does a router reporting no path.
|
|
133
139
|
*/
|
|
134
|
-
function
|
|
135
|
-
if (!
|
|
136
|
-
const destination = resolveSiteRelativeHref(
|
|
137
|
-
if (!destination.safe) return
|
|
138
|
-
return
|
|
140
|
+
function signInTarget(path) {
|
|
141
|
+
if (!path) return SIGN_IN_PAGE;
|
|
142
|
+
const destination = resolveSiteRelativeHref(path);
|
|
143
|
+
if (!destination.safe) return SIGN_IN_PAGE;
|
|
144
|
+
return {
|
|
145
|
+
standard: "sign-in",
|
|
146
|
+
query: { [RETURN_URL_PARAM]: destination.href }
|
|
147
|
+
};
|
|
139
148
|
}
|
|
140
149
|
/** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a
|
|
141
150
|
* real host; nothing is navigated to it and only `pathname` is read back. */
|
|
@@ -164,6 +173,6 @@ function hasStrippableCharacter(value) {
|
|
|
164
173
|
return false;
|
|
165
174
|
}
|
|
166
175
|
//#endregion
|
|
167
|
-
export { RETURN_URL_PARAM, isSignInRoute, resolveLoginAddressHref, resolveNavigableHref, resolveReturnHref, resolveSafeHref,
|
|
176
|
+
export { RETURN_URL_PARAM, SIGN_IN_PAGE, isSignInRoute, resolveLoginAddressHref, resolveNavigableHref, resolveReturnHref, resolveSafeHref, resolveSiteRelativeHref, signInTarget };
|
|
168
177
|
|
|
169
178
|
//# sourceMappingURL=safe-href.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe-href.js","names":[],"sources":["../../src/utils/safe-href.ts"],"sourcesContent":["export type SafeHrefRejection =\n | 'blank'\n | 'malformed'\n | 'protocol-relative'\n | 'forbidden-scheme'\n | 'absolute'\n | 'sign-in-route';\n\nexport type SafeHrefResult = { safe: true; href: string } | { safe: false; reason: SafeHrefRejection };\n\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/**\n * The only gate on a CMS-authored destination: `http:`, `https:`, `mailto:`, `tel:`, and paths\n * starting with a single `/`. The runtime slice does not enforce a model's `pattern`, and the sukima\n * preflight that does never sees content published after a deploy, so an authored `javascript:` value\n * can reach the component intact and this is what stands between it and an `href`.\n *\n * Rejects rather than sanitizes: a destination that comes back safe is character-for-character the\n * trimmed authored value, so no value is ever silently rewritten into a different working one.\n */\nexport function resolveSafeHref(raw: string): SafeHrefResult {\n const href = raw.trim();\n if (href.length === 0) {\n return { safe: false, reason: 'blank' };\n }\n // Browsers strip ASCII tabs and newlines from a URL before parsing it, so `java<TAB>script:alert(1)`\n // executes. Refusing the whole value is the only defense that does not depend on stripping the same\n // characters in the same order the parser does.\n if (hasStrippableCharacter(href)) {\n return { safe: false, reason: 'malformed' };\n }\n // A URL parser reads `\\` as `/` under a special scheme, so `/\\evil.example` resolves against the\n // store's origin as an authority rather than a path. Any pair of leading slashes is an off-site\n // jump however it is spelled, and only `//` looks like one.\n if (/^[/\\\\]{2}/.test(href)) {\n return { safe: false, reason: 'protocol-relative' };\n }\n if (href.startsWith('/')) {\n return { safe: true, href };\n }\n\n let protocol: string;\n try {\n protocol = new URL(href).protocol;\n } catch {\n return { safe: false, reason: 'malformed' };\n }\n // `new URL` lowercases the protocol, so `JavaScript:` and `javascript:` are the same rejection.\n return ALLOWED_PROTOCOLS.has(protocol) ? { safe: true, href } : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/** The storefront's own sign-in route, which forwards to the platform's login. A fixed convention,\n * never an authored value. */\nconst SIGN_IN_ROUTE = '/login';\n\n/** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */\nexport const RETURN_URL_PARAM = 'returnUrl';\n\n/**\n * `resolveSafeHref` narrowed to the site-relative subset: the destinations a shopper may be sent back to\n * across the auth hop. The allowlist admits absolute http(s) values, which are legitimate for an authored\n * link but are exactly what would turn the hop into an open redirect. Every other rejection travels out\n * unchanged, so a caller logging the reason still sees which spelling arrived.\n *\n * Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch\n * for a URL the shopper typed: the account button builds the destination through `resolveSignInHref`, and\n * the sign-in route revalidates what arrives through `resolveReturnHref`.\n */\nexport function resolveSiteRelativeHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return destination.href.startsWith('/') ? destination : { safe: false, reason: 'absolute' };\n}\n\n/** The subset of the allowlist that resolves to a page a document can be handed over to. */\nconst NAVIGABLE_PROTOCOLS = new Set(['http:', 'https:']);\n\n/**\n * `resolveSafeHref` narrowed to the destinations that resolve to a page: site-relative, or absolute\n * `http(s)`. `mailto:` and `tel:` are legitimate for an authored link and refused here, since handing a\n * document over to one leaves the shopper in a mail client instead of a login.\n */\nexport function resolveNavigableHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe || destination.href.startsWith('/')) {\n return destination;\n }\n // The allowlist already parsed this value, so the protocol is readable without a second guard.\n const { protocol } = new URL(destination.href);\n return NAVIGABLE_PROTOCOLS.has(protocol) ? destination : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/**\n * `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route\n * itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which\n * hands them to the platform a second time — a sign-in that never lands where the parameter promised.\n */\nexport function resolveReturnHref(raw: string): SafeHrefResult {\n const destination = resolveSiteRelativeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return isSignInRoute(destination.href) ? { safe: false, reason: 'sign-in-route' } : destination;\n}\n\n/** Whether a site-relative value names the storefront's own sign-in route, in any of its spellings. */\nexport function isSignInRoute(href: string): boolean {\n return pathOf(href) === SIGN_IN_ROUTE;\n}\n\n/**\n * `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in\n * route is refused. Sending `/login` to `/login` reloads the same document, which mounts the same\n * handover again — a loop the shopper never gets past, and the mirror of the refusal\n * `resolveReturnHref` already makes on the way back.\n *\n * Only the site-relative spelling is decidable here, being same-origin by construction. An absolute\n * address needs the document's own origin to compare against, which this module does not have and a\n * prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin\n * login page whose path happens to be `/login` is a different page and is left alone.\n */\nexport function resolveLoginAddressHref(raw: string): SafeHrefResult {\n const address = resolveNavigableHref(raw);\n if (!address.safe || !address.href.startsWith('/')) {\n return address;\n }\n return isSignInRoute(address.href) ? { safe: false, reason: 'sign-in-route' } : address;\n}\n\n/**\n * Builds the sign-in destination, carrying the current path so the shopper can be returned where they\n * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow\n * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of\n * travelling encoded, and so does a router reporting no path — `usePathname()`'s type is why this takes\n * a nullable one.\n */\nexport function resolveSignInHref(pathname: string | null): string {\n if (!pathname) {\n return SIGN_IN_ROUTE;\n }\n const destination = resolveSiteRelativeHref(pathname);\n if (!destination.safe) {\n return SIGN_IN_ROUTE;\n }\n return `${SIGN_IN_ROUTE}?${RETURN_URL_PARAM}=${encodeURIComponent(destination.href)}`;\n}\n\n/** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a\n * real host; nothing is navigated to it and only `pathname` is read back. */\nconst PATH_COMPARISON_BASE = 'https://store.invalid';\n\n/**\n * The path of a site-relative value, without its query or fragment and without a trailing slash, so a\n * route comparison reads the route rather than one of its spellings. `/loginhelp` is a different path\n * and stays one.\n *\n * Parsed rather than sliced, because `/account/../login`, `/account\\..\\login` and `/account/%2e%2e/login`\n * are all spellings a URL parser resolves to `/login`. A slice compares them literally and admits them,\n * and the value then reaches a receiver that does resolve them — which puts the shopper back on the\n * trampoline the refusal exists to prevent. Only the comparison is normalized: the caller returns the\n * value as it arrived, so the promise that nothing is silently rewritten still holds.\n */\nfunction pathOf(href: string): string {\n const { pathname } = new URL(href, PATH_COMPARISON_BASE);\n return pathname.replace(/\\/+$/, '') || '/';\n}\n\n/** Any C0 control or space anywhere in the value — the set a URL parser removes or trims. */\nfunction hasStrippableCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";AAUA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC;;;;;;;;;;AAWxE,SAAgB,gBAAgB,KAA6B;CAC3D,MAAM,OAAO,IAAI,KAAK;CACtB,IAAI,KAAK,WAAW,GAClB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAQ;CAKxC,IAAI,uBAAuB,IAAI,GAC7B,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAY;CAK5C,IAAI,YAAY,KAAK,IAAI,GACvB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAoB;CAEpD,IAAI,KAAK,WAAW,GAAG,GACrB,OAAO;EAAE,MAAM;EAAM;CAAK;CAG5B,IAAI;CACJ,IAAI;EACF,WAAW,IAAI,IAAI,IAAI,CAAC,CAAC;CAC3B,QAAQ;EACN,OAAO;GAAE,MAAM;GAAO,QAAQ;EAAY;CAC5C;CAEA,OAAO,kBAAkB,IAAI,QAAQ,IAAI;EAAE,MAAM;EAAM;CAAK,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAmB;AAC5G;;;AAIA,MAAM,gBAAgB;;AAGtB,MAAa,mBAAmB;;;;;;;;;;;AAYhC,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,YAAY,KAAK,WAAW,GAAG,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAW;AAC5F;;AAGA,MAAM,sCAAsB,IAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;;;;;;AAOvD,SAAgB,qBAAqB,KAA6B;CAChE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,QAAQ,YAAY,KAAK,WAAW,GAAG,GACtD,OAAO;CAGT,MAAM,EAAE,aAAa,IAAI,IAAI,YAAY,IAAI;CAC7C,OAAO,oBAAoB,IAAI,QAAQ,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAmB;AACrG;;;;;;AAOA,SAAgB,kBAAkB,KAA6B;CAC7D,MAAM,cAAc,wBAAwB,GAAG;CAC/C,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,cAAc,YAAY,IAAI,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AACtF;;AAGA,SAAgB,cAAc,MAAuB;CACnD,OAAO,OAAO,IAAI,MAAM;AAC1B;;;;;;;;;;;;AAaA,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,KAAK,WAAW,GAAG,GAC/C,OAAO;CAET,OAAO,cAAc,QAAQ,IAAI,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAClF;;;;;;;;AASA,SAAgB,kBAAkB,UAAiC;CACjE,IAAI,CAAC,UACH,OAAO;CAET,MAAM,cAAc,wBAAwB,QAAQ;CACpD,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,GAAG,cAAc,GAAG,iBAAiB,GAAG,mBAAmB,YAAY,IAAI;AACpF;;;AAIA,MAAM,uBAAuB;;;;;;;;;;;;AAa7B,SAAS,OAAO,MAAsB;CACpC,MAAM,EAAE,aAAa,IAAI,IAAI,MAAM,oBAAoB;CACvD,OAAO,SAAS,QAAQ,QAAQ,EAAE,KAAK;AACzC;;AAGA,SAAS,uBAAuB,OAAwB;CACtD,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,OAAO,UAAU,YAAY,CAAC,KAAK;EACzC,IAAI,QAAQ,MAAQ,SAAS,KAC3B,OAAO;CAEX;CACA,OAAO;AACT"}
|
|
1
|
+
{"version":3,"file":"safe-href.js","names":[],"sources":["../../src/utils/safe-href.ts"],"sourcesContent":["import type { PageRef } from '../sdk/navigation/types.js';\n\nexport type SafeHrefRejection =\n | 'blank'\n | 'malformed'\n | 'protocol-relative'\n | 'forbidden-scheme'\n | 'absolute'\n | 'sign-in-route';\n\nexport type SafeHrefResult = { safe: true; href: string } | { safe: false; reason: SafeHrefRejection };\n\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/**\n * The only gate on a CMS-authored destination: `http:`, `https:`, `mailto:`, `tel:`, and paths\n * starting with a single `/`. The runtime slice does not enforce a model's `pattern`, and the sukima\n * preflight that does never sees content published after a deploy, so an authored `javascript:` value\n * can reach the component intact and this is what stands between it and an `href`.\n *\n * Rejects rather than sanitizes: a destination that comes back safe is character-for-character the\n * trimmed authored value, so no value is ever silently rewritten into a different working one.\n */\nexport function resolveSafeHref(raw: string): SafeHrefResult {\n const href = raw.trim();\n if (href.length === 0) {\n return { safe: false, reason: 'blank' };\n }\n // Browsers strip ASCII tabs and newlines from a URL before parsing it, so `java<TAB>script:alert(1)`\n // executes. Refusing the whole value is the only defense that does not depend on stripping the same\n // characters in the same order the parser does.\n if (hasStrippableCharacter(href)) {\n return { safe: false, reason: 'malformed' };\n }\n // A URL parser reads `\\` as `/` under a special scheme, so `/\\evil.example` resolves against the\n // store's origin as an authority rather than a path. Any pair of leading slashes is an off-site\n // jump however it is spelled, and only `//` looks like one.\n if (/^[/\\\\]{2}/.test(href)) {\n return { safe: false, reason: 'protocol-relative' };\n }\n if (href.startsWith('/')) {\n return { safe: true, href };\n }\n\n let protocol: string;\n try {\n protocol = new URL(href).protocol;\n } catch {\n return { safe: false, reason: 'malformed' };\n }\n // `new URL` lowercases the protocol, so `JavaScript:` and `javascript:` are the same rejection.\n return ALLOWED_PROTOCOLS.has(protocol) ? { safe: true, href } : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/** The storefront's own sign-in page, which forwards to the platform's login. Never an authored value. */\nexport const SIGN_IN_PAGE: PageRef = { standard: 'sign-in' };\n\n/** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */\nexport const RETURN_URL_PARAM = 'returnUrl';\n\n/**\n * `resolveSafeHref` narrowed to the site-relative subset: the destinations a shopper may be sent back to\n * across the auth hop. The allowlist admits absolute http(s) values, which are legitimate for an authored\n * link but are exactly what would turn the hop into an open redirect. Every other rejection travels out\n * unchanged, so a caller logging the reason still sees which spelling arrived.\n *\n * Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch\n * for a URL the shopper typed: the account button builds the destination through `signInTarget`, and\n * the sign-in route revalidates what arrives through `resolveReturnHref`.\n */\nexport function resolveSiteRelativeHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return destination.href.startsWith('/') ? destination : { safe: false, reason: 'absolute' };\n}\n\n/** The subset of the allowlist that resolves to a page a document can be handed over to. */\nconst NAVIGABLE_PROTOCOLS = new Set(['http:', 'https:']);\n\n/**\n * `resolveSafeHref` narrowed to the destinations that resolve to a page: site-relative, or absolute\n * `http(s)`. `mailto:` and `tel:` are legitimate for an authored link and refused here, since handing a\n * document over to one leaves the shopper in a mail client instead of a login.\n */\nexport function resolveNavigableHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe || destination.href.startsWith('/')) {\n return destination;\n }\n // The allowlist already parsed this value, so the protocol is readable without a second guard.\n const { protocol } = new URL(destination.href);\n return NAVIGABLE_PROTOCOLS.has(protocol) ? destination : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/**\n * `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route\n * itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which\n * hands them to the platform a second time — a sign-in that never lands where the parameter promised.\n *\n * `signInPath` is the sign-in page's logical path, since a return is one; `null` when the store has no\n * sign-in page, and then no return is the route.\n */\nexport function resolveReturnHref(raw: string, signInPath: string | null): SafeHrefResult {\n const destination = resolveSiteRelativeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return isSignInRoute(destination.href, signInPath) ? { safe: false, reason: 'sign-in-route' } : destination;\n}\n\n/**\n * Whether a site-relative value names the sign-in page at `signInPath`, in any of its spellings. `null`\n * is a store without a sign-in page, where nothing is the route.\n */\nexport function isSignInRoute(href: string, signInPath: string | null): boolean {\n return signInPath !== null && pathOf(href) === pathOf(signInPath);\n}\n\n/**\n * `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in\n * route is refused. Sending the route to itself reloads the same document, which mounts the same\n * handover again — a loop the shopper never gets past, and the mirror of the refusal\n * `resolveReturnHref` already makes on the way back.\n *\n * Only the site-relative spelling is decidable here, being same-origin by construction. An absolute\n * address needs the document's own origin to compare against, which this module does not have and a\n * prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin\n * login page whose path happens to be the route's is a different page and is left alone.\n *\n * `signInPath` is the sign-in page's public path, since the address is a document URL.\n */\nexport function resolveLoginAddressHref(raw: string, signInPath: string | null): SafeHrefResult {\n const address = resolveNavigableHref(raw);\n if (!address.safe || !address.href.startsWith('/')) {\n return address;\n }\n return isSignInRoute(address.href, signInPath) ? { safe: false, reason: 'sign-in-route' } : address;\n}\n\n/**\n * The sign-in page, carrying the current logical path so the shopper can be returned where they\n * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow\n * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of\n * travelling encoded, and so does a router reporting no path.\n */\nexport function signInTarget(path: string | null): PageRef {\n if (!path) {\n return SIGN_IN_PAGE;\n }\n const destination = resolveSiteRelativeHref(path);\n if (!destination.safe) {\n return SIGN_IN_PAGE;\n }\n return { standard: 'sign-in', query: { [RETURN_URL_PARAM]: destination.href } };\n}\n\n/** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a\n * real host; nothing is navigated to it and only `pathname` is read back. */\nconst PATH_COMPARISON_BASE = 'https://store.invalid';\n\n/**\n * The path of a site-relative value, without its query or fragment and without a trailing slash, so a\n * route comparison reads the route rather than one of its spellings. `/loginhelp` is a different path\n * and stays one.\n *\n * Parsed rather than sliced, because `/account/../login`, `/account\\..\\login` and `/account/%2e%2e/login`\n * are all spellings a URL parser resolves to `/login`. A slice compares them literally and admits them,\n * and the value then reaches a receiver that does resolve them — which puts the shopper back on the\n * trampoline the refusal exists to prevent. Only the comparison is normalized: the caller returns the\n * value as it arrived, so the promise that nothing is silently rewritten still holds.\n */\nfunction pathOf(href: string): string {\n const { pathname } = new URL(href, PATH_COMPARISON_BASE);\n return pathname.replace(/\\/+$/, '') || '/';\n}\n\n/** Any C0 control or space anywhere in the value — the set a URL parser removes or trims. */\nfunction hasStrippableCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";AAYA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC;;;;;;;;;;AAWxE,SAAgB,gBAAgB,KAA6B;CAC3D,MAAM,OAAO,IAAI,KAAK;CACtB,IAAI,KAAK,WAAW,GAClB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAQ;CAKxC,IAAI,uBAAuB,IAAI,GAC7B,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAY;CAK5C,IAAI,YAAY,KAAK,IAAI,GACvB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAoB;CAEpD,IAAI,KAAK,WAAW,GAAG,GACrB,OAAO;EAAE,MAAM;EAAM;CAAK;CAG5B,IAAI;CACJ,IAAI;EACF,WAAW,IAAI,IAAI,IAAI,CAAC,CAAC;CAC3B,QAAQ;EACN,OAAO;GAAE,MAAM;GAAO,QAAQ;EAAY;CAC5C;CAEA,OAAO,kBAAkB,IAAI,QAAQ,IAAI;EAAE,MAAM;EAAM;CAAK,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAmB;AAC5G;;AAGA,MAAa,eAAwB,EAAE,UAAU,UAAU;;AAG3D,MAAa,mBAAmB;;;;;;;;;;;AAYhC,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,YAAY,KAAK,WAAW,GAAG,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAW;AAC5F;;AAGA,MAAM,sCAAsB,IAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;;;;;;AAOvD,SAAgB,qBAAqB,KAA6B;CAChE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,QAAQ,YAAY,KAAK,WAAW,GAAG,GACtD,OAAO;CAGT,MAAM,EAAE,aAAa,IAAI,IAAI,YAAY,IAAI;CAC7C,OAAO,oBAAoB,IAAI,QAAQ,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAmB;AACrG;;;;;;;;;AAUA,SAAgB,kBAAkB,KAAa,YAA2C;CACxF,MAAM,cAAc,wBAAwB,GAAG;CAC/C,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,cAAc,YAAY,MAAM,UAAU,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAClG;;;;;AAMA,SAAgB,cAAc,MAAc,YAAoC;CAC9E,OAAO,eAAe,QAAQ,OAAO,IAAI,MAAM,OAAO,UAAU;AAClE;;;;;;;;;;;;;;AAeA,SAAgB,wBAAwB,KAAa,YAA2C;CAC9F,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,KAAK,WAAW,GAAG,GAC/C,OAAO;CAET,OAAO,cAAc,QAAQ,MAAM,UAAU,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAC9F;;;;;;;AAQA,SAAgB,aAAa,MAA8B;CACzD,IAAI,CAAC,MACH,OAAO;CAET,MAAM,cAAc,wBAAwB,IAAI;CAChD,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO;EAAE,UAAU;EAAW,OAAO,GAAG,mBAAmB,YAAY,KAAK;CAAE;AAChF;;;AAIA,MAAM,uBAAuB;;;;;;;;;;;;AAa7B,SAAS,OAAO,MAAsB;CACpC,MAAM,EAAE,aAAa,IAAI,IAAI,MAAM,oBAAoB;CACvD,OAAO,SAAS,QAAQ,QAAQ,EAAE,KAAK;AACzC;;AAGA,SAAS,uBAAuB,OAAwB;CACtD,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,OAAO,UAAU,YAAY,CAAC,KAAK;EACzC,IAAI,QAAQ,MAAQ,SAAS,KAC3B,OAAO;CAEX;CACA,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtex/faststore",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "FastStore AI Native component library built on Base UI with AI-editable styles",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://developers.vtex.com/docs/guides/faststore",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"import": "./dist/graphql.js",
|
|
26
26
|
"default": "./dist/graphql.js"
|
|
27
27
|
},
|
|
28
|
+
"./cli": {
|
|
29
|
+
"types": "./dist/cli/index.d.ts",
|
|
30
|
+
"import": "./dist/cli/index.js",
|
|
31
|
+
"default": "./dist/cli/index.js"
|
|
32
|
+
},
|
|
28
33
|
"./internal/client": {
|
|
29
34
|
"types": "./dist/internal/client.d.ts",
|
|
30
35
|
"import": "./dist/internal/client.js"
|
|
@@ -45,12 +50,16 @@
|
|
|
45
50
|
},
|
|
46
51
|
"files": [
|
|
47
52
|
"dist",
|
|
53
|
+
"skills",
|
|
48
54
|
"src/styles/tailwind.css",
|
|
49
55
|
"CHANGELOG.md"
|
|
50
56
|
],
|
|
51
57
|
"dependencies": {
|
|
52
58
|
"@base-ui/react": "^1.3.0",
|
|
53
59
|
"@graphql-typed-document-node/core": "^3.2.0",
|
|
60
|
+
"@vtex/country-forms": "1.14.0",
|
|
61
|
+
"@vtex/faststore-catalog": "0.0.8",
|
|
62
|
+
"esbuild": "~0.27.3",
|
|
54
63
|
"graphql": "^16.13.1",
|
|
55
64
|
"react-hook-form": "^7.85.0",
|
|
56
65
|
"react-intl": "^10.1.22",
|
|
@@ -63,6 +72,12 @@
|
|
|
63
72
|
"@apollo/client-integration-nextjs": "^0.14.5",
|
|
64
73
|
"next": ">=16",
|
|
65
74
|
"react": "^19.0.0",
|
|
66
|
-
"react-dom": "^19.0.0"
|
|
75
|
+
"react-dom": "^19.0.0",
|
|
76
|
+
"typescript": "^5.9.3"
|
|
77
|
+
},
|
|
78
|
+
"peerDependenciesMeta": {
|
|
79
|
+
"typescript": {
|
|
80
|
+
"optional": true
|
|
81
|
+
}
|
|
67
82
|
}
|
|
68
83
|
}
|