@vtex/faststore 0.0.4 → 0.0.6
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 +67 -0
- package/dist/actions.json +181 -0
- package/dist/catalog.json +1595 -481
- package/dist/client.d.ts +2 -1
- package/dist/client.js +2 -1
- package/dist/components.d.ts +31 -7
- package/dist/components.js +35 -13
- package/dist/content-types.json +73 -0
- package/dist/docs/access-code-sign-in.md +1 -1
- package/dist/docs/account-access-gate.md +153 -0
- package/dist/docs/account-entry-point.md +1 -2
- package/dist/docs/account-menu.md +164 -0
- package/dist/docs/address-summary.md +24 -3
- package/dist/docs/alert-dialog.md +204 -0
- package/dist/docs/billing-address.md +284 -0
- package/dist/docs/buy-button.md +1 -1
- package/dist/docs/card-entry.md +250 -0
- package/dist/docs/cardholder-document.md +142 -0
- package/dist/docs/cart.md +1 -1
- package/dist/docs/client-preferences-fieldset.md +148 -0
- package/dist/docs/client-preferences.md +2 -1
- package/dist/docs/client-profile-fieldset.md +184 -0
- package/dist/docs/client-profile.md +1 -1
- package/dist/docs/document-field.md +58 -4
- package/dist/docs/field.md +317 -0
- package/dist/docs/form.md +307 -0
- package/dist/docs/identity-edit.md +6 -6
- package/dist/docs/identity-summary.md +5 -5
- package/dist/docs/installments.md +248 -0
- package/dist/docs/my-account-profile.md +1 -0
- package/dist/docs/order-placed-payment-summary.md +138 -0
- package/dist/docs/payment-method-badges.md +232 -0
- package/dist/docs/payment-methods.md +1 -0
- package/dist/docs/payment.md +218 -0
- package/dist/docs/phone-field.md +58 -4
- package/dist/docs/place-order.md +157 -0
- package/dist/docs/save-card.md +186 -0
- package/dist/docs/saved-cards.md +218 -0
- package/dist/docs/select.md +465 -0
- package/dist/docs/session.md +1 -1
- package/dist/docs/shipping-address.md +110 -258
- package/dist/docs/sign-in-redirect.md +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/internal/client.d.ts +3 -1
- package/dist/internal/client.js +3 -1
- package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
- package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
- package/dist/matter/account-access-gate/account-access-gate.d.ts +86 -0
- package/dist/matter/account-access-gate/account-access-gate.js +283 -0
- package/dist/matter/account-access-gate/account-access-gate.js.map +1 -0
- package/dist/matter/account-access-gate/sign-out-intent.d.ts +17 -0
- package/dist/matter/account-access-gate/sign-out-intent.js +62 -0
- package/dist/matter/account-access-gate/sign-out-intent.js.map +1 -0
- package/dist/matter/account-entry-point/account-entry-point.js +2 -2
- package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
- package/dist/matter/account-menu/account-menu.d.ts +88 -0
- package/dist/matter/account-menu/account-menu.js +246 -0
- package/dist/matter/account-menu/account-menu.js.map +1 -0
- package/dist/matter/billing-address/billing-address.d.ts +165 -0
- package/dist/matter/billing-address/billing-address.js +408 -0
- package/dist/matter/billing-address/billing-address.js.map +1 -0
- package/dist/matter/card-entry/card-capture.d.ts +25 -0
- package/dist/matter/card-entry/card-capture.js +25 -0
- package/dist/matter/card-entry/card-capture.js.map +1 -0
- package/dist/matter/card-entry/card-entry.d.ts +120 -0
- package/dist/matter/card-entry/card-entry.js +832 -0
- package/dist/matter/card-entry/card-entry.js.map +1 -0
- package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
- package/dist/matter/cardholder-document/cardholder-document.js +70 -0
- package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
- package/dist/matter/cart/cart.d.ts +1 -1
- package/dist/matter/cart/cart.js +2 -2
- package/dist/matter/cart/cart.js.map +1 -1
- package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
- package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
- package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
- package/dist/matter/client-preferences/client-preferences.js +6 -6
- package/dist/matter/client-preferences/client-preferences.js.map +1 -1
- package/dist/matter/client-profile/client-profile.d.ts +4 -6
- package/dist/matter/client-profile/client-profile.js +9 -6
- package/dist/matter/client-profile/client-profile.js.map +1 -1
- package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
- package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
- package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
- package/dist/matter/delivery-options/delivery-options.js.map +1 -1
- package/dist/matter/identity-edit/identity-edit.js +2 -2
- package/dist/matter/identity-edit/identity-edit.js.map +1 -1
- package/dist/matter/identity-summary/identity-summary.js +2 -2
- package/dist/matter/identity-summary/identity-summary.js.map +1 -1
- package/dist/matter/installments/installments-select.d.ts +42 -0
- package/dist/matter/installments/installments-select.js +167 -0
- package/dist/matter/installments/installments-select.js.map +1 -0
- package/dist/matter/installments/installments.d.ts +58 -0
- package/dist/matter/installments/installments.js +176 -0
- package/dist/matter/installments/installments.js.map +1 -0
- package/dist/matter/installments/use-installments-selection.d.ts +29 -0
- package/dist/matter/installments/use-installments-selection.js +95 -0
- package/dist/matter/installments/use-installments-selection.js.map +1 -0
- package/dist/matter/my-account-profile/my-account-profile.js +5 -5
- package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
- package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
- package/dist/matter/payment/payment-card-capture.d.ts +19 -0
- package/dist/matter/payment/payment-card-capture.js +129 -0
- package/dist/matter/payment/payment-card-capture.js.map +1 -0
- package/dist/matter/payment/payment-controller.d.ts +24 -0
- package/dist/matter/payment/payment-controller.js +107 -0
- package/dist/matter/payment/payment-controller.js.map +1 -0
- package/dist/matter/payment/payment-method-badges.d.ts +57 -0
- package/dist/matter/payment/payment-method-badges.js +192 -0
- package/dist/matter/payment/payment-method-badges.js.map +1 -0
- package/dist/matter/payment/payment.d.ts +89 -0
- package/dist/matter/payment/payment.js +263 -0
- package/dist/matter/payment/payment.js.map +1 -0
- package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
- package/dist/matter/payment/use-payment-method-selection.js +458 -0
- package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
- package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
- package/dist/matter/payment/use-payment-submit-gate.js +144 -0
- package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
- package/dist/matter/place-order/place-order.d.ts +74 -0
- package/dist/matter/place-order/place-order.js +379 -0
- package/dist/matter/place-order/place-order.js.map +1 -0
- package/dist/matter/product-list/product-list.d.ts +1 -0
- package/dist/matter/product-list/product-list.js.map +1 -1
- package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
- package/dist/matter/product-shelf/product-shelf.js +2 -0
- package/dist/matter/product-shelf/product-shelf.js.map +1 -1
- package/dist/matter/region/region.js +1 -1
- package/dist/matter/region/region.js.map +1 -1
- package/dist/matter/save-card/save-card.d.ts +49 -0
- package/dist/matter/save-card/save-card.js +188 -0
- package/dist/matter/save-card/save-card.js.map +1 -0
- package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
- package/dist/matter/saved-cards/saved-cards.js +387 -0
- package/dist/matter/saved-cards/saved-cards.js.map +1 -0
- package/dist/matter/shipping-address/country-descriptors.js +20 -10
- package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
- package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
- package/dist/matter/shipping-address/shipping-address.js +481 -792
- package/dist/matter/shipping-address/shipping-address.js.map +1 -1
- package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
- package/dist/matter/variant-selector/variant-selector.js +1 -1
- package/dist/particles/address-summary/address-summary.d.ts +24 -0
- package/dist/particles/address-summary/address-summary.js +83 -2
- package/dist/particles/address-summary/address-summary.js.map +1 -1
- package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
- package/dist/particles/alert-dialog/alert-dialog.js +187 -0
- package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
- package/dist/particles/checkbox/checkbox.d.ts +7 -3
- package/dist/particles/checkbox/checkbox.js +4 -1
- package/dist/particles/checkbox/checkbox.js.map +1 -1
- package/dist/particles/document-field/document-field.d.ts +48 -5
- package/dist/particles/document-field/document-field.js +189 -32
- package/dist/particles/document-field/document-field.js.map +1 -1
- package/dist/particles/field/bound-field-registry.js +52 -0
- package/dist/particles/field/bound-field-registry.js.map +1 -0
- package/dist/particles/field/field.d.ts +116 -0
- package/dist/particles/field/field.js +497 -6
- package/dist/particles/field/field.js.map +1 -1
- package/dist/particles/fieldset/fieldset.js +2 -2
- package/dist/particles/fieldset/fieldset.js.map +1 -1
- package/dist/particles/footer-social/footer-social.js +1 -1
- package/dist/particles/form/form.d.ts +104 -0
- package/dist/particles/form/form.js +485 -0
- package/dist/particles/form/form.js.map +1 -0
- package/dist/particles/incentives/incentives.js +1 -1
- package/dist/particles/phone-field/phone-field.d.ts +38 -10
- package/dist/particles/phone-field/phone-field.js +183 -39
- package/dist/particles/phone-field/phone-field.js.map +1 -1
- package/dist/particles/postal-code-field/postal-code-field.js +2 -2
- package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
- package/dist/particles/select/field-select.d.ts +43 -0
- package/dist/particles/select/field-select.js +150 -0
- package/dist/particles/select/field-select.js.map +1 -0
- package/dist/particles/select/select.d.ts +2 -0
- package/dist/particles/select/select.js.map +1 -1
- package/dist/particles/shared/compose-refs.js +21 -0
- package/dist/particles/shared/compose-refs.js.map +1 -0
- package/dist/schema.graphql +701 -2
- package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
- package/dist/sdk/actions/analytics-action-provider.js +19 -0
- package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
- package/dist/sdk/actions/cart-action-provider.d.ts +1 -1
- package/dist/sdk/actions/cart-action-provider.js +1 -1
- package/dist/sdk/actions/cart-action-provider.js.map +1 -1
- package/dist/sdk/actions/index.d.ts +3 -1
- package/dist/sdk/actions/index.js +3 -1
- package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
- package/dist/sdk/actions/payment-action-provider.js +26 -0
- package/dist/sdk/actions/payment-action-provider.js.map +1 -0
- package/dist/sdk/actions/session-action-provider.d.ts +1 -1
- package/dist/sdk/actions/session-action-provider.js +1 -1
- package/dist/sdk/actions/session-action-provider.js.map +1 -1
- package/dist/sdk/actions/shipping-action-provider.d.ts +1 -1
- package/dist/sdk/actions/shipping-action-provider.js +1 -1
- package/dist/sdk/actions/shipping-action-provider.js.map +1 -1
- package/dist/sdk/actions/types.d.ts +6 -2
- package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
- package/dist/sdk/analytics/analytics-destination.js +90 -0
- package/dist/sdk/analytics/analytics-destination.js.map +1 -0
- package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
- package/dist/sdk/analytics/use-analytics-actions.js +108 -0
- package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
- package/dist/sdk/cache/storefront-cache.js +1 -1
- package/dist/sdk/cache/storefront-cache.js.map +1 -1
- package/dist/sdk/cart/operations.d.ts +4 -4
- package/dist/sdk/cart/operations.js +1 -1
- package/dist/sdk/cart/operations.js.map +1 -1
- package/dist/sdk/cart/optimistic.js +1 -1
- package/dist/sdk/cart/optimistic.js.map +1 -1
- package/dist/sdk/cart/use-cart-actions.d.ts +1 -1
- package/dist/sdk/cart/use-cart-actions.js +4 -4
- package/dist/sdk/cart/use-cart-actions.js.map +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js +1 -1
- package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
- package/dist/sdk/cart/write-gate.js +1 -1
- package/dist/sdk/cart/write-gate.js.map +1 -1
- package/dist/sdk/data/entity-resolution-context.js +31 -0
- package/dist/sdk/data/entity-resolution-context.js.map +1 -0
- package/dist/sdk/data/entity-subscriber.js +18 -8
- package/dist/sdk/data/entity-subscriber.js.map +1 -1
- package/dist/sdk/data/index.js +1 -0
- package/dist/sdk/data/page-reactive-data-root.d.ts +38 -2
- package/dist/sdk/data/page-reactive-data-root.js +4 -2
- package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
- package/dist/sdk/data/reactive-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-data-provider.js +8 -4
- package/dist/sdk/data/reactive-data-provider.js.map +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.d.ts +1 -1
- package/dist/sdk/data/reactive-list-item-data-provider.js +13 -5
- package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
- package/dist/sdk/data/use-reactive-data-settled.js +39 -0
- package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
- package/dist/sdk/data/use-reactive-entity.js +6 -2
- package/dist/sdk/data/use-reactive-entity.js.map +1 -1
- 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 +2 -1
- package/dist/sdk/generated/gql.js.map +1 -1
- package/dist/sdk/generated/graphql.js +85 -1
- package/dist/sdk/generated/graphql.js.map +1 -1
- package/dist/sdk/i18n/messages/en-US.js +3 -0
- package/dist/sdk/i18n/messages/en-US.json +3 -0
- package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
- package/dist/sdk/i18n/messages/es-ES.js +3 -0
- package/dist/sdk/i18n/messages/es-ES.json +3 -0
- package/dist/sdk/i18n/messages/pt-BR.js +3 -0
- package/dist/sdk/i18n/messages/pt-BR.json +3 -0
- package/dist/sdk/identity/operations.js.map +1 -1
- package/dist/sdk/identity/use-identity-actions.d.ts +1 -1
- package/dist/sdk/identity/use-identity-actions.js +3 -2
- package/dist/sdk/identity/use-identity-actions.js.map +1 -1
- package/dist/sdk/payment/gateway-origin.js +35 -0
- package/dist/sdk/payment/gateway-origin.js.map +1 -0
- package/dist/sdk/payment/gateway.d.ts +85 -0
- package/dist/sdk/payment/gateway.js +183 -0
- package/dist/sdk/payment/gateway.js.map +1 -0
- package/dist/sdk/payment/operations.d.ts +52 -0
- package/dist/sdk/payment/operations.js +223 -0
- package/dist/sdk/payment/operations.js.map +1 -0
- package/dist/sdk/payment/security-code-mask.js +71 -0
- package/dist/sdk/payment/security-code-mask.js.map +1 -0
- package/dist/sdk/payment/submission-registry.d.ts +33 -0
- package/dist/sdk/payment/submission-registry.js +58 -0
- package/dist/sdk/payment/submission-registry.js.map +1 -0
- package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
- package/dist/sdk/payment/use-payment-actions.js +276 -0
- package/dist/sdk/payment/use-payment-actions.js.map +1 -0
- package/dist/sdk/payment/use-place-order.d.ts +65 -0
- package/dist/sdk/payment/use-place-order.js +640 -0
- package/dist/sdk/payment/use-place-order.js.map +1 -0
- package/dist/sdk/session/auth-operations.d.ts +1 -1
- package/dist/sdk/session/auth-operations.js.map +1 -1
- package/dist/sdk/session/use-session-actions.d.ts +1 -1
- package/dist/sdk/session/use-session-actions.js.map +1 -1
- package/dist/sdk/session/use-session-revalidation.js +65 -0
- package/dist/sdk/session/use-session-revalidation.js.map +1 -0
- package/dist/sdk/shipping/option-select-operations.d.ts +1 -1
- package/dist/sdk/shipping/option-select-operations.js.map +1 -1
- package/dist/sdk/shipping/request-timeout.js +1 -1
- package/dist/sdk/shipping/request-timeout.js.map +1 -1
- package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
- package/dist/sdk/shipping/shipping-operations.js.map +1 -1
- package/dist/sdk/shipping/use-shipping-actions.d.ts +2 -2
- package/dist/sdk/shipping/use-shipping-actions.js +1 -1
- package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
- package/dist/sdk/state/cart.d.ts +3 -4
- package/dist/sdk/state/cart.js +6 -7
- package/dist/sdk/state/cart.js.map +1 -1
- package/dist/utils/loggable-error-name.js +49 -0
- package/dist/utils/loggable-error-name.js.map +1 -0
- package/dist/utils/resolve-authored-copy.js +18 -0
- package/dist/utils/resolve-authored-copy.js.map +1 -0
- package/dist/utils/safe-href.js +3 -3
- package/dist/utils/safe-href.js.map +1 -1
- package/dist/utils/substitute-template.js +33 -0
- package/dist/utils/substitute-template.js.map +1 -0
- package/package.json +2 -1
- package/src/styles/tailwind.css +34 -0
- package/dist/docs/client-profile-form.md +0 -192
- package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
- package/dist/matter/client-profile-form/client-profile-form.js +0 -662
- package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-place-order.js","names":[],"sources":["../../../src/sdk/payment/use-place-order.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useRef, useState } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport type { ComponentActions } from '../actions/types.js';\nimport type { PaymentGatewayTransaction } from './gateway.js';\nimport { isTrustedGatewayOrigin } from './gateway-origin.js';\nimport { PAYMENT_NETWORK_ERROR_CODE, type PaymentMoney, type PaymentUserError } from './operations.js';\nimport { type PaymentPreflightCheck, type PaymentSubmission, usePaymentSubmission } from './submission-registry.js';\nimport type {\n PaymentActions,\n PaymentGatewayCallbackResult,\n PaymentStartTransactionResult,\n} from './use-payment-actions.js';\n\n/**\n * The place-order orchestration (specs/use-place-order.md, T13; docs/features/credit-card/rfc.md\n * § D9) — the PCI-critical core of the credit-card feature, and the only module that knows placing an\n * order is three calls rather than one mutation.\n *\n * **This hook never holds card data.** It resolves an opaque continuation from the submission channel\n * by the shopper's entry path and invokes it between the two backend legs; the card stays in the\n * holder's closure (T7 for a new card, T12 for a saved one), which calls\n * `$actions.payment.sendPayments` itself. So the actions this hook needs are `startTransaction`,\n * `gatewayCallback`, and `analytics.track` — never the gateway façade. Two tests assert the boundary\n * against this file's own source text: no card field is named in code, and the single import from\n * `./gateway.js` is the transaction descriptor's type.\n *\n * The order of the pre-flight is load-bearing, not stylistic. The path, the continuation, and the\n * selected method are all resolved *before* `startTransaction` runs, because a transaction that is\n * opened and then cannot be completed is dangling state on the shopper's order form.\n *\n * v1 is the direct-API mode: the gateway leg resolves inline and the shopper stays on the page. The\n * redirect mode — an external navigation with a resume-on-callback route, and with it 3D Secure — is\n * phase 2, which is why no `callbackUrl` reaches the descriptor.\n *\n * Every failure resolves as `userErrors`; nothing here throws for an expected outcome, so the CTA\n * (T14) renders one error path. Its one per-code branch is PLACE_ORDER_UNCONFIRMED, a pending outcome\n * it shows as a status rather than an error (T176).\n */\n\n// ---------------------------------------------------------------------------\n// Client-synthesized error codes\n// ---------------------------------------------------------------------------\n\n/** No entry path chosen, or no holder registered for the one that was. */\nexport const PAYMENT_MISSING_SUBMISSION_CODE = 'MISSING_PAYMENT_SUBMISSION';\n\n/**\n * No payment method selected. Reuses `PaymentStartTransactionErrorCode`'s own value for the same\n * state, so a consumer matches one code whichever side detected it.\n */\nexport const PAYMENT_MISSING_METHOD_CODE = 'MISSING_PAYMENT_METHOD_SELECTION';\n\n/**\n * The transaction opened but cannot be paid — an incomplete payload, or an origin this client will\n * not post a card to. Reuses the server's code for the same meaning (T18 Decision 5).\n */\nexport const PAYMENT_INVALID_TRANSACTION_CODE = 'INVALID_TRANSACTION_DATA';\n\n/**\n * The attempt's own sequence is still running — opened or finalizing, not yet settled. Not a\n * refusal: nothing failed, the record just belongs to a sequence this caller did not start.\n */\nexport const PLACE_ORDER_IN_FLIGHT_CODE = 'PLACE_ORDER_IN_FLIGHT';\n\n/**\n * The gatewayCallback leg ran after the gateway accepted the card POST, and this client could not confirm\n * its outcome — the payment may or may not have been authorized. Not a refusal (T176).\n */\nexport const PLACE_ORDER_UNCONFIRMED_CODE = 'PLACE_ORDER_UNCONFIRMED';\n\nconst MISSING_SUBMISSION_ERROR: PaymentUserError = {\n code: PAYMENT_MISSING_SUBMISSION_CODE,\n message: 'Enter your payment details before placing the order.',\n};\n\nconst MISSING_METHOD_ERROR: PaymentUserError = {\n code: PAYMENT_MISSING_METHOD_CODE,\n message: 'Choose a payment method before placing the order.',\n};\n\nconst INVALID_TRANSACTION_ERROR: PaymentUserError = {\n code: PAYMENT_INVALID_TRANSACTION_CODE,\n message: 'Unable to start the payment. Please try again.',\n};\n\nconst PLACE_ORDER_IN_FLIGHT_ERROR: PaymentUserError = {\n code: PLACE_ORDER_IN_FLIGHT_CODE,\n message: 'This order is already being placed. Please wait.',\n};\n\n/**\n * Worded as a pending state, never a failure: it must not tell the shopper to try again (FR-1).\n * `PlaceOrder`'s `unconfirmedMessage` schema default repeats this text verbatim.\n */\nconst PLACE_ORDER_UNCONFIRMED_ERROR: PaymentUserError = {\n code: PLACE_ORDER_UNCONFIRMED_CODE,\n message: 'We could not confirm your order yet. Your payment may still be processing, so please do not pay again.',\n};\n\n/** Mirrors `usePaymentActions`' own infrastructure-failure userError, which that module keeps private. */\nconst NETWORK_ERROR: PaymentUserError = {\n code: PAYMENT_NETWORK_ERROR_CODE,\n message: 'Unable to complete the request. Please try again.',\n};\n\n// ---------------------------------------------------------------------------\n// Data the descriptor needs from the read model\n// ---------------------------------------------------------------------------\n\nexport type PlaceOrderInstallment = Readonly<{\n count: number;\n /** Per-installment amount, as a display decimal. The gateway's unit is minor units. */\n value: PaymentMoney;\n interestRate: number;\n}>;\n\nexport type PlaceOrderMethod = Readonly<{ id: string; groupName: string }>;\n\n/**\n * The `Payment` slice T14's fragment forwards (arity-1, ADR-0015) — the same convention as\n * `PaymentSectionData`. These five values are the part of the descriptor `paymentStartTransaction`\n * does not carry: T18 deliberately did not re-project the read model onto a write payload.\n */\nexport type PlaceOrderData = {\n selectedMethodId?: string | null;\n selectedInstallment?: PlaceOrderInstallment | null;\n methods?: readonly PlaceOrderMethod[];\n} | null;\n\nexport type PlaceOrderResult = Readonly<{\n /** The placed order's id, once the callback resolved one. */\n orderId: string | null;\n /** Empty on success. Carries the server's own codes verbatim when a backend leg reported one. */\n userErrors: readonly PaymentUserError[];\n}>;\n\nexport type UsePlaceOrder = Readonly<{\n /** Runs the three-call sequence. Resolves; never rejects for an expected outcome. */\n placeOrder: () => Promise<PlaceOrderResult>;\n /** True while the sequence runs — what T14's blocking loading state renders. */\n placing: boolean;\n /** The latest attempt's userErrors. Empty before the first attempt and while one is in flight. */\n userErrors: readonly PaymentUserError[];\n /** The latest attempt's order id. */\n orderId: string | null;\n}>;\n\n// ---------------------------------------------------------------------------\n// Payload settling\n// ---------------------------------------------------------------------------\n\n/**\n * The start payload once every field the descriptor needs is known non-null. `userProfileId` is the\n * exception: a guest order legitimately has none.\n */\ntype SettledTransaction = Readonly<{\n transactionId: string;\n merchantName: string;\n gatewayUrl: string;\n orderGroup: string;\n userProfileId: string | null;\n value: PaymentMoney;\n valueInCents: number;\n referenceValueInCents: number;\n}>;\n\n/** Identifiers, a host, and amounts — nothing here is sensitive, so naming them in a log is safe. */\nfunction missingTransactionFields(payload: PaymentStartTransactionResult): string[] {\n return Object.entries({\n transactionId: payload.transactionId,\n merchantName: payload.merchantName,\n orderGroup: payload.orderGroup,\n value: payload.value,\n valueInCents: payload.valueInCents,\n referenceValueInCents: payload.referenceValueInCents,\n })\n .filter(([, field]) => field === null)\n .map(([name]) => name);\n}\n\n/**\n * Narrows a payload that reported no userErrors, or refuses it. The origin is checked first and\n * separately: it is the field that decides where a card is sent, and a refusal here happens before\n * any holder is asked to assemble one.\n */\nfunction settleTransaction(payload: PaymentStartTransactionResult): SettledTransaction | null {\n if (!isTrustedGatewayOrigin(payload.gatewayUrl)) {\n console.error('[payment.placeOrder] the opened transaction carries no trusted https gateway origin');\n return null;\n }\n\n const { transactionId, merchantName, orderGroup, userProfileId, value, valueInCents, referenceValueInCents } =\n payload;\n\n if (\n transactionId === null ||\n merchantName === null ||\n orderGroup === null ||\n value === null ||\n valueInCents === null ||\n referenceValueInCents === null\n ) {\n console.error(\n '[payment.placeOrder] the opened transaction payload is incomplete',\n missingTransactionFields(payload).join(', '),\n );\n return null;\n }\n\n return {\n gatewayUrl: payload.gatewayUrl,\n transactionId,\n merchantName,\n orderGroup,\n userProfileId,\n value,\n valueInCents,\n referenceValueInCents,\n };\n}\n\n/**\n * The one derived amount on the descriptor. VTEX's `payments[0]` carries no per-installment minor-unit\n * value, so T18 could not expose one and the conversion stays here — rounded, because\n * `19.99 * 100 === 1998.9999999999998`. `Number()` is not redundant: the components codegen maps the\n * `Decimal` scalar to `number` while the resolver serializes it as a string (see the spec's Open items).\n */\nfunction toMinorUnits(amount: number): number {\n return Math.round(Number(amount) * 100);\n}\n\n/**\n * The one call into holder-owned code. A holder's continuation is specified to resolve `userErrors` —\n * `sendPayments` already collapses every gateway outcome to one — so a throw means its contract broke.\n * Only a sanitised error *name* is logged (T160): the closure that threw holds the card, and a message\n * or stack could echo it — and so, unsanitised, could `.name` itself, since it is a writable own\n * property. See `loggableErrorName()`.\n */\nasync function invokeSubmission(\n submit: PaymentSubmission,\n transaction: PaymentGatewayTransaction,\n): Promise<readonly PaymentUserError[]> {\n try {\n // T160: totals the awaited resolution inside this `try`, mirroring `invokeStartTransaction`'s and\n // `invokeGatewayCallback`'s own T156 fix shape — a bare `return await submit(transaction)` let a\n // nullish resolution escape untouched, so the caller's own `submissionErrors.length` read threw\n // one call site away, latching the attempt at `opening` past the point `resume()` can reach it.\n const result = await submit(transaction);\n if (result == null) {\n console.error('[payment.placeOrder] the registered submission resolved with no result');\n return [NETWORK_ERROR];\n }\n return result;\n } catch (error) {\n console.error('[payment.placeOrder] the registered submission threw', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n}\n\n/**\n * The pre-flight counterpart of `invokeSubmission`, and it inherits that function's one rule: the\n * closure that throws holds the card, so only a sanitised error *name* is logged (T160) — never a\n * message, a stack, or the raw writable `.name` property. See `loggableErrorName()`.\n */\nfunction runPreflight(check: PaymentPreflightCheck): readonly PaymentUserError[] {\n try {\n return check();\n } catch (error) {\n console.error('[payment.placeOrder] the registered pre-flight threw', loggableErrorName(error));\n return [NETWORK_ERROR];\n }\n}\n\n/**\n * The `startTransaction` counterpart of `invokeSubmission`/`runPreflight` (fix pass, Medium finding):\n * before this, `run()` awaited `startTransaction()` directly, so a **rejection** — as opposed to a\n * resolved payload carrying `userErrors` — escaped past every one of `run()`'s own outcome branches\n * and `settleSequence`'s rejection handler never touches the attempt record, leaving it stuck at\n * `opening` for the payment root's lifetime. `opening` is the one phase `placeOrder()` treats as\n * \"already running\" with no failure exit, so every later click resolves `{ orderId: null, userErrors:\n * [] }` without running anything — a false \"Order placed successfully.\" with the CTA disabled forever.\n * `usePlaceOrder` is exported public API and `$actions` is compiler-injected and pluggable, so a\n * provider that rejects here is reachable, not hypothetical. Collapsing the rejection to a resolved\n * payload with one `userErrors` entry means `run()`'s own existing `payload.userErrors.length > 0`\n * branch is what catches it — the same `refused` outcome a server-reported refusal already gets,\n * correct here too since nothing can have been paid before the transaction even opened.\n *\n * T156 fold: the result is destructured inside this `try`, not returned as `await startTransaction()`\n * untouched — a provider resolving `undefined` used to throw at the caller's own\n * `payload.userErrors.length` read, past this function's own `catch`, latching the attempt at\n * `opening` exactly like the rejection case above. Destructuring a nullish resolution throws here\n * instead, so it collapses the same way. Mirrors `invokeGatewayCallback`'s own reason for\n * destructuring, below.\n *\n * Fix pass (review F1/S1): `userErrors` is defaulted with `?? [NETWORK_ERROR]`, not `?? []` — a\n * *partial* payload (present, but missing `userErrors`, e.g. a provider whose GraphQL selection omits\n * the field) used to leave it `undefined`, reaching the caller's `payload.userErrors.length` read\n * (`:627`) and throwing past this function's own `catch`, latching the attempt at `opening` exactly\n * like the cases already fixed. `userErrors` is this result's only signal of whether anything actually\n * went wrong, so a payload that omits it defaults to a *failure*, mirroring a rejection — defaulting to\n * `[]` instead would settle the attempt on a payload this function never actually saw. (The in-repo\n * default provider's own `payload?.userErrors ?? []`, `use-payment-actions.ts:202`, defaults to `[]`\n * only because there `payload` itself — not just the field — is what may be missing.)\n */\nasync function invokeStartTransaction(\n startTransaction: PaymentActions['startTransaction'],\n): Promise<PaymentStartTransactionResult> {\n try {\n const {\n transactionId,\n merchantName,\n gatewayUrl,\n orderGroup,\n userProfileId,\n value,\n valueInCents,\n referenceValueInCents,\n userErrors,\n } = await startTransaction();\n if (userErrors == null) {\n console.error('[payment.placeOrder] startTransaction resolved with no userErrors', orderGroup);\n }\n return {\n transactionId,\n merchantName,\n gatewayUrl,\n orderGroup,\n userProfileId,\n value,\n valueInCents,\n referenceValueInCents,\n userErrors: userErrors ?? [NETWORK_ERROR],\n };\n } catch (error) {\n console.error('[payment.placeOrder] startTransaction threw', loggableErrorName(error));\n return {\n transactionId: null,\n merchantName: null,\n gatewayUrl: null,\n orderGroup: null,\n userProfileId: null,\n value: null,\n valueInCents: null,\n referenceValueInCents: null,\n userErrors: [NETWORK_ERROR],\n };\n }\n}\n\n/**\n * The `gatewayCallback` counterpart of `invokeStartTransaction` above (T156, PR #756 review R-004):\n * before this, both call sites below awaited `gatewayCallback` directly, so a **rejection**\n * escaped past every outcome branch and `settleSequence`'s rejection handler never touches the attempt\n * record, leaving it stuck at `finalizing` for the payment root's lifetime — `placeOrder()` treats\n * `finalizing` exactly like `opening`, an already-running phase with no failure exit, so every later\n * click resolved `{ orderId: attempt.orderId, userErrors: [] }` without issuing anything.\n *\n * The destination is `unresolved`, never `refused` like `invokeStartTransaction`'s own collapse: this\n * leg only runs once the card already reached the gateway, so nothing here can pretend no money moved.\n * `unresolved` is exactly the phase `PlaceOrderAttemptPhase` already documents for this case, below,\n * and is already resumable.\n *\n * Three failure shapes collapse to the same `NETWORK_ERROR` result, logged distinctly (fix pass,\n * review F1/S1/F3): a **rejection**, caught below; a **nullish resolution** (`undefined`/`null`),\n * caught by the explicit check that follows rather than by letting a destructure throw, so it logs a\n * line of its own instead of printing identically to a rejection; and a **partial resolution** — an\n * object present but missing `userErrors`, e.g. a provider whose GraphQL selection omits the field —\n * defaulted with `?? [NETWORK_ERROR]`, not `?? []`. That last case used to return `{ orderId,\n * userErrors }` untouched, leaving `userErrors: undefined`, so the *caller's* `callback.userErrors.length`\n * read threw one call site away from where this wrapper's whole job is to stop exactly that. `[]` would\n * default a payload this function never actually saw to a clean success; `userErrors` is the only\n * signal of whether the callback settled anything, so omitting it means treating it as a failure.\n * Both failure branches log `orderGroup` and `attemptId` — neither is card data\n * (`missingTransactionFields`'s comment above), and this is the one point in the flow where money may\n * already have moved — but never the error's message, stack, or any call argument (FR-6).\n *\n * No `gatewayCallback` call may exist in this module outside this function (INV-2, asserted against\n * this file's own source text in use-place-order.test.tsx) — the two call sites below (`resume()` and\n * `run()`) call this and nothing else.\n */\nasync function invokeGatewayCallback(\n gatewayCallback: PaymentActions['gatewayCallback'],\n orderGroup: string,\n attemptId: string,\n): Promise<PaymentGatewayCallbackResult> {\n let result: PaymentGatewayCallbackResult | null | undefined;\n try {\n result = await gatewayCallback(orderGroup);\n } catch (error) {\n console.error('[payment.placeOrder] gatewayCallback threw', orderGroup, attemptId, loggableErrorName(error));\n return { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n\n if (result == null) {\n console.error('[payment.placeOrder] gatewayCallback resolved with no result', orderGroup, attemptId);\n return { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n\n if (result.userErrors == null) {\n console.error('[payment.placeOrder] gatewayCallback resolved with no userErrors', orderGroup, attemptId);\n }\n return { orderId: result.orderId ?? null, userErrors: result.userErrors ?? [NETWORK_ERROR] };\n}\n\n/**\n * T176 (FR-2, FR-3): what the caller reads from a `gatewayCallback` that reported `userErrors`, on both\n * paths that issue it. The gateway already accepted the card POST by then, so a result made only of this\n * package's own collapse — `PAYMENT_NETWORK_ERROR_CODE`, which `usePaymentActions` and\n * `invokeGatewayCallback` resolve for every thrown, lost or shapeless response — says nothing about\n * whether VTEX processed the order. It becomes PLACE_ORDER_UNCONFIRMED rather than a \"try again\" that\n * invites a second payment. A code the server sent is an answer, and comes back unchanged (INV-10).\n *\n * Total, and never throws: a non-array, or an entry with no readable string `code`, carries no server\n * code, so it reads as unconfirmed too. A server code elsewhere in the same list still wins, whatever\n * order the entries come in.\n */\nfunction reconcileCallbackUserErrors(userErrors: readonly PaymentUserError[]): readonly PaymentUserError[] {\n try {\n if (!Array.isArray(userErrors)) return [PLACE_ORDER_UNCONFIRMED_ERROR];\n if (userErrors.length === 0) return userErrors;\n const carriesServerCode = userErrors.some((userError) => {\n try {\n const code = userError.code;\n return typeof code === 'string' && code !== PAYMENT_NETWORK_ERROR_CODE;\n } catch {\n return false;\n }\n });\n return carriesServerCode ? userErrors : [PLACE_ORDER_UNCONFIRMED_ERROR];\n } catch {\n return [PLACE_ORDER_UNCONFIRMED_ERROR];\n }\n}\n\n/**\n * `crypto.randomUUID()` is secure-context-only (fix pass, Low finding) — on a plain-HTTP preview or\n * staging origin the method does not exist on `crypto` at all, so calling it throws, and every click\n * collapses to a generic `NETWORK_ERROR` with no diagnostic. `localhost` is always a secure context,\n * so dev never reproduces it. Falls back to a timestamp+random string, which only needs to be unique\n * for one payment root's lifetime (the staleness guard below is its one reader) — not a real UUID.\n */\nfunction generateAttemptId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * Fix pass (High finding, race #2): guards every write past an attempt's genesis against a stale,\n * out-of-order completion clobbering a newer outcome. `run()`/`resume()` mint one write *before* their\n * own first await (safe by construction — nothing can have superseded an attempt this call itself just\n * created) and one or more writes *after* an await, once `startTransaction`/the continuation/\n * `gatewayCallback` resolve. Because the writing closure keeps running after its own CTA unmounts\n * (NFR-3), that later write cannot assume the shared attempt is still the one it started with — a\n * remounted or sibling instance may have already resumed it to a newer phase in the meantime. Using\n * the setter's own functional-update form (`SetPlaceOrderAttempt`) checks against whatever the shared\n * attempt actually is *when the write is applied*, not the value this closure captured before its\n * await — mirrors `selectionToken`'s own precedent (`matter/payment/use-payment-method-selection.ts`)\n * for the identical shape of problem, keyed on the attempt's own id instead of a second counter.\n * `settled` is additionally excluded because INV-6 forbids any transition away from it.\n */\nfunction writeAttemptIfCurrent(\n setAttempt: SetPlaceOrderAttempt | null | undefined,\n attemptId: string,\n next: PlaceOrderAttempt | null,\n): void {\n setAttempt?.((prev) => (prev !== null && prev.attemptId === attemptId && prev.phase !== 'settled' ? next : prev));\n}\n\n/**\n * T29 (Decision 3, FR-3): the only path back into a `sent`/`unresolved` attempt — `gatewayCallback` is\n * the sole call it ever issues. Module scope, not a `useCallback` inside the hook (fix pass, Low\n * finding): the previous version of this doc comment claimed `startTransaction`, the submission\n * channel, and `PaymentGatewayTransaction` were \"not in scope,\" so a careless future edit could not\n * make a resume re-pay — true at runtime today (verified by identifier sweep) but false as a\n * structural guarantee, since all three were merely unreferenced identifiers a nested closure could\n * still have read. Hoisting here makes the claim actually true: none of those three is even\n * *importable* from a bare module-level function that takes only `gatewayCallback`/`setAttempt`/\n * `setPlacing`/`current` as arguments — a resume is safe by construction, not by convention.\n */\nasync function resume(\n gatewayCallback: PaymentActions['gatewayCallback'] | undefined,\n setAttempt: SetPlaceOrderAttempt | null | undefined,\n setPlacing: (placing: boolean) => void,\n current: PlaceOrderAttempt,\n): Promise<PlaceOrderResult> {\n if (!gatewayCallback || current.orderGroup === null) {\n // Not reachable through this hook's own writes — §3's own invariant keeps `orderGroup` non-null\n // past `opening` — only through a caller-constructed attempt or a missing action namespace. Fails\n // the same way `run()`'s own first guard does, above.\n console.error('[payment.placeOrder] cannot resume an attempt with no order group');\n return { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n\n // Mirrors `run()`'s own `setPlacing(true)` placement, immediately before its one `await`, so the\n // shared placing state stays accurate across a remount too. A plain write, guarded by\n // `writeAttemptIfCurrent` rather than an unconditional one, since `current` is a caller-supplied\n // snapshot that may already be stale by the time this async function actually runs.\n writeAttemptIfCurrent(setAttempt, current.attemptId, { ...current, phase: 'finalizing' });\n setPlacing(true);\n\n const callback = await invokeGatewayCallback(gatewayCallback, current.orderGroup, current.attemptId);\n const failed = callback.userErrors.length > 0;\n // T176 (FR-4, FR-7): the result is fixed by the callback before the write, so a caller-supplied\n // writer that throws can no longer turn a confirmed order into a rejection — `settleSequence` would\n // resolve that as NETWORK_ERROR. The record may stay at `finalizing` then; nothing here can repair a\n // broken writer. Only a sanitised error name is logged, as on every other catch in this module.\n const result: PlaceOrderResult = failed\n ? { orderId: null, userErrors: reconcileCallbackUserErrors(callback.userErrors) }\n : { orderId: callback.orderId, userErrors: [] };\n\n try {\n writeAttemptIfCurrent(\n setAttempt,\n current.attemptId,\n failed ? { ...current, phase: 'unresolved' } : { ...current, phase: 'settled', orderId: callback.orderId },\n );\n } catch (error) {\n console.error('[payment.placeOrder] the resume record write threw', current.attemptId, loggableErrorName(error));\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// The order-attempt record (T29, specs/make-an-order-attempt-survive-a.md) — an identity and a phase\n// that outlive the CTA's own mount, so a remount or a second click resumes a sequence instead of\n// re-running its dangerous half. Defined here, not in matter/payment/use-payment-method-selection.ts:\n// this is the only module that knows the sequence is three calls, and the layering stays\n// matter → sdk (submission-registry.tsx's own rule) — usePaymentMethodSelection imports this type,\n// mirroring `PaymentPath`'s own alias of `PaymentSubmissionPath`.\n// ---------------------------------------------------------------------------\n\n/**\n * How far an order attempt got. The phase, not an error code, is what says whether money may already\n * have moved — an aborted card POST and a refused transaction both surface as the same userError, and\n * only this distinguishes them.\n */\nexport type PlaceOrderAttemptPhase =\n /** `startTransaction` issued or resolved. Nothing has been paid. */\n | 'opening'\n /** A leg refused before the card left the browser. A fresh full attempt is legal. */\n | 'refused'\n /** The continuation resolved with no userErrors — the card reached the gateway. */\n | 'sent'\n /** The card's fate is unknown: the continuation threw, or the POST was aborted, or a finalization\n * did not resolve. Treated exactly like `sent`. */\n | 'unresolved'\n /** `gatewayCallback` is in flight for this attempt's order group. */\n | 'finalizing'\n /** `gatewayCallback` resolved with no userErrors. Terminal. */\n | 'settled';\n\nexport type PlaceOrderAttempt = Readonly<{\n /** Identity that outlives any one mount. Not `useId()` — that is per-instance and resets. */\n attemptId: string;\n phase: PlaceOrderAttemptPhase;\n /** Resolved by `startTransaction`; the only key a resume needs. Null before `opening` settles. */\n orderGroup: string | null;\n /**\n * Resolved by `gatewayCallback`. Not an independent identifier: the resolver returns\n * `orderId: input.orderGroup` (`checkout/index.ts:1965`), echoing the argument back, because the\n * upstream success response body is discarded. So `orderId === orderGroup` on every success today.\n */\n orderId: string | null;\n}>;\n\n/**\n * Fix pass (High finding, race #2): widened past a plain value so a write can be made conditional on\n * whatever the shared attempt actually is *at write time* — the primitive `useState` already exposes\n * this (its setter has always accepted an updater function; only this package's own declared type\n * stopped a caller from using that form). A plain value remains valid; every existing caller that\n * never needed the guard is unaffected.\n */\nexport type SetPlaceOrderAttempt = (\n update: PlaceOrderAttempt | null | ((prev: PlaceOrderAttempt | null) => PlaceOrderAttempt | null),\n) => void;\n\n// ---------------------------------------------------------------------------\n// The hook\n// ---------------------------------------------------------------------------\n\nexport type UsePlaceOrderArgs = {\n /** `Payment` slice from the caller's fragment. */\n $data?: PlaceOrderData;\n /** Compiler-injected action surface; carries `payment.startTransaction`, `payment.gatewayCallback`, and `analytics.track`. */\n $actions?: ComponentActions;\n /**\n * T29's order-attempt record and its writer — `usePayment().attempt` / `.setAttempt`, forwarded by\n * the caller exactly like `billingAddressDifferent` below. **Optional by necessity, not by safety**\n * (mirrors `submitGate`'s own doc note): a caller that omits either gets today's behaviour, silently\n * — `placeOrder()` always takes the full `run()` path, with no resume and no phase written anywhere.\n * `PlaceOrder` always sources both from `usePayment()`.\n */\n attempt?: PlaceOrderAttempt | null;\n /** See `attempt` above. Identity must be stable across renders (NFR-3) — `usePayment().setAttempt` already is. */\n setAttempt?: SetPlaceOrderAttempt | null;\n /**\n * `usePayment().draft.billingAddressDifferent` (T11's widening of `PaymentDraft`) — an explicit\n * argument, not read from `usePayment()`'s context in this hook, so the hook keeps its existing\n * shape of taking every fact it needs as a parameter rather than adding a second hard context\n * dependency alongside the submission channel below. `null`/omitted folds to the same \"not set\"\n * descriptor shape `gateway.ts`'s own `transaction.billingAddressDifferent ?? false` already expects\n * (fix pass, PR #544 review F1). The caller is responsible for sourcing this from `usePayment()` and\n * forwarding it here.\n */\n billingAddressDifferent?: boolean | null;\n /**\n * A client-side refusal the caller already resolved, or `null` to proceed. Deliberately an opaque\n * `PaymentUserError` rather than the facts behind it: this module may name no identifier matching\n * `CARD_FIELD_PATTERN`, which includes `document`. The caller owns resolving it —\n * `matter/payment/usePaymentSubmitGate()` is the one in this package.\n *\n * **Optional by necessity, not by safety.** This hook is exported public API; `PlaceOrder` is the\n * only in-repo caller, and it always sources this from `usePaymentSubmitGate()`, but nothing stops a\n * storefront from composing its own place-order button directly on this hook. Omitting this argument\n * is silent and behaves exactly as if this whole pre-flight branch did not exist — no cardholder or\n * billing-address refusal ever reaches a CTA built that way, even though the same client-side gate\n * would have caught it. There is no compile-time signal for that omission (making the type mandatory\n * would be a breaking change to a hook other code may already call, and a caller can still opt out\n * explicitly with `null` regardless of the type), so a store composing its own CTA on this hook must\n * source this argument from `usePaymentSubmitGate()` deliberately, not by copying an example that\n * happened to include it.\n */\n submitGate?: PaymentUserError | null;\n};\n\nexport function usePlaceOrder({\n $data,\n $actions,\n attempt,\n setAttempt,\n billingAddressDifferent,\n submitGate,\n}: UsePlaceOrderArgs): UsePlaceOrder {\n const { path, resolve, resolvePreflight } = usePaymentSubmission();\n\n const [placing, setPlacing] = useState(false);\n const [userErrors, setUserErrors] = useState<readonly PaymentUserError[]>([]);\n const [orderId, setOrderId] = useState<string | null>(null);\n const inFlight = useRef<Promise<PlaceOrderResult> | null>(null);\n\n const startTransaction = $actions?.payment?.startTransaction;\n const gatewayCallback = $actions?.payment?.gatewayCallback;\n const track = $actions?.analytics?.track;\n\n const selectedMethodId = $data?.selectedMethodId ?? null;\n const methods = $data?.methods;\n const selectedInstallment = $data?.selectedInstallment ?? null;\n\n const selectedMethod = useMemo(\n () => methods?.find((method) => method.id === selectedMethodId) ?? null,\n [methods, selectedMethodId],\n );\n\n const run = useCallback(async (): Promise<PlaceOrderResult> => {\n if (!startTransaction || !gatewayCallback) {\n console.error('[payment.placeOrder] the payment action namespace is not injected');\n return { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n\n // Resolved before anything is opened (epic, T13): a transaction nothing can complete is dangling\n // state on the order form. The two causes are one state to a shopper and differ only in the log.\n const submit = path === null ? null : resolve(path);\n if (submit === null) {\n console.error('[payment.placeOrder] no submission is registered for the entry path', path ?? 'none');\n return { orderId: null, userErrors: [MISSING_SUBMISSION_ERROR] };\n }\n\n // `paymentSystem` and `groupName` come from the read model, not from the start payload, so a\n // missing selection would otherwise surface only after the transaction was already open.\n if (selectedMethod === null) {\n console.error('[payment.placeOrder] no payment method is selected');\n return { orderId: null, userErrors: [MISSING_METHOD_ERROR] };\n }\n\n // T24's submit gate: an already-resolved client-side refusal (`matter/payment/\n // usePaymentSubmitGate()`), joining the pre-flight so no transaction opens for a submission this\n // client already knows would be refused. Only the opaque verdict is logged — never a fact behind\n // it — keeping this module's own PCI boundary intact (Decision 2).\n if (submitGate) {\n console.error('[payment.placeOrder] a client-side gate refused the submission', submitGate.code);\n return { orderId: null, userErrors: [submitGate] };\n }\n\n // The holder's own pre-flight on the draft it holds (T27). It resolves the same verdict its\n // submission would have resolved at :348, one network leg earlier, so an avoidable input mistake\n // never opens a transaction that is then left dangling. Only the opaque refusal crosses back —\n // this module learns nothing about what was wrong, exactly as with the gate above.\n //\n // Absence is a silent no-op, not a refusal (FR-6) — the same choice `submitGate` two branches\n // above makes on its own absence, staying quiet when it is simply falsy too. The parallel stops\n // there: `submitGate`'s truthiness *is* the refusal, while `preflight`'s only means a check was\n // registered. Deliberate, not overlooked (fix pass, review S1): a holder that registered no check\n // (the two-argument overload) contributes nothing here, exactly as if this branch did not exist.\n // Logging on this branch would fire on the overwhelming majority of calls — it is every pre-T27\n // holder's default, and most of this hook's own test suite exercises it as the baseline — diluting\n // the signal this file's other console.error calls carry for genuine anomalies. Failing closed\n // instead would refuse every one of those callers, breaking `register`'s own optional third\n // argument (NFR-6, Decision 2). A caller that wants this protection must register a check.\n const preflight = path === null ? null : resolvePreflight(path);\n if (preflight) {\n const refusals = runPreflight(preflight);\n if (refusals.length > 0) {\n console.error('[payment.placeOrder] the registered pre-flight refused the submission', refusals[0]?.code);\n return { orderId: null, userErrors: refusals };\n }\n }\n\n // T170 (FR-2/FR-3): the three facts this function's own `catch` needs and cannot read from inside\n // its `try`. `handedOver` records whether the card had already been handed to the registered\n // submission when a throw happened — the record's own phase cannot answer that, since it reads\n // `opening` on both sides of the order-group write below. `settledOrderGroup` carries the one\n // field an `unresolved` record must keep for `resume()` to be able to act on it at all, since the\n // settled payload itself is scoped inside the `try`.\n //\n // `placedAttempt` is the terminal record the success tail below is about to write, captured\n // *before* that write (fix round, Critical finding). `handedOver` cannot stand in for it: it is\n // equally true for the whole span from the card POST onwards, including the window *after*\n // `gatewayCallback` has already resolved a real order — and in that window neither `refused` nor\n // `unresolved` is the truth, because the order is placed. The sequence is the only thing that\n // knows it got there, so it carries the fact rather than letting the `catch` infer a phase the\n // record cannot distinguish.\n //\n // T176 (FR-5, Decision 4): `outcome` is the result each branch past the card hand-over fixes\n // *before* its own record write, so the `catch` can return it. From that point a throw — by a\n // caller-supplied writer or by the tracker — may still need the record recovered, but it no longer\n // changes what the caller reads: a confirmed order stays confirmed, and a refusal stays that refusal.\n // It is still null for a throw raised before any branch fixed a result, which keeps T170's\n // NETWORK_ERROR.\n //\n // Locals, not fields on `PlaceOrderAttempt` (NFR-1): only this closure ever reads them, and\n // putting any of them on the exported record would re-open the question T167 closed — readers\n // second-guessing the phase (INV-4).\n let handedOver = false;\n let settledOrderGroup: string | null = null;\n let placedAttempt: PlaceOrderAttempt | null = null;\n let outcome: PlaceOrderResult | null = null;\n\n // T29 (FR-1/FR-2): a fresh attempt record, minted only once every synchronous refusal guard above\n // has passed — none of those guards ever creates one, so a pre-card refusal (Scenario 6) leaves\n // `attempt` untouched and a fresh full run stays legal next time. Not `useId()` (T28's own\n // `instanceKey`): that resets on every remount, and this identity must not. A plain write, not\n // `writeAttemptIfCurrent`: this is the genesis of the attempt, so there is nothing yet for a\n // concurrent completion to have superseded.\n const attemptId = generateAttemptId();\n setAttempt?.({ attemptId, phase: 'opening', orderGroup: null, orderId: null });\n try {\n // FR-1 (T56): raised here — after every synchronous refusal guard, immediately before the first\n // `await` — so a refusal that returns before this line never commits a `placing: true` frame.\n // `setUserErrors([])` and `setOrderId(null)` remain in `placeOrder` (the click handler), and\n // `settle`'s `setPlacing(false)` is untouched.\n setPlacing(true);\n\n const payload = await invokeStartTransaction(startTransaction);\n\n // Before the completeness check, so a server diagnosis is never replaced by a synthesized one —\n // T18 returns INVALID_TRANSACTION_DATA with every other field null for a transaction VTEX opened\n // with no merchant to pay, which a null-field check would otherwise swallow.\n if (payload.userErrors.length > 0) {\n // T29 (Decision 4, Scenario 6): nothing was paid, so the attempt records `refused` — a fresh\n // full sequence stays legal next time (`placeOrder()`'s own branch falls through to `run()` for\n // any phase other than opening/finalizing/settled/sent/unresolved, `refused` included). Fix\n // pass (Critical finding): this used to reset straight to `null`, which is indistinguishable\n // from \"no attempt ever started\" to a *different*, still-mounted or freshly-remounted instance —\n // `usePaymentMethodSelection`'s shared `placing` derivation reads this phase specifically to\n // release a lock a CTA that unmounted mid-flight can never release itself (FR-5, INV-5).\n // `writeAttemptIfCurrent`, not a plain write: this closure may be running after its own CTA\n // unmounted (NFR-3), so a newer completion for this same attempt must win instead.\n writeAttemptIfCurrent(setAttempt, attemptId, { attemptId, phase: 'refused', orderGroup: null, orderId: null });\n return { orderId: null, userErrors: payload.userErrors };\n }\n\n const settled = settleTransaction(payload);\n if (settled === null) {\n writeAttemptIfCurrent(setAttempt, attemptId, { attemptId, phase: 'refused', orderGroup: null, orderId: null });\n return { orderId: null, userErrors: [INVALID_TRANSACTION_ERROR] };\n }\n\n // T167: orderGroup is known and validated as soon as settleTransaction() returns non-null — well\n // before invokeSubmission() (the card POST, below) resolves. Writing it now closes that gap for the\n // whole 'opening' window instead of leaving it null until a terminal write. Data-completeness only:\n // placeOrder()'s phase branch and resumable (place-order.tsx) still derive only from `phase`, which\n // stays 'opening' here, so neither becomes actionable while this record sits in this phase.\n //\n // T170: kept for the recovery path too, which cannot reach `settled` from the `catch` below.\n settledOrderGroup = settled.orderGroup;\n writeAttemptIfCurrent(setAttempt, attemptId, {\n attemptId,\n phase: 'opening',\n orderGroup: settled.orderGroup,\n orderId: null,\n });\n\n const transaction: PaymentGatewayTransaction = {\n gatewayUrl: settled.gatewayUrl,\n transactionId: settled.transactionId,\n merchantName: settled.merchantName,\n orderGroup: settled.orderGroup,\n userProfileId: settled.userProfileId,\n paymentSystem: selectedMethod.id,\n groupName: selectedMethod.groupName,\n currencyCode: settled.value.currencyCode,\n valueInCents: settled.valueInCents,\n referenceValueInCents: settled.referenceValueInCents,\n installments: selectedInstallment?.count ?? 1,\n // A count: 1 installment is the full transaction value by definition. The read model's\n // selectedInstallment.value for a synthesized 1x tier is option.value (mappers.ts:597),\n // which can differ from the transaction's own value (Decision 8, spec:232) — e.g. an option\n // priced at 10000 on an order form whose value is 8997. Using settled.valueInCents for the\n // 1x case avoids charging option.value instead of the transaction value. For count > 1 the\n // tier value is upstream data, never synthesized, so the per-installment amount is correct.\n installmentsValueInCents:\n selectedInstallment && selectedInstallment.count !== 1\n ? toMinorUnits(selectedInstallment.value.amount)\n : settled.valueInCents,\n interestRate: selectedInstallment?.interestRate ?? 0,\n // Omitted entirely (never an explicit `undefined` key) when the caller passed none, matching\n // `callbackUrl`'s own absent-when-not-provided convention above (fix pass, review F1).\n ...(billingAddressDifferent != null ? { billingAddressDifferent } : {}),\n };\n\n // T170 (FR-3): raised on this side of the await, never the other. From the next line on, the\n // card has left the browser and nothing may recover this attempt as `refused` — which is the\n // only fact the `catch` below cannot re-derive, since the record reads `opening` either way.\n handedOver = true;\n const submissionErrors = await invokeSubmission(submit, transaction);\n // An unpaid transaction is never finalized.\n if (submissionErrors.length > 0) {\n // T29 (FR-2, Decision 5): the card's fate is unknown past this point. `gateway.ts` resolves one\n // opaque userError whether the gateway declined the card, the network failed, or the POST was\n // aborted (FR-6) — this hook cannot and must not try to tell those apart, so every one of them is\n // `unresolved`, never `refused`. Sticky for the payment root's lifetime (FR-4): the only call\n // `resume()` ever issues again is `gatewayCallback(orderGroup)`.\n outcome = { orderId: null, userErrors: submissionErrors };\n writeAttemptIfCurrent(setAttempt, attemptId, {\n attemptId,\n phase: 'unresolved',\n orderGroup: settled.orderGroup,\n orderId: null,\n });\n return outcome;\n }\n\n // T29: the card reached the gateway clean. Past this line the card may be charged — `resume()`\n // (below) is the only legal path back in (Decision 3). Fix pass (High finding): written as\n // `finalizing`, not `sent` — `sent` and `finalizing` are two distinct edges in the spec's own state\n // diagram (`sent --> finalizing: gatewayCallback issued`), but this call issues `gatewayCallback`\n // with no `await` in between, so nothing can ever legally observe the record at rest in `sent`\n // here: React batches same-tick writes, so whichever value is written *last*, before the next\n // `await`, is the only one any render (or a remount reading mid-flight) ever sees. The previous\n // version of this comment argued that fact meant the choice between the two values did not matter;\n // it does — `resumable` (place-order.tsx) treats `sent` as safe to resume, so writing it here left\n // `resumable` true for the entire span of this in-flight `gatewayCallback`, and a remounted or\n // sibling CTA could issue a second, concurrent one on the same order group (this file's own \"is\n // between the card POST and gatewayCallback\" test used to pin exactly that window). `finalizing` is\n // the value that keeps `resumable` false until this call actually settles — exactly what `resume()`\n // (below) already writes for its own, separately-triggered invocation of this same call.\n writeAttemptIfCurrent(setAttempt, attemptId, {\n attemptId,\n phase: 'finalizing',\n orderGroup: settled.orderGroup,\n orderId: null,\n });\n\n const callback = await invokeGatewayCallback(gatewayCallback, settled.orderGroup, attemptId);\n if (callback.userErrors.length > 0) {\n outcome = { orderId: null, userErrors: reconcileCallbackUserErrors(callback.userErrors) };\n writeAttemptIfCurrent(setAttempt, attemptId, {\n attemptId,\n phase: 'unresolved',\n orderGroup: settled.orderGroup,\n orderId: null,\n });\n return outcome;\n }\n\n // Built into a local before it is written, not inline (fix round, Critical finding): the write\n // below is itself a throw site — `setAttempt` is caller-supplied — and from the line above onwards\n // the order is placed. Handing the same value to the `catch` lets it re-assert the terminal truth\n // instead of downgrading a paid order to a resumable one.\n placedAttempt = {\n attemptId,\n phase: 'settled',\n orderGroup: settled.orderGroup,\n orderId: callback.orderId,\n };\n outcome = { orderId: callback.orderId, userErrors: [] };\n\n // GA4's transaction_id is the order a merchant reconciles against. A callback can succeed without\n // resolving one, and that is still a placed order, so the payment transaction id is the fallback.\n // `settled.value.amount` is typed `number` but arrives over the wire as a decimal string (the same\n // Decimal-scalar mismatch `toMinorUnits` coerces above), so GA4's numeric `value` needs the same\n // `Number()` coercion the rest of this package applies at the point of numeric use (e.g.\n // `sdk/cart/optimistic.ts`'s `moneyAdd`).\n //\n // T176 (Decision 5): dispatched before the terminal write, not after it. The event reports VTEX's\n // confirmation, which has already happened; the record is local bookkeeping about that fact, so a\n // writer that throws on it no longer loses the event. A tracker that throws lands in the `catch`\n // before that write, and the recovery write lands `placedAttempt` instead — never a second call.\n track?.({\n name: 'purchase',\n transactionId: callback.orderId ?? settled.transactionId,\n value: { amount: Number(settled.value.amount), currencyCode: settled.value.currencyCode },\n });\n\n writeAttemptIfCurrent(setAttempt, attemptId, placedAttempt);\n\n return outcome;\n } catch (error) {\n // T170 (FR-1): before this, `run()` had no `try`/`catch` of its own, so a throw anywhere past\n // the genesis write above — the synchronous descriptor build, or the caller-supplied `setAttempt`\n // that `writeAttemptIfCurrent` invokes — escaped every one of the outcome branches inside it.\n // `settleSequence`'s rejection handler (`placeOrder`, below) restores this hook's *local* state\n // only and never touches the shared record, so the record stayed latched at `opening` with no\n // sequence alive to move it: every later click hit `placeOrder()`'s own in-flight branch and\n // issued nothing, for the payment root's lifetime.\n //\n // The phase this settles on is not a judgement call, but it is a three-way one, and the first\n // version of this catch read it from `handedOver` alone (fix round, Critical finding). A throw\n // before the card was handed over provably never started the card POST, so nothing was paid and\n // `refused` is correct — a fresh full attempt stays legal (T29 Decision 4). A throw after it\n // with no order resolved means the card's fate is unknown, which is what `unresolved` means\n // (Decision 5) and what `resume()` exists for. But the `settled` write above is a throw site\n // too, and at that one site `gatewayCallback` has already returned a real order while `settled`\n // has not yet landed — so `writeAttemptIfCurrent`'s own `settled` guard does not refuse the\n // write either, and `unresolved` there made `resumable` (`place-order.tsx`) true for an order\n // that was already paid: one click on the re-enabled CTA routed through `resume()` into a second\n // `gatewayCallback` on the same order group, undeduplicated at every layer (no ownership check,\n // no idempotency key in `PaymentGatewayCallbackInput`, and VTEX's behaviour on a repeat carried\n // as unmeasured residual risk under PEXP-2049), doubling pressure on the account-wide\n // `vtex.checkout` breaker as well. Hence `placedAttempt` first: re-asserting the terminal record\n // the failed write was carrying is the only phase that is true there, and it can never be a\n // downgrade, because `writeAttemptIfCurrent` refuses it outright once `settled` has landed\n // (INV-6). Since T176 the `track?.()` call sits before that write, so for a tracker that throws\n // this recovery write is the one that lands `settled`.\n //\n // `writeAttemptIfCurrent`, never a plain write (INV-1): this closure may be running after its\n // own CTA unmounted (NFR-3), so a newer completion for this same attempt must win instead. That\n // write is itself wrapped, because it goes through the same caller-supplied `setAttempt` that may\n // be what threw in the first place (fix round, High finding): `writeAttemptIfCurrent` passes the\n // setter a *function* updater, so a writer that rejects that form — one that serializes,\n // schema-validates or persists what it is given — lands the plain genesis write and throws on\n // every write after it, this one included. Unguarded, that second throw escaped `run()` and left\n // this hook's contract (FR-6: resolve, never reject) resting on `settleSequence` catching it a\n // frame away. Nothing further can be tried once the writer itself is broken — a plain\n // `setAttempt` fallback is exactly the stale-closure clobber INV-1 forbids — so it is logged and\n // the result is returned either way: the `outcome` a branch already fixed (T176, FR-5), or\n // NETWORK_ERROR when the throw came before any branch fixed one. Only a sanitised error *name* is\n // logged, on both lines (FR-7): the closure that threw may hold the card, and a message, a stack,\n // or the raw writable `.name` could echo it. See `loggableErrorName()`.\n console.error('[payment.placeOrder] the place-order sequence threw', attemptId, loggableErrorName(error));\n try {\n writeAttemptIfCurrent(\n setAttempt,\n attemptId,\n placedAttempt ??\n (handedOver\n ? { attemptId, phase: 'unresolved', orderGroup: settledOrderGroup, orderId: null }\n : { attemptId, phase: 'refused', orderGroup: null, orderId: null }),\n );\n } catch (writeError) {\n console.error(\n '[payment.placeOrder] the place-order recovery write threw',\n attemptId,\n loggableErrorName(writeError),\n );\n }\n return outcome ?? { orderId: null, userErrors: [NETWORK_ERROR] };\n }\n }, [\n startTransaction,\n gatewayCallback,\n track,\n path,\n resolve,\n resolvePreflight,\n selectedMethod,\n selectedInstallment,\n billingAddressDifferent,\n submitGate,\n setAttempt,\n ]);\n\n const placeOrder = useCallback<UsePlaceOrder['placeOrder']>(() => {\n // A second click lands before T14's disabled state commits a render, and duplicating a\n // transaction is the worst outcome this surface has — so the guard is the in-flight promise\n // itself, not the `placing` flag. Both callers observe the one attempt that ran.\n if (inFlight.current !== null) return inFlight.current;\n\n // FR-1 (T56): `setPlacing(true)` moved into `run()`/`resume()`, immediately before their own first\n // `await`, so a synchronous refusal never commits a `placing: true` frame. `run()`'s and `resume()`'s\n // outcomes share this one settle wrapper (T29).\n const settleSequence = (sequence: Promise<PlaceOrderResult>): Promise<PlaceOrderResult> => {\n setUserErrors([]);\n setOrderId(null);\n\n const settle = (result: PlaceOrderResult): PlaceOrderResult => {\n inFlight.current = null;\n setPlacing(false);\n setUserErrors(result.userErrors);\n setOrderId(result.orderId);\n return result;\n };\n\n // `run()`/`resume()` resolve for every path this hook drives itself, but a collaborator outside\n // its control (a different $actions provider, or a mock resolving `undefined`) can still reject\n // one. Settling on both paths keeps `placing` from wedging true forever and surfaces an error, so\n // the CTA is clickable again either way. Spec correction (review F2): whether the *next* click\n // actually retries anything is decided by the attempt's phase, not by this settle —\n // `invokeStartTransaction`/`invokeGatewayCallback` each write a resumable phase before their own\n // await and normalize their result, so a throw on either leg lands on `refused`/`unresolved`\n // (T156). T170 closes the rest of that class at the source: `run()` now catches its own throws\n // and settles the record itself, so what is left is a collaborator-owned promise that never\n // settles at all — nothing has thrown, so there is nothing for either that catch or this settle\n // to act on, and bounding it needs a deadline nobody has set yet (T170's own OQ-1).\n const outcome = sequence.then(settle, () => settle({ orderId: null, userErrors: [NETWORK_ERROR] }));\n\n inFlight.current = outcome;\n return outcome;\n };\n\n // T29 (FR-2, FR-3): the CTA's next legal action is derived from the surviving attempt's own phase,\n // not always `run()`. `sent`/`unresolved` resume through a module-level function with no access at\n // all to `startTransaction` or the submission channel (Decision 3); `opening`/`finalizing` are\n // already running — possibly from a mount this closure has outlived (NFR-3) — and `settled` is\n // terminal (INV-6), so none of the three issues anything, independent of whatever a composing\n // CTA's own disabled state happens to do. Only the terminal one reads as a success, though: see\n // the in-flight arm's own comment below. `refused` falls through to a full run below like `null` —\n // nothing was paid, so a fresh attempt is legal (Decision 4). The `'sent'` check just below is\n // defensive-only: `run()` never leaves the record resting there today (it writes `finalizing`\n // directly, same tick — see that write site's own comment); kept so a future write path resting at\n // `sent` would still resume correctly instead of silently falling through to a full run.\n if (attempt) {\n if (attempt.phase === 'settled') {\n return Promise.resolve({ orderId: attempt.orderId, userErrors: [] });\n }\n // T170 (FR-5, Decision 4): split off the two in-flight phases, which used to share this arm and\n // so resolved the empty `userErrors` this hook's own contract defines as success\n // (`PlaceOrderResult`) — a reader that did not start the sequence was handed a success shape for\n // an order still in flight, and a CTA derived from it (`place-order.tsx`'s `succeeded`) rendered\n // \"placed\" for an order nobody had paid for. Settled through `settleSequence` like every other\n // outcome, so the refusal reaches this hook's own `userErrors` rather than only the resolved\n // value a composing CTA may never read. Still issues nothing, and still reads the phase alone\n // (INV-4): waiting is the correct behaviour while the card POST is genuinely open.\n if (attempt.phase === 'opening' || attempt.phase === 'finalizing') {\n return settleSequence(Promise.resolve({ orderId: attempt.orderId, userErrors: [PLACE_ORDER_IN_FLIGHT_ERROR] }));\n }\n if (attempt.phase === 'sent' || attempt.phase === 'unresolved') {\n return settleSequence(resume(gatewayCallback, setAttempt, setPlacing, attempt));\n }\n }\n\n return settleSequence(run());\n }, [run, attempt, gatewayCallback, setAttempt]);\n\n return useMemo(() => ({ placeOrder, placing, userErrors, orderId }), [placeOrder, placing, userErrors, orderId]);\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import "./operations.js";
|
|
|
3
3
|
import { TypedDocumentNode } from "@apollo/client";
|
|
4
4
|
//#region src/sdk/session/auth-operations.d.ts
|
|
5
5
|
/**
|
|
6
|
-
* Session auth mutation documents (
|
|
6
|
+
* Session auth mutation documents (docs/storefront-core/reference-free-particle-model.md § Write side — actions).
|
|
7
7
|
*
|
|
8
8
|
* Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive
|
|
9
9
|
* read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-operations.js","names":[],"sources":["../../../src/sdk/session/auth-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\nimport type { SessionEntity } from './operations.js';\n\n/**\n * Session auth mutation documents (
|
|
1
|
+
{"version":3,"file":"auth-operations.js","names":[],"sources":["../../../src/sdk/session/auth-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\nimport type { SessionEntity } from './operations.js';\n\n/**\n * Session auth mutation documents (docs/storefront-core/reference-free-particle-model.md § Write side — actions).\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive\n * read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see\n * `codegen.ts`): the `gql` tag alone is still plucked by `graphql-codegen`, which would duplicate\n * these hand-written types in `sdk/generated/`. The mutations stay hand-typed as\n * `TypedDocumentNode`s (Decision 3). Login/validate/logout share `SessionLoginPayloadFragment`,\n * a hand-written fragment selecting the full refreshed payload:\n * `session` with exactly `SessionFragment`'s field set, `cart` spreading the canonical codegen\n * `CartFragment` (interpolated as a document), and the full `clientProfile` / `clientPreferences`\n * slices. All payload entities are normalized Relay Nodes keyed on the orderFormId, so the response\n * write into the cache *is* the post-login refresh: `SessionRoot`'s reactive read flips with no\n * refetch and no imperative cache write (Decision 2).\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`\n * (`SessionError`); transport and top-level GraphQL failures are infrastructure, mapped by the\n * handlers in `use-session-actions.ts` to the one client-synthesized code, `NETWORK_ERROR`.\n */\n\n/** A typed login-attempt failure; NETWORK_ERROR is the one client-synthesized code (Decision 5). */\nexport type SessionUserError = Readonly<{ code: string; message: string }>;\n\nexport type SessionPasswordLoginPayload = Readonly<{ email: string; password: string }>;\n\nexport type SessionRequestAccessCodePayload = Readonly<{ email: string }>;\n\nexport type SessionValidateAccessCodePayload = Readonly<{\n email: string;\n accessCode: string;\n /** Opaque token from requestAccessCode, handed back unchanged (Decision 4). */\n authenticationToken: string;\n}>;\n\nexport type SessionAccessCodeRequestResult = Readonly<{\n authenticationToken: string | null;\n userErrors: readonly SessionUserError[];\n}>;\n\n/** The shopper's profile slice of the login payload; fields are null when unset. */\nexport type ClientProfileEntity = Readonly<{\n __typename: 'ClientProfile';\n id: string;\n email: string | null;\n firstName: string | null;\n lastName: string | null;\n phone: string | null;\n document: string | null;\n}>;\n\n/** The shopper's preference opt-ins slice of the login payload; fields are null when unset. */\nexport type ClientPreferencesEntity = Readonly<{\n __typename: 'ClientPreferences';\n id: string;\n optinNewsLetter: boolean | null;\n savePersonalData: boolean | null;\n}>;\n\n/** The full login/logout mutation payload, projected from the one refreshed order form. */\nexport type SessionLoginPayloadEntity = Readonly<{\n __typename: 'SessionLoginPayload';\n session: SessionEntity;\n cart: CartEntity;\n clientProfile: ClientProfileEntity;\n clientPreferences: ClientPreferencesEntity;\n userErrors: readonly SessionUserError[];\n}>;\n\nexport type SessionRequestAccessCodePayloadEntity = Readonly<{\n __typename: 'SessionRequestAccessCodePayload';\n authenticationToken: string | null;\n userErrors: readonly SessionUserError[];\n}>;\n\ntype SessionLoginWithPasswordData = Readonly<{ sessionLoginWithPassword: SessionLoginPayloadEntity }>;\ntype SessionRequestAccessCodeData = Readonly<{ sessionRequestAccessCode: SessionRequestAccessCodePayloadEntity }>;\ntype SessionValidateAccessCodeData = Readonly<{ sessionValidateAccessCode: SessionLoginPayloadEntity }>;\ntype SessionLogoutData = Readonly<{ sessionLogout: SessionLoginPayloadEntity }>;\n\n/** The shared full-refreshed-payload selection for login/validate/logout; embeds `CartFragment`. */\nconst SessionLoginPayloadFragment = gql`\n fragment SessionLoginPayloadFragment on SessionLoginPayload {\n __typename\n session {\n __typename\n id\n loggedIn\n canEditData\n isIdentified\n }\n cart {\n ...CartFragment\n }\n clientProfile {\n __typename\n id\n email\n firstName\n lastName\n phone\n document\n }\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n userErrors {\n code\n message\n }\n }\n ${CartFragment}\n`;\n\nexport const SESSION_LOGIN_WITH_PASSWORD: TypedDocumentNode<\n SessionLoginWithPasswordData,\n { input: SessionPasswordLoginPayload }\n> = gql`\n mutation SessionLoginWithPassword($input: SessionPasswordLoginInput!) {\n sessionLoginWithPassword(input: $input) {\n ...SessionLoginPayloadFragment\n }\n }\n ${SessionLoginPayloadFragment}\n`;\n\nexport const SESSION_REQUEST_ACCESS_CODE: TypedDocumentNode<\n SessionRequestAccessCodeData,\n { input: SessionRequestAccessCodePayload }\n> = gql`\n mutation SessionRequestAccessCode($input: SessionRequestAccessCodeInput!) {\n sessionRequestAccessCode(input: $input) {\n __typename\n authenticationToken\n userErrors {\n code\n message\n }\n }\n }\n`;\n\nexport const SESSION_VALIDATE_ACCESS_CODE: TypedDocumentNode<\n SessionValidateAccessCodeData,\n { input: SessionValidateAccessCodePayload }\n> = gql`\n mutation SessionValidateAccessCode($input: SessionValidateAccessCodeInput!) {\n sessionValidateAccessCode(input: $input) {\n ...SessionLoginPayloadFragment\n }\n }\n ${SessionLoginPayloadFragment}\n`;\n\nexport const SESSION_LOGOUT: TypedDocumentNode<SessionLogoutData, Record<string, never>> = gql`\n mutation SessionLogout {\n sessionLogout {\n ...SessionLoginPayloadFragment\n }\n }\n ${SessionLoginPayloadFragment}\n`;\n"],"mappings":";;;;AAqFA,MAAM,8BAA8B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiCnC,aAAa;;AAGjB,MAAa,8BAGT,GAAG;;;;;;IAMH,4BAA4B;;AAGhC,MAAa,8BAGT,GAAG;;;;;;;;;;;;AAaP,MAAa,+BAGT,GAAG;;;;;;IAMH,4BAA4B;;AAGhC,MAAa,iBAA8E,GAAG;;;;;;IAM1F,4BAA4B"}
|
|
@@ -3,7 +3,7 @@ import { SessionAccessCodeRequestResult, SessionPasswordLoginPayload, SessionReq
|
|
|
3
3
|
//#region src/sdk/session/use-session-actions.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* The `session` action namespace — the one sanctioned client write surface for authentication
|
|
6
|
-
* (
|
|
6
|
+
* (docs/storefront-core/reference-free-particle-model.md § Write side — actions, docs/storefront-core/adr-0010-actions-own-the-write-side.md).
|
|
7
7
|
*
|
|
8
8
|
* Every action is async/pessimistic (Decision 1): the handler awaits the mutation and only the
|
|
9
9
|
* server-confirmed payload changes the cache — authentication cannot be guessed client-side. The
|
|
@@ -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 * (
|
|
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":";;;;;;;AAwCA,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,KAAK;GAClF,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,KAAK;GAClF,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,KAAK;GACpF,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,KAAK;GAC5D,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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { graphql } from "../generated/gql.js";
|
|
3
|
+
import { getApolloContext } from "@apollo/client/react";
|
|
4
|
+
import { useCallback, useContext } from "react";
|
|
5
|
+
//#region src/sdk/session/use-session-revalidation.ts
|
|
6
|
+
/**
|
|
7
|
+
* The imperative re-read of the session, for the one case the reactive path cannot serve: a document
|
|
8
|
+
* the browser restored from its back-forward cache. A restored document resumes its heap without
|
|
9
|
+
* remounting, so `PageReactiveDataRoot` never re-runs its `cache-first` query and
|
|
10
|
+
* `useReactiveEntity` never issues a request — the session comes back exactly as stale as the frame
|
|
11
|
+
* around it.
|
|
12
|
+
*
|
|
13
|
+
* Selects the same field set as `SessionFragment`, so the response writes over the entity the layout
|
|
14
|
+
* query already references and every `SessionRoot` below it reacts.
|
|
15
|
+
*/
|
|
16
|
+
const ACCOUNT_SESSION_REVALIDATE = graphql(`
|
|
17
|
+
query AccountSessionRevalidate {
|
|
18
|
+
session {
|
|
19
|
+
...SessionFragment
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
`);
|
|
23
|
+
/**
|
|
24
|
+
* Discards the cached session and re-reads it from the network, resolving what it was able to find
|
|
25
|
+
* out. Only `failed` means the caller is holding an answer it has reason to distrust: the session was
|
|
26
|
+
* discarded and the query that should have replaced it rejected.
|
|
27
|
+
*
|
|
28
|
+
* **The discard comes first, and that ordering is the contract.** For the whole of the re-read there
|
|
29
|
+
* must be no session in the cache for anything to read: a re-read that merely overwrote would leave
|
|
30
|
+
* the restored `loggedIn` answering every consumer in the tree until the network replied. What has to
|
|
31
|
+
* go is the normalized entity, not the root field that points at it — the reactive read subscribes to
|
|
32
|
+
* `Session:<id>` through `useFragment`, so a root field cleared from under a live entity leaves that
|
|
33
|
+
* read complete and the consumer resolved.
|
|
34
|
+
*
|
|
35
|
+
* The consumers follow asynchronously, once the watched query has re-read: a component that must
|
|
36
|
+
* withhold something in the same frame the discard happens has to hold that state itself, and
|
|
37
|
+
* `AccountAccessGate` does.
|
|
38
|
+
*
|
|
39
|
+
* The client is resolved through Apollo's context rather than `useApolloClient()`, which throws when
|
|
40
|
+
* there is none: every session-aware story and test in this package renders `SessionRoot` bare, and a
|
|
41
|
+
* revalidation that cannot run is not a reason for a component to fail to render.
|
|
42
|
+
*/
|
|
43
|
+
function useSessionRevalidation() {
|
|
44
|
+
const { client } = useContext(getApolloContext());
|
|
45
|
+
return useCallback(async () => {
|
|
46
|
+
if (!client) return "unavailable";
|
|
47
|
+
try {
|
|
48
|
+
const cached = client.cache.readQuery({ query: ACCOUNT_SESSION_REVALIDATE });
|
|
49
|
+
const entity = cached?.session ? client.cache.identify(cached.session) : void 0;
|
|
50
|
+
if (entity) client.cache.evict({ id: entity });
|
|
51
|
+
await client.query({
|
|
52
|
+
query: ACCOUNT_SESSION_REVALIDATE,
|
|
53
|
+
fetchPolicy: "network-only"
|
|
54
|
+
});
|
|
55
|
+
return "revalidated";
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error("[useSessionRevalidation] session re-read failed", error);
|
|
58
|
+
return "failed";
|
|
59
|
+
}
|
|
60
|
+
}, [client]);
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { ACCOUNT_SESSION_REVALIDATE, useSessionRevalidation };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=use-session-revalidation.js.map
|
|
@@ -0,0 +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":";;;;;;;;;;;;;;;AAgBA,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,KAAK;GACtE,OAAO;EACT;CACF,GAAG,CAAC,MAAM,CAAC;AACb"}
|
|
@@ -2,7 +2,7 @@ import "../cart/operations.js";
|
|
|
2
2
|
import { TypedDocumentNode } from "@apollo/client";
|
|
3
3
|
//#region src/sdk/shipping/option-select-operations.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* `shippingOptionSelect` mutation document (
|
|
5
|
+
* `shippingOptionSelect` mutation document (docs/storefront-core/reference-free-particle-model.md § The cart write contract).
|
|
6
6
|
*
|
|
7
7
|
* Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive
|
|
8
8
|
* read path (`shipping/operations.ts`) — and explicitly excluded from the codegen `documents` glob
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"option-select-operations.js","names":[],"sources":["../../../src/sdk/shipping/option-select-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * `shippingOptionSelect` mutation document (
|
|
1
|
+
{"version":3,"file":"option-select-operations.js","names":[],"sources":["../../../src/sdk/shipping/option-select-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * `shippingOptionSelect` mutation document (docs/storefront-core/reference-free-particle-model.md § The cart write contract).\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive\n * read path (`shipping/operations.ts`) — and explicitly excluded from the codegen `documents` glob\n * (see `codegen.ts`): the `gql` tag alone is still plucked by `graphql-codegen`, which would\n * duplicate these hand-written types in `sdk/generated/`. Mirrors the `session`/`identity`\n * action-mutation convention (hand-typed `TypedDocumentNode`s).\n *\n * Selects `cart { ...CartFragment }` alongside `shipping` so the normalized Apollo cache updates\n * the cart totalizer in the same round trip (T1 epic note). Both `shipping` and its nested\n * `options` select `id`/`__typename` so `InMemoryCache` normalizes them as the same entities the\n * reactive `DeliveryOptionsData` fragment reads — required for the mutation response to flow back\n * into the reactive UI with no refetch (Decision 1/Decision 5).\n */\n\nexport type ShippingOptionSelectUserError = Readonly<{ code: string; message: string }>;\n\nexport type ShippingOptionSelectInput = Readonly<{ optionId: string }>;\n\ntype ShippingOptionEntity = Readonly<{\n __typename?: 'ShippingOption';\n id: string;\n name: string;\n channel: string;\n shippingEstimate: Readonly<{ __typename?: 'ShippingEstimate'; value: number; unit: string }>;\n price: Readonly<{ __typename?: 'Money'; amount: number; currencyCode: string }>;\n listPrice: Readonly<{ __typename?: 'Money'; amount: number; currencyCode: string }>;\n}>;\n\ntype ShippingEntity = Readonly<{\n __typename?: 'Shipping';\n id: string;\n options: readonly ShippingOptionEntity[];\n selectedOptionId: string | null;\n}>;\n\ntype ShippingOptionSelectPayloadEntity = Readonly<{\n __typename?: 'ShippingOptionSelectPayload';\n shipping: ShippingEntity | null;\n cart: CartEntity | null;\n userErrors: readonly ShippingOptionSelectUserError[];\n}>;\n\ntype ShippingOptionSelectMutation = Readonly<{ shippingOptionSelect: ShippingOptionSelectPayloadEntity }>;\n\ntype ShippingOptionSelectMutationVariables = Readonly<{ input: ShippingOptionSelectInput }>;\n\nexport const SHIPPING_OPTION_SELECT: TypedDocumentNode<\n ShippingOptionSelectMutation,\n ShippingOptionSelectMutationVariables\n> = gql`\n mutation ShippingOptionSelect($input: ShippingOptionSelectInput!) {\n shippingOptionSelect(input: $input) {\n __typename\n shipping {\n __typename\n id\n options {\n __typename\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${CartFragment}\n`;\n"],"mappings":";;;AAoDA,MAAa,yBAGT,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoCH,aAAa"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/sdk/shipping/request-timeout.ts
|
|
2
2
|
/**
|
|
3
|
-
* Bounds the default shipping-simulation SDK request (
|
|
3
|
+
* Bounds the default shipping-simulation SDK request (docs/storefront-core/reference-free-particle-model.md § Read side — data).
|
|
4
4
|
*
|
|
5
5
|
* The default `useShippingSimulation` / `useCartShippingSimulation` callbacks run an imperative
|
|
6
6
|
* `client.query` with no time bound, so a logistics transport that never settles leaves the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-timeout.js","names":[],"sources":["../../../src/sdk/shipping/request-timeout.ts"],"sourcesContent":["/**\n * Bounds the default shipping-simulation SDK request (
|
|
1
|
+
{"version":3,"file":"request-timeout.js","names":[],"sources":["../../../src/sdk/shipping/request-timeout.ts"],"sourcesContent":["/**\n * Bounds the default shipping-simulation SDK request (docs/storefront-core/reference-free-particle-model.md § Read side — data).\n *\n * The default `useShippingSimulation` / `useCartShippingSimulation` callbacks run an imperative\n * `client.query` with no time bound, so a logistics transport that never settles leaves the\n * simulator Root stuck on `loading` forever. `withRequestTimeout` races the request against a finite\n * timer: when the timer wins it aborts the in-flight request (via the `AbortSignal` threaded into\n * `context.fetchOptions`) and rejects, which each hook's existing `catch` collapses to the same\n * `UNKNOWN` userError as any other failure — so the timeout reuses the established error path and the\n * Root leaves `loading` for `error`.\n *\n * The abort is best-effort: it cancels the network request only when the Apollo link chain honors the\n * signal (`HttpLink` does; `MockLink` in tests does not). Settlement never depends on it — the timer\n * race guarantees the returned promise resolves or rejects within `timeoutMs` regardless.\n */\n\n// A generous safety net: well above any healthy round-trip and above the resolver's own upstream\n// budget, so it fires only on a genuine hang, not on a merely slow-but-healthy response.\nexport const SHIPPING_SIMULATION_TIMEOUT_MS = 10_000;\n\nexport class ShippingSimulationTimeoutError extends Error {\n constructor() {\n super('Shipping simulation request timed out.');\n this.name = 'ShippingSimulationTimeoutError';\n }\n}\n\nexport function withRequestTimeout<T>(\n run: (signal: AbortSignal) => Promise<T>,\n // Defaults to the shared constant; no runtime caller overrides it today. Kept as the injection\n // point for a future per-account configurable timeout, once a per-account config source exists.\n timeoutMs: number = SHIPPING_SIMULATION_TIMEOUT_MS,\n): Promise<T> {\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new ShippingSimulationTimeoutError());\n }, timeoutMs);\n });\n\n // `run` is invoked inside an async wrapper so a synchronous throw becomes a rejection the race can\n // observe. Called bare, it would escape before `finally` is attached, leaving the timer armed and\n // the timeout's own rejection unhandled.\n const request = (async () => run(controller.signal))();\n\n return Promise.race([request, timeout]).finally(() => {\n clearTimeout(timer);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,iCAAiC;AAE9C,IAAa,iCAAb,cAAoD,MAAM;CACxD,cAAc;EACZ,MAAM,wCAAwC;EAC9C,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,mBACd,KAGA,YAAoB,gCACR;CACZ,MAAM,aAAa,IAAI,gBAAgB;CACvC,IAAI;CAEJ,MAAM,UAAU,IAAI,SAAgB,GAAG,WAAW;EAChD,QAAQ,iBAAiB;GACvB,WAAW,MAAM;GACjB,OAAO,IAAI,+BAA+B,CAAC;EAC7C,GAAG,SAAS;CACd,CAAC;CAKD,MAAM,WAAW,YAAY,IAAI,WAAW,MAAM,EAAA,CAAG;CAErD,OAAO,QAAQ,KAAK,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,cAAc;EACpD,aAAa,KAAK;CACpB,CAAC;AACH"}
|
|
@@ -2,7 +2,7 @@ import "../cart/operations.js";
|
|
|
2
2
|
import { TypedDocumentNode } from "@apollo/client";
|
|
3
3
|
//#region src/sdk/shipping/shipping-operations.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Shipping address mutation documents (
|
|
5
|
+
* Shipping address mutation documents (docs/storefront-core/reference-free-particle-model.md § The cart write contract).
|
|
6
6
|
*
|
|
7
7
|
* Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive
|
|
8
8
|
* read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shipping-operations.js","names":[],"sources":["../../../src/sdk/shipping/shipping-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Shipping address mutation documents (
|
|
1
|
+
{"version":3,"file":"shipping-operations.js","names":[],"sources":["../../../src/sdk/shipping/shipping-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Shipping address mutation documents (docs/storefront-core/reference-free-particle-model.md § The cart write contract).\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive\n * read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see\n * `codegen.ts`): the `gql` tag alone is still plucked by `graphql-codegen`, which would duplicate\n * these hand-written types in `sdk/generated/`. The mutation stays hand-typed as a\n * `TypedDocumentNode` (Decision 3 in the spec). The payload projects the full refreshed `shipping`\n * and `cart` state, so the response write into the cache *is* the post-update refresh: `Shipping`'s\n * reactive read flips with no refetch and no imperative cache write.\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`\n * (`ShippingAddressUpdateError`); transport and top-level GraphQL failures are infrastructure,\n * mapped by the handlers in `use-shipping-actions.ts` to the one client-synthesized code,\n * `NETWORK_USER_ERROR`.\n */\n\n/** A typed address-update failure; NETWORK_USER_ERROR is the one client-synthesized code. */\nexport type ShippingAddressUpdateErrorEntity = Readonly<{ code: string; message: string }>;\n\n/**\n * The one client-synthesized error code, carried by the userError that `setAddress` *resolves*\n * (never throws) when the mutation fails at the transport/top-level-GraphQL layer. Consumers use\n * it to route the resolved synthetic failure to the generic upstream error state (Decision 5),\n * distinct from the domain `userErrors` codes that render inline.\n */\nexport const SHIPPING_NETWORK_ERROR_CODE = 'NETWORK_ERROR';\n\nexport type ShippingAddressInput = Readonly<{\n savedAddressId?: string;\n recipientName: string;\n postalCode: string;\n country: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n state?: string;\n}>;\n\n/** The full shippingAddressUpdate mutation payload. */\nexport type ShippingAddressUpdatePayloadEntity = Readonly<{\n __typename: 'ShippingAddressUpdatePayload';\n shipping: {\n __typename: 'Shipping';\n id: string;\n address: {\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n } | null;\n savedAddresses: ReadonlyArray<{\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n }>;\n options: ReadonlyArray<{\n __typename: 'ShippingOption';\n id: string;\n name: string;\n channel: string;\n shippingEstimate: { __typename: 'ShippingEstimate'; value: number; unit: string };\n price: { __typename: 'Money'; amount: number; currencyCode: string };\n listPrice: { __typename: 'Money'; amount: number; currencyCode: string };\n }>;\n selectedOptionId?: string | null;\n } | null;\n cart: CartEntity;\n userErrors: readonly ShippingAddressUpdateErrorEntity[];\n}>;\n\ntype ShippingAddressUpdateData = Readonly<{ shippingAddressUpdate: ShippingAddressUpdatePayloadEntity }>;\n\nexport const SHIPPING_ADDRESS_UPDATE: TypedDocumentNode<ShippingAddressUpdateData, { input: ShippingAddressInput }> =\n gql`\n mutation ShippingAddressUpdate($input: ShippingAddressUpdateInput!) {\n shippingAddressUpdate(input: $input) {\n shipping {\n __typename\n id\n address {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n savedAddresses {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n options {\n __typename\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${CartFragment}\n`;\n"],"mappings":";;;;;;;;;AA8BA,MAAa,8BAA8B;AAgE3C,MAAa,0BACX,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6DD,aAAa"}
|
|
@@ -4,9 +4,9 @@ import { ShippingAddressInput, ShippingAddressUpdateErrorEntity } from "./shippi
|
|
|
4
4
|
//#region src/sdk/shipping/use-shipping-actions.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* The `shipping` action namespace — the sanctioned client write surface against the VTEX orderForm
|
|
7
|
-
* shippingData: delivery-address updates (
|
|
7
|
+
* shippingData: delivery-address updates (docs/storefront-core/reference-free-particle-model.md § The cart write contract;
|
|
8
8
|
* docs/storefront-core/adr-0010-actions-own-the-write-side.md) and cart-scoped delivery-option
|
|
9
|
-
* selection (
|
|
9
|
+
* selection (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Per Decision 4 the two tasks share this one
|
|
10
10
|
* namespace — T2 (`setAddress`) merged first and owns the registration, T3 extends it with
|
|
11
11
|
* `selectOption` here.
|
|
12
12
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { defineActions } from "../../core/dist/actions/registry.js";
|
|
3
3
|
import "../../core/dist/index.js";
|
|
4
|
-
import { SHIPPING_ADDRESS_UPDATE, SHIPPING_NETWORK_ERROR_CODE } from "./shipping-operations.js";
|
|
5
4
|
import { SHIPPING_OPTION_SELECT } from "./option-select-operations.js";
|
|
5
|
+
import { SHIPPING_ADDRESS_UPDATE, SHIPPING_NETWORK_ERROR_CODE } from "./shipping-operations.js";
|
|
6
6
|
import { useMutation } from "@apollo/client/react";
|
|
7
7
|
import { useCallback, useMemo } from "react";
|
|
8
8
|
//#region src/sdk/shipping/use-shipping-actions.ts
|
|
@@ -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 (
|
|
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":";;;;;;;;AAmCA,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,KAAK;GACzE,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,KAAK;GAC1E,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"}
|
package/dist/sdk/state/cart.d.ts
CHANGED
|
@@ -3,8 +3,7 @@ export declare const orderFormIdVar: import("@apollo/client").ReactiveVar<string
|
|
|
3
3
|
/**
|
|
4
4
|
* Latest `userErrors` from any cart write, surfaced context-free. The cart action hook publishes
|
|
5
5
|
* here on every call (cleared synchronously at the start of the next call) and `CartError` reads it
|
|
6
|
-
* via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (
|
|
7
|
-
* FR-9). Stays in client state — never a query variable or request header.
|
|
6
|
+
* via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Stays in client state — never a query variable or request header.
|
|
8
7
|
*/
|
|
9
8
|
export declare const cartUserErrorsVar: import("@apollo/client").ReactiveVar<readonly Readonly<{
|
|
10
9
|
code: string;
|
|
@@ -15,7 +14,7 @@ export declare const cartUserErrorsVar: import("@apollo/client").ReactiveVar<rea
|
|
|
15
14
|
* error and network-catch branches leave it untouched. `CartOpenOnAdd` and `CartRedirectOnAdd` key
|
|
16
15
|
* a `useEffect` on it via `useReactiveVar`, so every successful add re-fires their behavior even when
|
|
17
16
|
* the drawer is already open or was just closed — a boolean would not re-fire on an unchanged value
|
|
18
|
-
* (
|
|
17
|
+
* (docs/storefront-core/reference-free-particle-model.md § Read side — state). Client state only — never a query variable
|
|
19
18
|
* or request header.
|
|
20
19
|
*/
|
|
21
20
|
export declare const cartLastAddVar: import("@apollo/client").ReactiveVar<number>;
|
|
@@ -30,7 +29,7 @@ export declare const miniCartOpenVar: import("@apollo/client").ReactiveVar<boole
|
|
|
30
29
|
/**
|
|
31
30
|
* Latest `userErrors` from a coupon write (`applyCoupon` / `removeCoupon`), surfaced context-free.
|
|
32
31
|
* A dedicated channel mirroring `cartUserErrorsVar` so coupon feedback sits next to the coupon form
|
|
33
|
-
* and never collides with item-write errors (
|
|
32
|
+
* and never collides with item-write errors (docs/storefront-core/reference-free-particle-model.md § The cart write contract). The coupon
|
|
34
33
|
* actions publish here on every call (cleared at the start of the next call) and `CartCouponError`
|
|
35
34
|
* reads it via `useReactiveVar`. Stays in client state — never a query variable or request header.
|
|
36
35
|
*/
|