@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.
Files changed (306) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/actions.json +181 -0
  3. package/dist/catalog.json +1595 -481
  4. package/dist/client.d.ts +2 -1
  5. package/dist/client.js +2 -1
  6. package/dist/components.d.ts +31 -7
  7. package/dist/components.js +35 -13
  8. package/dist/content-types.json +73 -0
  9. package/dist/docs/access-code-sign-in.md +1 -1
  10. package/dist/docs/account-access-gate.md +153 -0
  11. package/dist/docs/account-entry-point.md +1 -2
  12. package/dist/docs/account-menu.md +164 -0
  13. package/dist/docs/address-summary.md +24 -3
  14. package/dist/docs/alert-dialog.md +204 -0
  15. package/dist/docs/billing-address.md +284 -0
  16. package/dist/docs/buy-button.md +1 -1
  17. package/dist/docs/card-entry.md +250 -0
  18. package/dist/docs/cardholder-document.md +142 -0
  19. package/dist/docs/cart.md +1 -1
  20. package/dist/docs/client-preferences-fieldset.md +148 -0
  21. package/dist/docs/client-preferences.md +2 -1
  22. package/dist/docs/client-profile-fieldset.md +184 -0
  23. package/dist/docs/client-profile.md +1 -1
  24. package/dist/docs/document-field.md +58 -4
  25. package/dist/docs/field.md +317 -0
  26. package/dist/docs/form.md +307 -0
  27. package/dist/docs/identity-edit.md +6 -6
  28. package/dist/docs/identity-summary.md +5 -5
  29. package/dist/docs/installments.md +248 -0
  30. package/dist/docs/my-account-profile.md +1 -0
  31. package/dist/docs/order-placed-payment-summary.md +138 -0
  32. package/dist/docs/payment-method-badges.md +232 -0
  33. package/dist/docs/payment-methods.md +1 -0
  34. package/dist/docs/payment.md +218 -0
  35. package/dist/docs/phone-field.md +58 -4
  36. package/dist/docs/place-order.md +157 -0
  37. package/dist/docs/save-card.md +186 -0
  38. package/dist/docs/saved-cards.md +218 -0
  39. package/dist/docs/select.md +465 -0
  40. package/dist/docs/session.md +1 -1
  41. package/dist/docs/shipping-address.md +110 -258
  42. package/dist/docs/sign-in-redirect.md +1 -1
  43. package/dist/index.d.ts +4 -1
  44. package/dist/internal/client.d.ts +3 -1
  45. package/dist/internal/client.js +3 -1
  46. package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
  47. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  48. package/dist/matter/account-access-gate/account-access-gate.d.ts +86 -0
  49. package/dist/matter/account-access-gate/account-access-gate.js +283 -0
  50. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -0
  51. package/dist/matter/account-access-gate/sign-out-intent.d.ts +17 -0
  52. package/dist/matter/account-access-gate/sign-out-intent.js +62 -0
  53. package/dist/matter/account-access-gate/sign-out-intent.js.map +1 -0
  54. package/dist/matter/account-entry-point/account-entry-point.js +2 -2
  55. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  56. package/dist/matter/account-menu/account-menu.d.ts +88 -0
  57. package/dist/matter/account-menu/account-menu.js +246 -0
  58. package/dist/matter/account-menu/account-menu.js.map +1 -0
  59. package/dist/matter/billing-address/billing-address.d.ts +165 -0
  60. package/dist/matter/billing-address/billing-address.js +408 -0
  61. package/dist/matter/billing-address/billing-address.js.map +1 -0
  62. package/dist/matter/card-entry/card-capture.d.ts +25 -0
  63. package/dist/matter/card-entry/card-capture.js +25 -0
  64. package/dist/matter/card-entry/card-capture.js.map +1 -0
  65. package/dist/matter/card-entry/card-entry.d.ts +120 -0
  66. package/dist/matter/card-entry/card-entry.js +832 -0
  67. package/dist/matter/card-entry/card-entry.js.map +1 -0
  68. package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
  69. package/dist/matter/cardholder-document/cardholder-document.js +70 -0
  70. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
  71. package/dist/matter/cart/cart.d.ts +1 -1
  72. package/dist/matter/cart/cart.js +2 -2
  73. package/dist/matter/cart/cart.js.map +1 -1
  74. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
  75. package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
  76. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
  77. package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
  78. package/dist/matter/client-preferences/client-preferences.js +6 -6
  79. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  80. package/dist/matter/client-profile/client-profile.d.ts +4 -6
  81. package/dist/matter/client-profile/client-profile.js +9 -6
  82. package/dist/matter/client-profile/client-profile.js.map +1 -1
  83. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
  84. package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
  85. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
  86. package/dist/matter/delivery-options/delivery-options.js.map +1 -1
  87. package/dist/matter/identity-edit/identity-edit.js +2 -2
  88. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  89. package/dist/matter/identity-summary/identity-summary.js +2 -2
  90. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  91. package/dist/matter/installments/installments-select.d.ts +42 -0
  92. package/dist/matter/installments/installments-select.js +167 -0
  93. package/dist/matter/installments/installments-select.js.map +1 -0
  94. package/dist/matter/installments/installments.d.ts +58 -0
  95. package/dist/matter/installments/installments.js +176 -0
  96. package/dist/matter/installments/installments.js.map +1 -0
  97. package/dist/matter/installments/use-installments-selection.d.ts +29 -0
  98. package/dist/matter/installments/use-installments-selection.js +95 -0
  99. package/dist/matter/installments/use-installments-selection.js.map +1 -0
  100. package/dist/matter/my-account-profile/my-account-profile.js +5 -5
  101. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  102. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
  103. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
  104. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
  105. package/dist/matter/payment/payment-card-capture.d.ts +19 -0
  106. package/dist/matter/payment/payment-card-capture.js +129 -0
  107. package/dist/matter/payment/payment-card-capture.js.map +1 -0
  108. package/dist/matter/payment/payment-controller.d.ts +24 -0
  109. package/dist/matter/payment/payment-controller.js +107 -0
  110. package/dist/matter/payment/payment-controller.js.map +1 -0
  111. package/dist/matter/payment/payment-method-badges.d.ts +57 -0
  112. package/dist/matter/payment/payment-method-badges.js +192 -0
  113. package/dist/matter/payment/payment-method-badges.js.map +1 -0
  114. package/dist/matter/payment/payment.d.ts +89 -0
  115. package/dist/matter/payment/payment.js +263 -0
  116. package/dist/matter/payment/payment.js.map +1 -0
  117. package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
  118. package/dist/matter/payment/use-payment-method-selection.js +458 -0
  119. package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
  120. package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
  121. package/dist/matter/payment/use-payment-submit-gate.js +144 -0
  122. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
  123. package/dist/matter/place-order/place-order.d.ts +74 -0
  124. package/dist/matter/place-order/place-order.js +379 -0
  125. package/dist/matter/place-order/place-order.js.map +1 -0
  126. package/dist/matter/product-list/product-list.d.ts +1 -0
  127. package/dist/matter/product-list/product-list.js.map +1 -1
  128. package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
  129. package/dist/matter/product-shelf/product-shelf.js +2 -0
  130. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  131. package/dist/matter/region/region.js +1 -1
  132. package/dist/matter/region/region.js.map +1 -1
  133. package/dist/matter/save-card/save-card.d.ts +49 -0
  134. package/dist/matter/save-card/save-card.js +188 -0
  135. package/dist/matter/save-card/save-card.js.map +1 -0
  136. package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
  137. package/dist/matter/saved-cards/saved-cards.js +387 -0
  138. package/dist/matter/saved-cards/saved-cards.js.map +1 -0
  139. package/dist/matter/shipping-address/country-descriptors.js +20 -10
  140. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  141. package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
  142. package/dist/matter/shipping-address/shipping-address.js +481 -792
  143. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  144. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  145. package/dist/matter/variant-selector/variant-selector.js +1 -1
  146. package/dist/particles/address-summary/address-summary.d.ts +24 -0
  147. package/dist/particles/address-summary/address-summary.js +83 -2
  148. package/dist/particles/address-summary/address-summary.js.map +1 -1
  149. package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
  150. package/dist/particles/alert-dialog/alert-dialog.js +187 -0
  151. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
  152. package/dist/particles/checkbox/checkbox.d.ts +7 -3
  153. package/dist/particles/checkbox/checkbox.js +4 -1
  154. package/dist/particles/checkbox/checkbox.js.map +1 -1
  155. package/dist/particles/document-field/document-field.d.ts +48 -5
  156. package/dist/particles/document-field/document-field.js +189 -32
  157. package/dist/particles/document-field/document-field.js.map +1 -1
  158. package/dist/particles/field/bound-field-registry.js +52 -0
  159. package/dist/particles/field/bound-field-registry.js.map +1 -0
  160. package/dist/particles/field/field.d.ts +116 -0
  161. package/dist/particles/field/field.js +497 -6
  162. package/dist/particles/field/field.js.map +1 -1
  163. package/dist/particles/fieldset/fieldset.js +2 -2
  164. package/dist/particles/fieldset/fieldset.js.map +1 -1
  165. package/dist/particles/footer-social/footer-social.js +1 -1
  166. package/dist/particles/form/form.d.ts +104 -0
  167. package/dist/particles/form/form.js +485 -0
  168. package/dist/particles/form/form.js.map +1 -0
  169. package/dist/particles/incentives/incentives.js +1 -1
  170. package/dist/particles/phone-field/phone-field.d.ts +38 -10
  171. package/dist/particles/phone-field/phone-field.js +183 -39
  172. package/dist/particles/phone-field/phone-field.js.map +1 -1
  173. package/dist/particles/postal-code-field/postal-code-field.js +2 -2
  174. package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
  175. package/dist/particles/select/field-select.d.ts +43 -0
  176. package/dist/particles/select/field-select.js +150 -0
  177. package/dist/particles/select/field-select.js.map +1 -0
  178. package/dist/particles/select/select.d.ts +2 -0
  179. package/dist/particles/select/select.js.map +1 -1
  180. package/dist/particles/shared/compose-refs.js +21 -0
  181. package/dist/particles/shared/compose-refs.js.map +1 -0
  182. package/dist/schema.graphql +701 -2
  183. package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
  184. package/dist/sdk/actions/analytics-action-provider.js +19 -0
  185. package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
  186. package/dist/sdk/actions/cart-action-provider.d.ts +1 -1
  187. package/dist/sdk/actions/cart-action-provider.js +1 -1
  188. package/dist/sdk/actions/cart-action-provider.js.map +1 -1
  189. package/dist/sdk/actions/index.d.ts +3 -1
  190. package/dist/sdk/actions/index.js +3 -1
  191. package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
  192. package/dist/sdk/actions/payment-action-provider.js +26 -0
  193. package/dist/sdk/actions/payment-action-provider.js.map +1 -0
  194. package/dist/sdk/actions/session-action-provider.d.ts +1 -1
  195. package/dist/sdk/actions/session-action-provider.js +1 -1
  196. package/dist/sdk/actions/session-action-provider.js.map +1 -1
  197. package/dist/sdk/actions/shipping-action-provider.d.ts +1 -1
  198. package/dist/sdk/actions/shipping-action-provider.js +1 -1
  199. package/dist/sdk/actions/shipping-action-provider.js.map +1 -1
  200. package/dist/sdk/actions/types.d.ts +6 -2
  201. package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
  202. package/dist/sdk/analytics/analytics-destination.js +90 -0
  203. package/dist/sdk/analytics/analytics-destination.js.map +1 -0
  204. package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
  205. package/dist/sdk/analytics/use-analytics-actions.js +108 -0
  206. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
  207. package/dist/sdk/cache/storefront-cache.js +1 -1
  208. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  209. package/dist/sdk/cart/operations.d.ts +4 -4
  210. package/dist/sdk/cart/operations.js +1 -1
  211. package/dist/sdk/cart/operations.js.map +1 -1
  212. package/dist/sdk/cart/optimistic.js +1 -1
  213. package/dist/sdk/cart/optimistic.js.map +1 -1
  214. package/dist/sdk/cart/use-cart-actions.d.ts +1 -1
  215. package/dist/sdk/cart/use-cart-actions.js +4 -4
  216. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  217. package/dist/sdk/cart/use-cart-validate-on-open.js +1 -1
  218. package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
  219. package/dist/sdk/cart/write-gate.js +1 -1
  220. package/dist/sdk/cart/write-gate.js.map +1 -1
  221. package/dist/sdk/data/entity-resolution-context.js +31 -0
  222. package/dist/sdk/data/entity-resolution-context.js.map +1 -0
  223. package/dist/sdk/data/entity-subscriber.js +18 -8
  224. package/dist/sdk/data/entity-subscriber.js.map +1 -1
  225. package/dist/sdk/data/index.js +1 -0
  226. package/dist/sdk/data/page-reactive-data-root.d.ts +38 -2
  227. package/dist/sdk/data/page-reactive-data-root.js +4 -2
  228. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  229. package/dist/sdk/data/reactive-data-provider.d.ts +1 -1
  230. package/dist/sdk/data/reactive-data-provider.js +8 -4
  231. package/dist/sdk/data/reactive-data-provider.js.map +1 -1
  232. package/dist/sdk/data/reactive-list-item-data-provider.d.ts +1 -1
  233. package/dist/sdk/data/reactive-list-item-data-provider.js +13 -5
  234. package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
  235. package/dist/sdk/data/use-reactive-data-settled.js +39 -0
  236. package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
  237. package/dist/sdk/data/use-reactive-entity.js +6 -2
  238. package/dist/sdk/data/use-reactive-entity.js.map +1 -1
  239. package/dist/sdk/generated/fragment-types.js +2 -0
  240. package/dist/sdk/generated/fragment-types.js.map +1 -1
  241. package/dist/sdk/generated/gql.js +2 -1
  242. package/dist/sdk/generated/gql.js.map +1 -1
  243. package/dist/sdk/generated/graphql.js +85 -1
  244. package/dist/sdk/generated/graphql.js.map +1 -1
  245. package/dist/sdk/i18n/messages/en-US.js +3 -0
  246. package/dist/sdk/i18n/messages/en-US.json +3 -0
  247. package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
  248. package/dist/sdk/i18n/messages/es-ES.js +3 -0
  249. package/dist/sdk/i18n/messages/es-ES.json +3 -0
  250. package/dist/sdk/i18n/messages/pt-BR.js +3 -0
  251. package/dist/sdk/i18n/messages/pt-BR.json +3 -0
  252. package/dist/sdk/identity/operations.js.map +1 -1
  253. package/dist/sdk/identity/use-identity-actions.d.ts +1 -1
  254. package/dist/sdk/identity/use-identity-actions.js +3 -2
  255. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  256. package/dist/sdk/payment/gateway-origin.js +35 -0
  257. package/dist/sdk/payment/gateway-origin.js.map +1 -0
  258. package/dist/sdk/payment/gateway.d.ts +85 -0
  259. package/dist/sdk/payment/gateway.js +183 -0
  260. package/dist/sdk/payment/gateway.js.map +1 -0
  261. package/dist/sdk/payment/operations.d.ts +52 -0
  262. package/dist/sdk/payment/operations.js +223 -0
  263. package/dist/sdk/payment/operations.js.map +1 -0
  264. package/dist/sdk/payment/security-code-mask.js +71 -0
  265. package/dist/sdk/payment/security-code-mask.js.map +1 -0
  266. package/dist/sdk/payment/submission-registry.d.ts +33 -0
  267. package/dist/sdk/payment/submission-registry.js +58 -0
  268. package/dist/sdk/payment/submission-registry.js.map +1 -0
  269. package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
  270. package/dist/sdk/payment/use-payment-actions.js +276 -0
  271. package/dist/sdk/payment/use-payment-actions.js.map +1 -0
  272. package/dist/sdk/payment/use-place-order.d.ts +65 -0
  273. package/dist/sdk/payment/use-place-order.js +640 -0
  274. package/dist/sdk/payment/use-place-order.js.map +1 -0
  275. package/dist/sdk/session/auth-operations.d.ts +1 -1
  276. package/dist/sdk/session/auth-operations.js.map +1 -1
  277. package/dist/sdk/session/use-session-actions.d.ts +1 -1
  278. package/dist/sdk/session/use-session-actions.js.map +1 -1
  279. package/dist/sdk/session/use-session-revalidation.js +65 -0
  280. package/dist/sdk/session/use-session-revalidation.js.map +1 -0
  281. package/dist/sdk/shipping/option-select-operations.d.ts +1 -1
  282. package/dist/sdk/shipping/option-select-operations.js.map +1 -1
  283. package/dist/sdk/shipping/request-timeout.js +1 -1
  284. package/dist/sdk/shipping/request-timeout.js.map +1 -1
  285. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  286. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  287. package/dist/sdk/shipping/use-shipping-actions.d.ts +2 -2
  288. package/dist/sdk/shipping/use-shipping-actions.js +1 -1
  289. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
  290. package/dist/sdk/state/cart.d.ts +3 -4
  291. package/dist/sdk/state/cart.js +6 -7
  292. package/dist/sdk/state/cart.js.map +1 -1
  293. package/dist/utils/loggable-error-name.js +49 -0
  294. package/dist/utils/loggable-error-name.js.map +1 -0
  295. package/dist/utils/resolve-authored-copy.js +18 -0
  296. package/dist/utils/resolve-authored-copy.js.map +1 -0
  297. package/dist/utils/safe-href.js +3 -3
  298. package/dist/utils/safe-href.js.map +1 -1
  299. package/dist/utils/substitute-template.js +33 -0
  300. package/dist/utils/substitute-template.js.map +1 -0
  301. package/package.json +2 -1
  302. package/src/styles/tailwind.css +34 -0
  303. package/dist/docs/client-profile-form.md +0 -192
  304. package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
  305. package/dist/matter/client-profile-form/client-profile-form.js +0 -662
  306. package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
@@ -0,0 +1,640 @@
1
+ "use client";
2
+ import { usePaymentSubmission } from "./submission-registry.js";
3
+ import { PAYMENT_NETWORK_ERROR_CODE } from "./operations.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
5
+ import { isTrustedGatewayOrigin } from "./gateway-origin.js";
6
+ import { useCallback, useMemo, useRef, useState } from "react";
7
+ //#region src/sdk/payment/use-place-order.ts
8
+ /**
9
+ * The place-order orchestration (specs/use-place-order.md, T13; docs/features/credit-card/rfc.md
10
+ * § D9) — the PCI-critical core of the credit-card feature, and the only module that knows placing an
11
+ * order is three calls rather than one mutation.
12
+ *
13
+ * **This hook never holds card data.** It resolves an opaque continuation from the submission channel
14
+ * by the shopper's entry path and invokes it between the two backend legs; the card stays in the
15
+ * holder's closure (T7 for a new card, T12 for a saved one), which calls
16
+ * `$actions.payment.sendPayments` itself. So the actions this hook needs are `startTransaction`,
17
+ * `gatewayCallback`, and `analytics.track` — never the gateway façade. Two tests assert the boundary
18
+ * against this file's own source text: no card field is named in code, and the single import from
19
+ * `./gateway.js` is the transaction descriptor's type.
20
+ *
21
+ * The order of the pre-flight is load-bearing, not stylistic. The path, the continuation, and the
22
+ * selected method are all resolved *before* `startTransaction` runs, because a transaction that is
23
+ * opened and then cannot be completed is dangling state on the shopper's order form.
24
+ *
25
+ * v1 is the direct-API mode: the gateway leg resolves inline and the shopper stays on the page. The
26
+ * redirect mode — an external navigation with a resume-on-callback route, and with it 3D Secure — is
27
+ * phase 2, which is why no `callbackUrl` reaches the descriptor.
28
+ *
29
+ * Every failure resolves as `userErrors`; nothing here throws for an expected outcome, so the CTA
30
+ * (T14) renders one error path. Its one per-code branch is PLACE_ORDER_UNCONFIRMED, a pending outcome
31
+ * it shows as a status rather than an error (T176).
32
+ */
33
+ /** No entry path chosen, or no holder registered for the one that was. */
34
+ const PAYMENT_MISSING_SUBMISSION_CODE = "MISSING_PAYMENT_SUBMISSION";
35
+ /**
36
+ * No payment method selected. Reuses `PaymentStartTransactionErrorCode`'s own value for the same
37
+ * state, so a consumer matches one code whichever side detected it.
38
+ */
39
+ const PAYMENT_MISSING_METHOD_CODE = "MISSING_PAYMENT_METHOD_SELECTION";
40
+ /**
41
+ * The transaction opened but cannot be paid — an incomplete payload, or an origin this client will
42
+ * not post a card to. Reuses the server's code for the same meaning (T18 Decision 5).
43
+ */
44
+ const PAYMENT_INVALID_TRANSACTION_CODE = "INVALID_TRANSACTION_DATA";
45
+ /**
46
+ * The attempt's own sequence is still running — opened or finalizing, not yet settled. Not a
47
+ * refusal: nothing failed, the record just belongs to a sequence this caller did not start.
48
+ */
49
+ const PLACE_ORDER_IN_FLIGHT_CODE = "PLACE_ORDER_IN_FLIGHT";
50
+ /**
51
+ * The gatewayCallback leg ran after the gateway accepted the card POST, and this client could not confirm
52
+ * its outcome — the payment may or may not have been authorized. Not a refusal (T176).
53
+ */
54
+ const PLACE_ORDER_UNCONFIRMED_CODE = "PLACE_ORDER_UNCONFIRMED";
55
+ const MISSING_SUBMISSION_ERROR = {
56
+ code: PAYMENT_MISSING_SUBMISSION_CODE,
57
+ message: "Enter your payment details before placing the order."
58
+ };
59
+ const MISSING_METHOD_ERROR = {
60
+ code: PAYMENT_MISSING_METHOD_CODE,
61
+ message: "Choose a payment method before placing the order."
62
+ };
63
+ const INVALID_TRANSACTION_ERROR = {
64
+ code: PAYMENT_INVALID_TRANSACTION_CODE,
65
+ message: "Unable to start the payment. Please try again."
66
+ };
67
+ const PLACE_ORDER_IN_FLIGHT_ERROR = {
68
+ code: PLACE_ORDER_IN_FLIGHT_CODE,
69
+ message: "This order is already being placed. Please wait."
70
+ };
71
+ /**
72
+ * Worded as a pending state, never a failure: it must not tell the shopper to try again (FR-1).
73
+ * `PlaceOrder`'s `unconfirmedMessage` schema default repeats this text verbatim.
74
+ */
75
+ const PLACE_ORDER_UNCONFIRMED_ERROR = {
76
+ code: PLACE_ORDER_UNCONFIRMED_CODE,
77
+ message: "We could not confirm your order yet. Your payment may still be processing, so please do not pay again."
78
+ };
79
+ /** Mirrors `usePaymentActions`' own infrastructure-failure userError, which that module keeps private. */
80
+ const NETWORK_ERROR = {
81
+ code: PAYMENT_NETWORK_ERROR_CODE,
82
+ message: "Unable to complete the request. Please try again."
83
+ };
84
+ /** Identifiers, a host, and amounts — nothing here is sensitive, so naming them in a log is safe. */
85
+ function missingTransactionFields(payload) {
86
+ return Object.entries({
87
+ transactionId: payload.transactionId,
88
+ merchantName: payload.merchantName,
89
+ orderGroup: payload.orderGroup,
90
+ value: payload.value,
91
+ valueInCents: payload.valueInCents,
92
+ referenceValueInCents: payload.referenceValueInCents
93
+ }).filter(([, field]) => field === null).map(([name]) => name);
94
+ }
95
+ /**
96
+ * Narrows a payload that reported no userErrors, or refuses it. The origin is checked first and
97
+ * separately: it is the field that decides where a card is sent, and a refusal here happens before
98
+ * any holder is asked to assemble one.
99
+ */
100
+ function settleTransaction(payload) {
101
+ if (!isTrustedGatewayOrigin(payload.gatewayUrl)) {
102
+ console.error("[payment.placeOrder] the opened transaction carries no trusted https gateway origin");
103
+ return null;
104
+ }
105
+ const { transactionId, merchantName, orderGroup, userProfileId, value, valueInCents, referenceValueInCents } = payload;
106
+ if (transactionId === null || merchantName === null || orderGroup === null || value === null || valueInCents === null || referenceValueInCents === null) {
107
+ console.error("[payment.placeOrder] the opened transaction payload is incomplete", missingTransactionFields(payload).join(", "));
108
+ return null;
109
+ }
110
+ return {
111
+ gatewayUrl: payload.gatewayUrl,
112
+ transactionId,
113
+ merchantName,
114
+ orderGroup,
115
+ userProfileId,
116
+ value,
117
+ valueInCents,
118
+ referenceValueInCents
119
+ };
120
+ }
121
+ /**
122
+ * The one derived amount on the descriptor. VTEX's `payments[0]` carries no per-installment minor-unit
123
+ * value, so T18 could not expose one and the conversion stays here — rounded, because
124
+ * `19.99 * 100 === 1998.9999999999998`. `Number()` is not redundant: the components codegen maps the
125
+ * `Decimal` scalar to `number` while the resolver serializes it as a string (see the spec's Open items).
126
+ */
127
+ function toMinorUnits(amount) {
128
+ return Math.round(Number(amount) * 100);
129
+ }
130
+ /**
131
+ * The one call into holder-owned code. A holder's continuation is specified to resolve `userErrors` —
132
+ * `sendPayments` already collapses every gateway outcome to one — so a throw means its contract broke.
133
+ * Only a sanitised error *name* is logged (T160): the closure that threw holds the card, and a message
134
+ * or stack could echo it — and so, unsanitised, could `.name` itself, since it is a writable own
135
+ * property. See `loggableErrorName()`.
136
+ */
137
+ async function invokeSubmission(submit, transaction) {
138
+ try {
139
+ const result = await submit(transaction);
140
+ if (result == null) {
141
+ console.error("[payment.placeOrder] the registered submission resolved with no result");
142
+ return [NETWORK_ERROR];
143
+ }
144
+ return result;
145
+ } catch (error) {
146
+ console.error("[payment.placeOrder] the registered submission threw", loggableErrorName(error));
147
+ return [NETWORK_ERROR];
148
+ }
149
+ }
150
+ /**
151
+ * The pre-flight counterpart of `invokeSubmission`, and it inherits that function's one rule: the
152
+ * closure that throws holds the card, so only a sanitised error *name* is logged (T160) — never a
153
+ * message, a stack, or the raw writable `.name` property. See `loggableErrorName()`.
154
+ */
155
+ function runPreflight(check) {
156
+ try {
157
+ return check();
158
+ } catch (error) {
159
+ console.error("[payment.placeOrder] the registered pre-flight threw", loggableErrorName(error));
160
+ return [NETWORK_ERROR];
161
+ }
162
+ }
163
+ /**
164
+ * The `startTransaction` counterpart of `invokeSubmission`/`runPreflight` (fix pass, Medium finding):
165
+ * before this, `run()` awaited `startTransaction()` directly, so a **rejection** — as opposed to a
166
+ * resolved payload carrying `userErrors` — escaped past every one of `run()`'s own outcome branches
167
+ * and `settleSequence`'s rejection handler never touches the attempt record, leaving it stuck at
168
+ * `opening` for the payment root's lifetime. `opening` is the one phase `placeOrder()` treats as
169
+ * "already running" with no failure exit, so every later click resolves `{ orderId: null, userErrors:
170
+ * [] }` without running anything — a false "Order placed successfully." with the CTA disabled forever.
171
+ * `usePlaceOrder` is exported public API and `$actions` is compiler-injected and pluggable, so a
172
+ * provider that rejects here is reachable, not hypothetical. Collapsing the rejection to a resolved
173
+ * payload with one `userErrors` entry means `run()`'s own existing `payload.userErrors.length > 0`
174
+ * branch is what catches it — the same `refused` outcome a server-reported refusal already gets,
175
+ * correct here too since nothing can have been paid before the transaction even opened.
176
+ *
177
+ * T156 fold: the result is destructured inside this `try`, not returned as `await startTransaction()`
178
+ * untouched — a provider resolving `undefined` used to throw at the caller's own
179
+ * `payload.userErrors.length` read, past this function's own `catch`, latching the attempt at
180
+ * `opening` exactly like the rejection case above. Destructuring a nullish resolution throws here
181
+ * instead, so it collapses the same way. Mirrors `invokeGatewayCallback`'s own reason for
182
+ * destructuring, below.
183
+ *
184
+ * Fix pass (review F1/S1): `userErrors` is defaulted with `?? [NETWORK_ERROR]`, not `?? []` — a
185
+ * *partial* payload (present, but missing `userErrors`, e.g. a provider whose GraphQL selection omits
186
+ * the field) used to leave it `undefined`, reaching the caller's `payload.userErrors.length` read
187
+ * (`:627`) and throwing past this function's own `catch`, latching the attempt at `opening` exactly
188
+ * like the cases already fixed. `userErrors` is this result's only signal of whether anything actually
189
+ * went wrong, so a payload that omits it defaults to a *failure*, mirroring a rejection — defaulting to
190
+ * `[]` instead would settle the attempt on a payload this function never actually saw. (The in-repo
191
+ * default provider's own `payload?.userErrors ?? []`, `use-payment-actions.ts:202`, defaults to `[]`
192
+ * only because there `payload` itself — not just the field — is what may be missing.)
193
+ */
194
+ async function invokeStartTransaction(startTransaction) {
195
+ try {
196
+ const { transactionId, merchantName, gatewayUrl, orderGroup, userProfileId, value, valueInCents, referenceValueInCents, userErrors } = await startTransaction();
197
+ if (userErrors == null) console.error("[payment.placeOrder] startTransaction resolved with no userErrors", orderGroup);
198
+ return {
199
+ transactionId,
200
+ merchantName,
201
+ gatewayUrl,
202
+ orderGroup,
203
+ userProfileId,
204
+ value,
205
+ valueInCents,
206
+ referenceValueInCents,
207
+ userErrors: userErrors ?? [NETWORK_ERROR]
208
+ };
209
+ } catch (error) {
210
+ console.error("[payment.placeOrder] startTransaction threw", loggableErrorName(error));
211
+ return {
212
+ transactionId: null,
213
+ merchantName: null,
214
+ gatewayUrl: null,
215
+ orderGroup: null,
216
+ userProfileId: null,
217
+ value: null,
218
+ valueInCents: null,
219
+ referenceValueInCents: null,
220
+ userErrors: [NETWORK_ERROR]
221
+ };
222
+ }
223
+ }
224
+ /**
225
+ * The `gatewayCallback` counterpart of `invokeStartTransaction` above (T156, PR #756 review R-004):
226
+ * before this, both call sites below awaited `gatewayCallback` directly, so a **rejection**
227
+ * escaped past every outcome branch and `settleSequence`'s rejection handler never touches the attempt
228
+ * record, leaving it stuck at `finalizing` for the payment root's lifetime — `placeOrder()` treats
229
+ * `finalizing` exactly like `opening`, an already-running phase with no failure exit, so every later
230
+ * click resolved `{ orderId: attempt.orderId, userErrors: [] }` without issuing anything.
231
+ *
232
+ * The destination is `unresolved`, never `refused` like `invokeStartTransaction`'s own collapse: this
233
+ * leg only runs once the card already reached the gateway, so nothing here can pretend no money moved.
234
+ * `unresolved` is exactly the phase `PlaceOrderAttemptPhase` already documents for this case, below,
235
+ * and is already resumable.
236
+ *
237
+ * Three failure shapes collapse to the same `NETWORK_ERROR` result, logged distinctly (fix pass,
238
+ * review F1/S1/F3): a **rejection**, caught below; a **nullish resolution** (`undefined`/`null`),
239
+ * caught by the explicit check that follows rather than by letting a destructure throw, so it logs a
240
+ * line of its own instead of printing identically to a rejection; and a **partial resolution** — an
241
+ * object present but missing `userErrors`, e.g. a provider whose GraphQL selection omits the field —
242
+ * defaulted with `?? [NETWORK_ERROR]`, not `?? []`. That last case used to return `{ orderId,
243
+ * userErrors }` untouched, leaving `userErrors: undefined`, so the *caller's* `callback.userErrors.length`
244
+ * read threw one call site away from where this wrapper's whole job is to stop exactly that. `[]` would
245
+ * default a payload this function never actually saw to a clean success; `userErrors` is the only
246
+ * signal of whether the callback settled anything, so omitting it means treating it as a failure.
247
+ * Both failure branches log `orderGroup` and `attemptId` — neither is card data
248
+ * (`missingTransactionFields`'s comment above), and this is the one point in the flow where money may
249
+ * already have moved — but never the error's message, stack, or any call argument (FR-6).
250
+ *
251
+ * No `gatewayCallback` call may exist in this module outside this function (INV-2, asserted against
252
+ * this file's own source text in use-place-order.test.tsx) — the two call sites below (`resume()` and
253
+ * `run()`) call this and nothing else.
254
+ */
255
+ async function invokeGatewayCallback(gatewayCallback, orderGroup, attemptId) {
256
+ let result;
257
+ try {
258
+ result = await gatewayCallback(orderGroup);
259
+ } catch (error) {
260
+ console.error("[payment.placeOrder] gatewayCallback threw", orderGroup, attemptId, loggableErrorName(error));
261
+ return {
262
+ orderId: null,
263
+ userErrors: [NETWORK_ERROR]
264
+ };
265
+ }
266
+ if (result == null) {
267
+ console.error("[payment.placeOrder] gatewayCallback resolved with no result", orderGroup, attemptId);
268
+ return {
269
+ orderId: null,
270
+ userErrors: [NETWORK_ERROR]
271
+ };
272
+ }
273
+ if (result.userErrors == null) console.error("[payment.placeOrder] gatewayCallback resolved with no userErrors", orderGroup, attemptId);
274
+ return {
275
+ orderId: result.orderId ?? null,
276
+ userErrors: result.userErrors ?? [NETWORK_ERROR]
277
+ };
278
+ }
279
+ /**
280
+ * T176 (FR-2, FR-3): what the caller reads from a `gatewayCallback` that reported `userErrors`, on both
281
+ * paths that issue it. The gateway already accepted the card POST by then, so a result made only of this
282
+ * package's own collapse — `PAYMENT_NETWORK_ERROR_CODE`, which `usePaymentActions` and
283
+ * `invokeGatewayCallback` resolve for every thrown, lost or shapeless response — says nothing about
284
+ * whether VTEX processed the order. It becomes PLACE_ORDER_UNCONFIRMED rather than a "try again" that
285
+ * invites a second payment. A code the server sent is an answer, and comes back unchanged (INV-10).
286
+ *
287
+ * Total, and never throws: a non-array, or an entry with no readable string `code`, carries no server
288
+ * code, so it reads as unconfirmed too. A server code elsewhere in the same list still wins, whatever
289
+ * order the entries come in.
290
+ */
291
+ function reconcileCallbackUserErrors(userErrors) {
292
+ try {
293
+ if (!Array.isArray(userErrors)) return [PLACE_ORDER_UNCONFIRMED_ERROR];
294
+ if (userErrors.length === 0) return userErrors;
295
+ return userErrors.some((userError) => {
296
+ try {
297
+ const code = userError.code;
298
+ return typeof code === "string" && code !== "NETWORK_ERROR";
299
+ } catch {
300
+ return false;
301
+ }
302
+ }) ? userErrors : [PLACE_ORDER_UNCONFIRMED_ERROR];
303
+ } catch {
304
+ return [PLACE_ORDER_UNCONFIRMED_ERROR];
305
+ }
306
+ }
307
+ /**
308
+ * `crypto.randomUUID()` is secure-context-only (fix pass, Low finding) — on a plain-HTTP preview or
309
+ * staging origin the method does not exist on `crypto` at all, so calling it throws, and every click
310
+ * collapses to a generic `NETWORK_ERROR` with no diagnostic. `localhost` is always a secure context,
311
+ * so dev never reproduces it. Falls back to a timestamp+random string, which only needs to be unique
312
+ * for one payment root's lifetime (the staleness guard below is its one reader) — not a real UUID.
313
+ */
314
+ function generateAttemptId() {
315
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
316
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
317
+ }
318
+ /**
319
+ * Fix pass (High finding, race #2): guards every write past an attempt's genesis against a stale,
320
+ * out-of-order completion clobbering a newer outcome. `run()`/`resume()` mint one write *before* their
321
+ * own first await (safe by construction — nothing can have superseded an attempt this call itself just
322
+ * created) and one or more writes *after* an await, once `startTransaction`/the continuation/
323
+ * `gatewayCallback` resolve. Because the writing closure keeps running after its own CTA unmounts
324
+ * (NFR-3), that later write cannot assume the shared attempt is still the one it started with — a
325
+ * remounted or sibling instance may have already resumed it to a newer phase in the meantime. Using
326
+ * the setter's own functional-update form (`SetPlaceOrderAttempt`) checks against whatever the shared
327
+ * attempt actually is *when the write is applied*, not the value this closure captured before its
328
+ * await — mirrors `selectionToken`'s own precedent (`matter/payment/use-payment-method-selection.ts`)
329
+ * for the identical shape of problem, keyed on the attempt's own id instead of a second counter.
330
+ * `settled` is additionally excluded because INV-6 forbids any transition away from it.
331
+ */
332
+ function writeAttemptIfCurrent(setAttempt, attemptId, next) {
333
+ setAttempt?.((prev) => prev !== null && prev.attemptId === attemptId && prev.phase !== "settled" ? next : prev);
334
+ }
335
+ /**
336
+ * T29 (Decision 3, FR-3): the only path back into a `sent`/`unresolved` attempt — `gatewayCallback` is
337
+ * the sole call it ever issues. Module scope, not a `useCallback` inside the hook (fix pass, Low
338
+ * finding): the previous version of this doc comment claimed `startTransaction`, the submission
339
+ * channel, and `PaymentGatewayTransaction` were "not in scope," so a careless future edit could not
340
+ * make a resume re-pay — true at runtime today (verified by identifier sweep) but false as a
341
+ * structural guarantee, since all three were merely unreferenced identifiers a nested closure could
342
+ * still have read. Hoisting here makes the claim actually true: none of those three is even
343
+ * *importable* from a bare module-level function that takes only `gatewayCallback`/`setAttempt`/
344
+ * `setPlacing`/`current` as arguments — a resume is safe by construction, not by convention.
345
+ */
346
+ async function resume(gatewayCallback, setAttempt, setPlacing, current) {
347
+ if (!gatewayCallback || current.orderGroup === null) {
348
+ console.error("[payment.placeOrder] cannot resume an attempt with no order group");
349
+ return {
350
+ orderId: null,
351
+ userErrors: [NETWORK_ERROR]
352
+ };
353
+ }
354
+ writeAttemptIfCurrent(setAttempt, current.attemptId, {
355
+ ...current,
356
+ phase: "finalizing"
357
+ });
358
+ setPlacing(true);
359
+ const callback = await invokeGatewayCallback(gatewayCallback, current.orderGroup, current.attemptId);
360
+ const failed = callback.userErrors.length > 0;
361
+ const result = failed ? {
362
+ orderId: null,
363
+ userErrors: reconcileCallbackUserErrors(callback.userErrors)
364
+ } : {
365
+ orderId: callback.orderId,
366
+ userErrors: []
367
+ };
368
+ try {
369
+ writeAttemptIfCurrent(setAttempt, current.attemptId, failed ? {
370
+ ...current,
371
+ phase: "unresolved"
372
+ } : {
373
+ ...current,
374
+ phase: "settled",
375
+ orderId: callback.orderId
376
+ });
377
+ } catch (error) {
378
+ console.error("[payment.placeOrder] the resume record write threw", current.attemptId, loggableErrorName(error));
379
+ }
380
+ return result;
381
+ }
382
+ function usePlaceOrder({ $data, $actions, attempt, setAttempt, billingAddressDifferent, submitGate }) {
383
+ const { path, resolve, resolvePreflight } = usePaymentSubmission();
384
+ const [placing, setPlacing] = useState(false);
385
+ const [userErrors, setUserErrors] = useState([]);
386
+ const [orderId, setOrderId] = useState(null);
387
+ const inFlight = useRef(null);
388
+ const startTransaction = $actions?.payment?.startTransaction;
389
+ const gatewayCallback = $actions?.payment?.gatewayCallback;
390
+ const track = $actions?.analytics?.track;
391
+ const selectedMethodId = $data?.selectedMethodId ?? null;
392
+ const methods = $data?.methods;
393
+ const selectedInstallment = $data?.selectedInstallment ?? null;
394
+ const selectedMethod = useMemo(() => methods?.find((method) => method.id === selectedMethodId) ?? null, [methods, selectedMethodId]);
395
+ const run = useCallback(async () => {
396
+ if (!startTransaction || !gatewayCallback) {
397
+ console.error("[payment.placeOrder] the payment action namespace is not injected");
398
+ return {
399
+ orderId: null,
400
+ userErrors: [NETWORK_ERROR]
401
+ };
402
+ }
403
+ const submit = path === null ? null : resolve(path);
404
+ if (submit === null) {
405
+ console.error("[payment.placeOrder] no submission is registered for the entry path", path ?? "none");
406
+ return {
407
+ orderId: null,
408
+ userErrors: [MISSING_SUBMISSION_ERROR]
409
+ };
410
+ }
411
+ if (selectedMethod === null) {
412
+ console.error("[payment.placeOrder] no payment method is selected");
413
+ return {
414
+ orderId: null,
415
+ userErrors: [MISSING_METHOD_ERROR]
416
+ };
417
+ }
418
+ if (submitGate) {
419
+ console.error("[payment.placeOrder] a client-side gate refused the submission", submitGate.code);
420
+ return {
421
+ orderId: null,
422
+ userErrors: [submitGate]
423
+ };
424
+ }
425
+ const preflight = path === null ? null : resolvePreflight(path);
426
+ if (preflight) {
427
+ const refusals = runPreflight(preflight);
428
+ if (refusals.length > 0) {
429
+ console.error("[payment.placeOrder] the registered pre-flight refused the submission", refusals[0]?.code);
430
+ return {
431
+ orderId: null,
432
+ userErrors: refusals
433
+ };
434
+ }
435
+ }
436
+ let handedOver = false;
437
+ let settledOrderGroup = null;
438
+ let placedAttempt = null;
439
+ let outcome = null;
440
+ const attemptId = generateAttemptId();
441
+ setAttempt?.({
442
+ attemptId,
443
+ phase: "opening",
444
+ orderGroup: null,
445
+ orderId: null
446
+ });
447
+ try {
448
+ setPlacing(true);
449
+ const payload = await invokeStartTransaction(startTransaction);
450
+ if (payload.userErrors.length > 0) {
451
+ writeAttemptIfCurrent(setAttempt, attemptId, {
452
+ attemptId,
453
+ phase: "refused",
454
+ orderGroup: null,
455
+ orderId: null
456
+ });
457
+ return {
458
+ orderId: null,
459
+ userErrors: payload.userErrors
460
+ };
461
+ }
462
+ const settled = settleTransaction(payload);
463
+ if (settled === null) {
464
+ writeAttemptIfCurrent(setAttempt, attemptId, {
465
+ attemptId,
466
+ phase: "refused",
467
+ orderGroup: null,
468
+ orderId: null
469
+ });
470
+ return {
471
+ orderId: null,
472
+ userErrors: [INVALID_TRANSACTION_ERROR]
473
+ };
474
+ }
475
+ settledOrderGroup = settled.orderGroup;
476
+ writeAttemptIfCurrent(setAttempt, attemptId, {
477
+ attemptId,
478
+ phase: "opening",
479
+ orderGroup: settled.orderGroup,
480
+ orderId: null
481
+ });
482
+ const transaction = {
483
+ gatewayUrl: settled.gatewayUrl,
484
+ transactionId: settled.transactionId,
485
+ merchantName: settled.merchantName,
486
+ orderGroup: settled.orderGroup,
487
+ userProfileId: settled.userProfileId,
488
+ paymentSystem: selectedMethod.id,
489
+ groupName: selectedMethod.groupName,
490
+ currencyCode: settled.value.currencyCode,
491
+ valueInCents: settled.valueInCents,
492
+ referenceValueInCents: settled.referenceValueInCents,
493
+ installments: selectedInstallment?.count ?? 1,
494
+ installmentsValueInCents: selectedInstallment && selectedInstallment.count !== 1 ? toMinorUnits(selectedInstallment.value.amount) : settled.valueInCents,
495
+ interestRate: selectedInstallment?.interestRate ?? 0,
496
+ ...billingAddressDifferent != null ? { billingAddressDifferent } : {}
497
+ };
498
+ handedOver = true;
499
+ const submissionErrors = await invokeSubmission(submit, transaction);
500
+ if (submissionErrors.length > 0) {
501
+ outcome = {
502
+ orderId: null,
503
+ userErrors: submissionErrors
504
+ };
505
+ writeAttemptIfCurrent(setAttempt, attemptId, {
506
+ attemptId,
507
+ phase: "unresolved",
508
+ orderGroup: settled.orderGroup,
509
+ orderId: null
510
+ });
511
+ return outcome;
512
+ }
513
+ writeAttemptIfCurrent(setAttempt, attemptId, {
514
+ attemptId,
515
+ phase: "finalizing",
516
+ orderGroup: settled.orderGroup,
517
+ orderId: null
518
+ });
519
+ const callback = await invokeGatewayCallback(gatewayCallback, settled.orderGroup, attemptId);
520
+ if (callback.userErrors.length > 0) {
521
+ outcome = {
522
+ orderId: null,
523
+ userErrors: reconcileCallbackUserErrors(callback.userErrors)
524
+ };
525
+ writeAttemptIfCurrent(setAttempt, attemptId, {
526
+ attemptId,
527
+ phase: "unresolved",
528
+ orderGroup: settled.orderGroup,
529
+ orderId: null
530
+ });
531
+ return outcome;
532
+ }
533
+ placedAttempt = {
534
+ attemptId,
535
+ phase: "settled",
536
+ orderGroup: settled.orderGroup,
537
+ orderId: callback.orderId
538
+ };
539
+ outcome = {
540
+ orderId: callback.orderId,
541
+ userErrors: []
542
+ };
543
+ track?.({
544
+ name: "purchase",
545
+ transactionId: callback.orderId ?? settled.transactionId,
546
+ value: {
547
+ amount: Number(settled.value.amount),
548
+ currencyCode: settled.value.currencyCode
549
+ }
550
+ });
551
+ writeAttemptIfCurrent(setAttempt, attemptId, placedAttempt);
552
+ return outcome;
553
+ } catch (error) {
554
+ console.error("[payment.placeOrder] the place-order sequence threw", attemptId, loggableErrorName(error));
555
+ try {
556
+ writeAttemptIfCurrent(setAttempt, attemptId, placedAttempt ?? (handedOver ? {
557
+ attemptId,
558
+ phase: "unresolved",
559
+ orderGroup: settledOrderGroup,
560
+ orderId: null
561
+ } : {
562
+ attemptId,
563
+ phase: "refused",
564
+ orderGroup: null,
565
+ orderId: null
566
+ }));
567
+ } catch (writeError) {
568
+ console.error("[payment.placeOrder] the place-order recovery write threw", attemptId, loggableErrorName(writeError));
569
+ }
570
+ return outcome ?? {
571
+ orderId: null,
572
+ userErrors: [NETWORK_ERROR]
573
+ };
574
+ }
575
+ }, [
576
+ startTransaction,
577
+ gatewayCallback,
578
+ track,
579
+ path,
580
+ resolve,
581
+ resolvePreflight,
582
+ selectedMethod,
583
+ selectedInstallment,
584
+ billingAddressDifferent,
585
+ submitGate,
586
+ setAttempt
587
+ ]);
588
+ const placeOrder = useCallback(() => {
589
+ if (inFlight.current !== null) return inFlight.current;
590
+ const settleSequence = (sequence) => {
591
+ setUserErrors([]);
592
+ setOrderId(null);
593
+ const settle = (result) => {
594
+ inFlight.current = null;
595
+ setPlacing(false);
596
+ setUserErrors(result.userErrors);
597
+ setOrderId(result.orderId);
598
+ return result;
599
+ };
600
+ const outcome = sequence.then(settle, () => settle({
601
+ orderId: null,
602
+ userErrors: [NETWORK_ERROR]
603
+ }));
604
+ inFlight.current = outcome;
605
+ return outcome;
606
+ };
607
+ if (attempt) {
608
+ if (attempt.phase === "settled") return Promise.resolve({
609
+ orderId: attempt.orderId,
610
+ userErrors: []
611
+ });
612
+ if (attempt.phase === "opening" || attempt.phase === "finalizing") return settleSequence(Promise.resolve({
613
+ orderId: attempt.orderId,
614
+ userErrors: [PLACE_ORDER_IN_FLIGHT_ERROR]
615
+ }));
616
+ if (attempt.phase === "sent" || attempt.phase === "unresolved") return settleSequence(resume(gatewayCallback, setAttempt, setPlacing, attempt));
617
+ }
618
+ return settleSequence(run());
619
+ }, [
620
+ run,
621
+ attempt,
622
+ gatewayCallback,
623
+ setAttempt
624
+ ]);
625
+ return useMemo(() => ({
626
+ placeOrder,
627
+ placing,
628
+ userErrors,
629
+ orderId
630
+ }), [
631
+ placeOrder,
632
+ placing,
633
+ userErrors,
634
+ orderId
635
+ ]);
636
+ }
637
+ //#endregion
638
+ export { PAYMENT_INVALID_TRANSACTION_CODE, PAYMENT_MISSING_METHOD_CODE, PAYMENT_MISSING_SUBMISSION_CODE, PLACE_ORDER_IN_FLIGHT_CODE, PLACE_ORDER_UNCONFIRMED_CODE, usePlaceOrder };
639
+
640
+ //# sourceMappingURL=use-place-order.js.map