@vtex/faststore 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/actions.json +152 -1
  3. package/dist/catalog.json +1264 -142
  4. package/dist/cli/index.d.ts +512 -63
  5. package/dist/cli/index.js +2098 -686
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/server-runtime.js +44 -24
  8. package/dist/cli/server-runtime.js.map +1 -1
  9. package/dist/client.d.ts +5 -1
  10. package/dist/client.js +5 -1
  11. package/dist/components.d.ts +34 -7
  12. package/dist/components.js +38 -11
  13. package/dist/content-types.json +523 -0
  14. package/dist/core/dist/define-component.d.ts +6 -1
  15. package/dist/docs/account-access-gate.md +4 -4
  16. package/dist/docs/account-address-book.md +519 -0
  17. package/dist/docs/account-entry-point.md +1 -1
  18. package/dist/docs/account-menu.md +5 -5
  19. package/dist/docs/alert-dialog.md +2 -2
  20. package/dist/docs/billing-address.md +17 -9
  21. package/dist/docs/card-entry.md +37 -6
  22. package/dist/docs/cardholder-document.md +16 -14
  23. package/dist/docs/cart-item.md +1 -1
  24. package/dist/docs/cart.md +8 -8
  25. package/dist/docs/client-profile-fieldset.md +7 -5
  26. package/dist/docs/copy-text.md +84 -0
  27. package/dist/docs/document-field.md +8 -8
  28. package/dist/docs/footer-link-group.md +2 -2
  29. package/dist/docs/header-root.md +1 -1
  30. package/dist/docs/incentives.md +2 -2
  31. package/dist/docs/logo.md +5 -5
  32. package/dist/docs/my-account-profile.md +4 -4
  33. package/dist/docs/navigation-link-list.md +2 -2
  34. package/dist/docs/navigation-link.md +3 -3
  35. package/dist/docs/order-cancel.md +52 -0
  36. package/dist/docs/order-delivery-address.md +63 -0
  37. package/dist/docs/order-delivery-group.md +83 -0
  38. package/dist/docs/order-details-back.md +41 -0
  39. package/dist/docs/order-details-header.md +48 -0
  40. package/dist/docs/order-list-row.md +46 -0
  41. package/dist/docs/order-list-search.md +101 -0
  42. package/dist/docs/order-list-views.md +97 -0
  43. package/dist/docs/order-list.md +94 -0
  44. package/dist/docs/order-payment.md +94 -0
  45. package/dist/docs/order-placed-date.md +49 -0
  46. package/dist/docs/order-placed-payment-summary.md +13 -15
  47. package/dist/docs/order-placed.md +225 -0
  48. package/dist/docs/order-progress.md +88 -0
  49. package/dist/docs/order-status-badge.md +91 -0
  50. package/dist/docs/order-summary.md +53 -0
  51. package/dist/docs/payment-method-badges.md +14 -3
  52. package/dist/docs/place-order.md +13 -9
  53. package/dist/docs/saved-cards.md +2 -2
  54. package/dist/docs/select.md +19 -6
  55. package/dist/docs/session.md +1 -1
  56. package/dist/docs/shipping-address.md +1 -1
  57. package/dist/docs/sign-in-redirect.md +6 -6
  58. package/dist/docs/toast.md +7 -3
  59. package/dist/index.d.ts +6 -2
  60. package/dist/index.js +2 -1
  61. package/dist/internal/client.d.ts +6 -1
  62. package/dist/internal/client.js +7 -2
  63. package/dist/internal/server.d.ts +6 -2
  64. package/dist/internal/server.js +6 -2
  65. package/dist/matter/account-access-gate/account-access-gate.d.ts +2 -1
  66. package/dist/matter/account-access-gate/account-access-gate.js +19 -16
  67. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
  68. package/dist/matter/account-address-book/account-address-book-delete.d.ts +60 -0
  69. package/dist/matter/account-address-book/account-address-book-delete.js +184 -0
  70. package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -0
  71. package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +19 -0
  72. package/dist/matter/account-address-book/account-address-book-deliverability.js +50 -0
  73. package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -0
  74. package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +42 -0
  75. package/dist/matter/account-address-book/account-address-book-form-parts.js +146 -0
  76. package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -0
  77. package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +25 -0
  78. package/dist/matter/account-address-book/account-address-book-profile-notice.js +72 -0
  79. package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -0
  80. package/dist/matter/account-address-book/account-address-book.d.ts +120 -0
  81. package/dist/matter/account-address-book/account-address-book.js +469 -0
  82. package/dist/matter/account-address-book/account-address-book.js.map +1 -0
  83. package/dist/matter/account-address-book/account-address-country-switch.js +59 -0
  84. package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -0
  85. package/dist/matter/account-address-book/account-address-country.d.ts +36 -0
  86. package/dist/matter/account-address-book/account-address-country.js +151 -0
  87. package/dist/matter/account-address-book/account-address-country.js.map +1 -0
  88. package/dist/matter/account-address-book/account-address-first-line.js +11 -0
  89. package/dist/matter/account-address-book/account-address-first-line.js.map +1 -0
  90. package/dist/matter/account-address-book/account-address-form-context.d.ts +55 -0
  91. package/dist/matter/account-address-book/account-address-form-context.js +14 -0
  92. package/dist/matter/account-address-book/account-address-form-context.js.map +1 -0
  93. package/dist/matter/account-address-book/account-address-form.d.ts +85 -0
  94. package/dist/matter/account-address-book/account-address-form.js +946 -0
  95. package/dist/matter/account-address-book/account-address-form.js.map +1 -0
  96. package/dist/matter/account-address-book/account-address-postal-autofill.js +189 -0
  97. package/dist/matter/account-address-book/account-address-postal-autofill.js.map +1 -0
  98. package/dist/matter/account-address-book/account-address-record.d.ts +26 -0
  99. package/dist/matter/account-address-book/account-address-record.js +138 -0
  100. package/dist/matter/account-address-book/account-address-record.js.map +1 -0
  101. package/dist/matter/account-entry-point/account-entry-point.js +11 -11
  102. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  103. package/dist/matter/account-menu/account-menu.d.ts +7 -3
  104. package/dist/matter/account-menu/account-menu.js +69 -28
  105. package/dist/matter/account-menu/account-menu.js.map +1 -1
  106. package/dist/matter/billing-address/billing-address.d.ts +30 -17
  107. package/dist/matter/billing-address/billing-address.js +128 -33
  108. package/dist/matter/billing-address/billing-address.js.map +1 -1
  109. package/dist/matter/breadcrumb/breadcrumb.js +2 -2
  110. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
  111. package/dist/matter/card-entry/card-capture.js +4 -3
  112. package/dist/matter/card-entry/card-capture.js.map +1 -1
  113. package/dist/matter/card-entry/card-entry.d.ts +5 -3
  114. package/dist/matter/card-entry/card-entry.js +77 -27
  115. package/dist/matter/card-entry/card-entry.js.map +1 -1
  116. package/dist/matter/cardholder-document/cardholder-document.d.ts +10 -9
  117. package/dist/matter/cardholder-document/cardholder-document.js +36 -16
  118. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -1
  119. package/dist/matter/cart/cart.d.ts +7 -2
  120. package/dist/matter/cart/cart.js +29 -26
  121. package/dist/matter/cart/cart.js.map +1 -1
  122. package/dist/matter/cart-item/cart-item.js +2 -2
  123. package/dist/matter/cart-item/cart-item.js.map +1 -1
  124. package/dist/matter/client-preferences/client-preferences-fieldset.js +1 -1
  125. package/dist/matter/client-profile-form/client-profile-fieldset.js +8 -5
  126. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
  127. package/dist/matter/identity-edit/identity-edit.js +3 -3
  128. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  129. package/dist/matter/identity-summary/identity-summary.js +2 -2
  130. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  131. package/dist/matter/my-account-profile/my-account-profile.d.ts +3 -3
  132. package/dist/matter/my-account-profile/my-account-profile.js +4 -4
  133. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  134. package/dist/matter/order-cancel/order-cancel.d.ts +110 -0
  135. package/dist/matter/order-cancel/order-cancel.js +344 -0
  136. package/dist/matter/order-cancel/order-cancel.js.map +1 -0
  137. package/dist/matter/order-delivery-address/order-delivery-address.d.ts +73 -0
  138. package/dist/matter/order-delivery-address/order-delivery-address.js +172 -0
  139. package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -0
  140. package/dist/matter/order-delivery-group/order-delivery-group.d.ts +128 -0
  141. package/dist/matter/order-delivery-group/order-delivery-group.js +408 -0
  142. package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -0
  143. package/dist/matter/order-details-header/order-details-header.d.ts +104 -0
  144. package/dist/matter/order-details-header/order-details-header.js +190 -0
  145. package/dist/matter/order-details-header/order-details-header.js.map +1 -0
  146. package/dist/matter/order-list/customer-orders-filter.d.ts +12 -0
  147. package/dist/matter/order-list/customer-orders-filter.js +30 -0
  148. package/dist/matter/order-list/customer-orders-filter.js.map +1 -0
  149. package/dist/matter/order-list/order-list.d.ts +121 -0
  150. package/dist/matter/order-list/order-list.js +395 -0
  151. package/dist/matter/order-list/order-list.js.map +1 -0
  152. package/dist/matter/order-list-row/order-list-row.d.ts +44 -0
  153. package/dist/matter/order-list-row/order-list-row.js +127 -0
  154. package/dist/matter/order-list-row/order-list-row.js.map +1 -0
  155. package/dist/matter/order-list-search/order-list-search.d.ts +72 -0
  156. package/dist/matter/order-list-search/order-list-search.js +296 -0
  157. package/dist/matter/order-list-search/order-list-search.js.map +1 -0
  158. package/dist/matter/order-list-views/order-list-views.d.ts +65 -0
  159. package/dist/matter/order-list-views/order-list-views.js +154 -0
  160. package/dist/matter/order-list-views/order-list-views.js.map +1 -0
  161. package/dist/matter/order-payment/order-payment.d.ts +83 -0
  162. package/dist/matter/order-payment/order-payment.js +258 -0
  163. package/dist/matter/order-payment/order-payment.js.map +1 -0
  164. package/dist/matter/order-placed/order-placed-deliveries.d.ts +145 -0
  165. package/dist/matter/order-placed/order-placed-deliveries.js +380 -0
  166. package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -0
  167. package/dist/matter/order-placed/order-placed.d.ts +122 -0
  168. package/dist/matter/order-placed/order-placed.js +452 -0
  169. package/dist/matter/order-placed/order-placed.js.map +1 -0
  170. package/dist/matter/order-placed-date/order-placed-date.d.ts +45 -0
  171. package/dist/matter/order-placed-date/order-placed-date.js +92 -0
  172. package/dist/matter/order-placed-date/order-placed-date.js.map +1 -0
  173. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +5 -8
  174. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +29 -81
  175. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
  176. package/dist/matter/order-progress/order-progress.d.ts +85 -0
  177. package/dist/matter/order-progress/order-progress.js +203 -0
  178. package/dist/matter/order-progress/order-progress.js.map +1 -0
  179. package/dist/matter/order-summary/order-summary.d.ts +81 -0
  180. package/dist/matter/order-summary/order-summary.js +192 -0
  181. package/dist/matter/order-summary/order-summary.js.map +1 -0
  182. package/dist/matter/payment/cardholder-document-rule.d.ts +35 -0
  183. package/dist/matter/payment/cardholder-document-rule.js +35 -0
  184. package/dist/matter/payment/cardholder-document-rule.js.map +1 -0
  185. package/dist/matter/payment/payment-card-capture.js +38 -23
  186. package/dist/matter/payment/payment-card-capture.js.map +1 -1
  187. package/dist/matter/payment/payment-controller.js +11 -0
  188. package/dist/matter/payment/payment-controller.js.map +1 -1
  189. package/dist/matter/payment/payment-method-badges.js +4 -2
  190. package/dist/matter/payment/payment-method-badges.js.map +1 -1
  191. package/dist/matter/payment/payment.js +11 -0
  192. package/dist/matter/payment/payment.js.map +1 -1
  193. package/dist/matter/payment/use-payment-method-selection.d.ts +39 -0
  194. package/dist/matter/payment/use-payment-method-selection.js +30 -2
  195. package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
  196. package/dist/matter/payment/use-payment-submit-gate.d.ts +16 -2
  197. package/dist/matter/payment/use-payment-submit-gate.js +42 -14
  198. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
  199. package/dist/matter/place-order/place-order.d.ts +12 -7
  200. package/dist/matter/place-order/place-order.js +126 -103
  201. package/dist/matter/place-order/place-order.js.map +1 -1
  202. package/dist/matter/pricing/pricing.js +5 -5
  203. package/dist/matter/pricing/pricing.js.map +1 -1
  204. package/dist/matter/region/region.js +1 -1
  205. package/dist/matter/saved-cards/saved-cards.js +26 -15
  206. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  207. package/dist/matter/session/session.js +2 -2
  208. package/dist/matter/session/session.js.map +1 -1
  209. package/dist/matter/shipping-address/country-descriptors.d.ts +1 -0
  210. package/dist/matter/shipping-address/country-descriptors.js +23 -1
  211. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  212. package/dist/matter/shipping-address/shipping-address.js +62 -14
  213. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  214. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +1 -1
  215. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  216. package/dist/matter/sign-in-redirect/sign-in-redirect.js +48 -10
  217. package/dist/matter/sign-in-redirect/sign-in-redirect.js.map +1 -1
  218. package/dist/matter/variant-selector/variant-selector.js +2 -2
  219. package/dist/matter/variant-selector/variant-selector.js.map +1 -1
  220. package/dist/particles/address-summary/address-summary.js +2 -2
  221. package/dist/particles/address-summary/address-summary.js.map +1 -1
  222. package/dist/particles/alert-dialog/alert-dialog.d.ts +5 -1
  223. package/dist/particles/alert-dialog/alert-dialog.js +5 -2
  224. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -1
  225. package/dist/particles/copy-text/copy-text.d.ts +28 -0
  226. package/dist/particles/copy-text/copy-text.js +140 -0
  227. package/dist/particles/copy-text/copy-text.js.map +1 -0
  228. package/dist/particles/document-field/document-field.d.ts +34 -5
  229. package/dist/particles/document-field/document-field.js +115 -19
  230. package/dist/particles/document-field/document-field.js.map +1 -1
  231. package/dist/particles/field/field.js +1 -1
  232. package/dist/particles/field/field.js.map +1 -1
  233. package/dist/particles/footer-link-group/footer-link-group.d.ts +6 -2
  234. package/dist/particles/footer-link-group/footer-link-group.js +18 -7
  235. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
  236. package/dist/particles/incentives/incentives.d.ts +6 -2
  237. package/dist/particles/incentives/incentives.js +7 -2
  238. package/dist/particles/incentives/incentives.js.map +1 -1
  239. package/dist/particles/logo/logo.d.ts +3 -2
  240. package/dist/particles/logo/logo.js +20 -8
  241. package/dist/particles/logo/logo.js.map +1 -1
  242. package/dist/particles/navigation-link/navigation-link.d.ts +2 -3
  243. package/dist/particles/navigation-link/navigation-link.js +4 -4
  244. package/dist/particles/navigation-link/navigation-link.js.map +1 -1
  245. package/dist/particles/navigation-link-list/navigation-link-list.d.ts +6 -2
  246. package/dist/particles/navigation-link-list/navigation-link-list.js +18 -7
  247. package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -1
  248. package/dist/particles/order-details-back/order-details-back.d.ts +28 -0
  249. package/dist/particles/order-details-back/order-details-back.js +52 -0
  250. package/dist/particles/order-details-back/order-details-back.js.map +1 -0
  251. package/dist/particles/order-status-badge/order-status-badge.d.ts +19 -0
  252. package/dist/particles/order-status-badge/order-status-badge.js +50 -0
  253. package/dist/particles/order-status-badge/order-status-badge.js.map +1 -0
  254. package/dist/particles/phone-field/phone-field.js +2 -2
  255. package/dist/particles/phone-field/phone-field.js.map +1 -1
  256. package/dist/particles/select/select.js +6 -6
  257. package/dist/particles/select/select.js.map +1 -1
  258. package/dist/particles/toast/toast.d.ts +1 -1
  259. package/dist/particles/toast/toast.js +32 -6
  260. package/dist/particles/toast/toast.js.map +1 -1
  261. package/dist/schema.graphql +1014 -28
  262. package/dist/sdk/actions/address-action-provider.d.ts +16 -0
  263. package/dist/sdk/actions/address-action-provider.js +20 -0
  264. package/dist/sdk/actions/address-action-provider.js.map +1 -0
  265. package/dist/sdk/actions/analytics-action-provider.js +1 -1
  266. package/dist/sdk/actions/index.d.ts +3 -1
  267. package/dist/sdk/actions/index.js +3 -1
  268. package/dist/sdk/actions/order-action-provider.d.ts +12 -0
  269. package/dist/sdk/actions/order-action-provider.js +16 -0
  270. package/dist/sdk/actions/order-action-provider.js.map +1 -0
  271. package/dist/sdk/actions/types.d.ts +6 -2
  272. package/dist/sdk/address/address-fields.js +38 -0
  273. package/dist/sdk/address/address-fields.js.map +1 -0
  274. package/dist/sdk/address/checkout-readiness.js +17 -0
  275. package/dist/sdk/address/checkout-readiness.js.map +1 -0
  276. package/dist/sdk/address/constants.js +60 -0
  277. package/dist/sdk/address/constants.js.map +1 -0
  278. package/dist/sdk/address/country-display.js +19 -0
  279. package/dist/sdk/address/country-display.js.map +1 -0
  280. package/dist/sdk/address/country-rules.js +30 -0
  281. package/dist/sdk/address/country-rules.js.map +1 -0
  282. package/dist/sdk/address/format-address.js +18 -0
  283. package/dist/sdk/address/format-address.js.map +1 -0
  284. package/dist/sdk/address/iso-countries.js +262 -0
  285. package/dist/sdk/address/iso-countries.js.map +1 -0
  286. package/dist/sdk/address/layouts.js +56 -0
  287. package/dist/sdk/address/layouts.js.map +1 -0
  288. package/dist/sdk/address/messages.js +97 -0
  289. package/dist/sdk/address/messages.js.map +1 -0
  290. package/dist/sdk/address/operations.d.ts +54 -0
  291. package/dist/sdk/address/operations.js +83 -0
  292. package/dist/sdk/address/operations.js.map +1 -0
  293. package/dist/sdk/address/postal-code-lookup-operations.js +23 -0
  294. package/dist/sdk/address/postal-code-lookup-operations.js.map +1 -0
  295. package/dist/sdk/address/postal-code.js +11 -0
  296. package/dist/sdk/address/postal-code.js.map +1 -0
  297. package/dist/sdk/address/schema.js +14 -0
  298. package/dist/sdk/address/schema.js.map +1 -0
  299. package/dist/sdk/address/server-fields.js +25 -0
  300. package/dist/sdk/address/server-fields.js.map +1 -0
  301. package/dist/sdk/address/switch-country.js +57 -0
  302. package/dist/sdk/address/switch-country.js.map +1 -0
  303. package/dist/sdk/address/types.d.ts +26 -0
  304. package/dist/sdk/address/use-address-actions.d.ts +29 -0
  305. package/dist/sdk/address/use-address-actions.js +247 -0
  306. package/dist/sdk/address/use-address-actions.js.map +1 -0
  307. package/dist/sdk/address/use-address-by-postal-code.js +57 -0
  308. package/dist/sdk/address/use-address-by-postal-code.js.map +1 -0
  309. package/dist/sdk/address/validate-address.js +62 -0
  310. package/dist/sdk/address/validate-address.js.map +1 -0
  311. package/dist/sdk/cache/storefront-cache.js +29 -4
  312. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  313. package/dist/sdk/client/fetch-page-data.d.ts +11 -0
  314. package/dist/sdk/client/fetch-page-data.js +12 -1
  315. package/dist/sdk/client/fetch-page-data.js.map +1 -1
  316. package/dist/sdk/content/create-content-runtime.js +1 -8
  317. package/dist/sdk/content/create-content-runtime.js.map +1 -1
  318. package/dist/sdk/data/failed-fields.js +23 -0
  319. package/dist/sdk/data/failed-fields.js.map +1 -0
  320. package/dist/sdk/data/index.js +2 -2
  321. package/dist/sdk/data/page-reactive-data-root.d.ts +45 -7
  322. package/dist/sdk/data/page-reactive-data-root.js +88 -12
  323. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  324. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  325. package/dist/sdk/generated/fragment-types.js +2 -0
  326. package/dist/sdk/generated/fragment-types.js.map +1 -1
  327. package/dist/sdk/generated/gql.js +3 -1
  328. package/dist/sdk/generated/gql.js.map +1 -1
  329. package/dist/sdk/generated/graphql.d.ts +8 -0
  330. package/dist/sdk/generated/graphql.js +212 -1
  331. package/dist/sdk/generated/graphql.js.map +1 -1
  332. package/dist/sdk/i18n/messages/en-US.js +138 -1
  333. package/dist/sdk/i18n/messages/en-US.json +138 -1
  334. package/dist/sdk/i18n/messages/en-US.json.d.ts +137 -0
  335. package/dist/sdk/i18n/messages/es-ES.js +138 -1
  336. package/dist/sdk/i18n/messages/es-ES.json +138 -1
  337. package/dist/sdk/i18n/messages/pt-BR.js +138 -1
  338. package/dist/sdk/i18n/messages/pt-BR.json +138 -1
  339. package/dist/sdk/navigation/current-page.js +30 -0
  340. package/dist/sdk/navigation/current-page.js.map +1 -0
  341. package/dist/sdk/navigation/not-found-log.d.ts +28 -0
  342. package/dist/sdk/navigation/not-found-log.js +133 -0
  343. package/dist/sdk/navigation/not-found-log.js.map +1 -0
  344. package/dist/sdk/navigation/path.js +25 -0
  345. package/dist/sdk/navigation/path.js.map +1 -0
  346. package/dist/sdk/navigation/redirect.d.ts +11 -0
  347. package/dist/sdk/navigation/redirect.js +22 -0
  348. package/dist/sdk/navigation/redirect.js.map +1 -0
  349. package/dist/sdk/navigation/report.js +70 -0
  350. package/dist/sdk/navigation/report.js.map +1 -0
  351. package/dist/sdk/navigation/resolve-storefront-href.d.ts +12 -0
  352. package/dist/sdk/navigation/resolve-storefront-href.js +214 -0
  353. package/dist/sdk/navigation/resolve-storefront-href.js.map +1 -0
  354. package/dist/sdk/navigation/route-identity-provider.d.ts +11 -0
  355. package/dist/sdk/navigation/route-identity-provider.js +20 -0
  356. package/dist/sdk/navigation/route-identity-provider.js.map +1 -0
  357. package/dist/sdk/navigation/route-map-provider.d.ts +19 -0
  358. package/dist/sdk/navigation/route-map-provider.js +29 -0
  359. package/dist/sdk/navigation/route-map-provider.js.map +1 -0
  360. package/dist/sdk/navigation/storefront-link.d.ts +16 -0
  361. package/dist/sdk/navigation/storefront-link.js +66 -0
  362. package/dist/sdk/navigation/storefront-link.js.map +1 -0
  363. package/dist/sdk/navigation/types.d.ts +45 -0
  364. package/dist/sdk/navigation/use-storefront-navigation.d.ts +26 -0
  365. package/dist/sdk/navigation/use-storefront-navigation.js +73 -0
  366. package/dist/sdk/navigation/use-storefront-navigation.js.map +1 -0
  367. package/dist/sdk/navigation/use-storefront-route.d.ts +26 -0
  368. package/dist/sdk/navigation/use-storefront-route.js +87 -0
  369. package/dist/sdk/navigation/use-storefront-route.js.map +1 -0
  370. package/dist/sdk/navigation/use-storefront-search-params.d.ts +11 -0
  371. package/dist/sdk/navigation/use-storefront-search-params.js +16 -0
  372. package/dist/sdk/navigation/use-storefront-search-params.js.map +1 -0
  373. package/dist/sdk/orders/completion-badge.d.ts +8 -0
  374. package/dist/sdk/orders/completion-badge.js +47 -0
  375. package/dist/sdk/orders/completion-badge.js.map +1 -0
  376. package/dist/sdk/orders/order-operations.d.ts +19 -0
  377. package/dist/sdk/orders/order-operations.js +21 -0
  378. package/dist/sdk/orders/order-operations.js.map +1 -0
  379. package/dist/sdk/orders/use-order-actions.d.ts +23 -0
  380. package/dist/sdk/orders/use-order-actions.js +62 -0
  381. package/dist/sdk/orders/use-order-actions.js.map +1 -0
  382. package/dist/sdk/payment/gateway-origin.js +26 -13
  383. package/dist/sdk/payment/gateway-origin.js.map +1 -1
  384. package/dist/sdk/payment/gateway.d.ts +14 -2
  385. package/dist/sdk/payment/gateway.js +32 -14
  386. package/dist/sdk/payment/gateway.js.map +1 -1
  387. package/dist/sdk/payment/operations.js +11 -0
  388. package/dist/sdk/payment/operations.js.map +1 -1
  389. package/dist/sdk/payment/submission-registry.d.ts +2 -1
  390. package/dist/sdk/payment/submission-registry.js +12 -8
  391. package/dist/sdk/payment/submission-registry.js.map +1 -1
  392. package/dist/sdk/payment/use-payment-actions.d.ts +5 -3
  393. package/dist/sdk/payment/use-payment-actions.js +5 -2
  394. package/dist/sdk/payment/use-payment-actions.js.map +1 -1
  395. package/dist/sdk/payment/use-place-order.d.ts +6 -3
  396. package/dist/sdk/payment/use-place-order.js +333 -143
  397. package/dist/sdk/payment/use-place-order.js.map +1 -1
  398. package/dist/sdk/seo/page-alternates.d.ts +55 -0
  399. package/dist/sdk/seo/page-alternates.js +132 -0
  400. package/dist/sdk/seo/page-alternates.js.map +1 -0
  401. package/dist/utils/own-value.js +19 -0
  402. package/dist/utils/own-value.js.map +1 -0
  403. package/dist/utils/safe-href.d.ts +4 -4
  404. package/dist/utils/safe-href.js +31 -22
  405. package/dist/utils/safe-href.js.map +1 -1
  406. package/package.json +5 -1
  407. package/skills/storefront-asset/SKILL.md +111 -0
  408. package/skills/storefront-asset/references/api-side.md +153 -0
  409. package/skills/storefront-asset/references/findings.md +40 -0
  410. package/skills/storefront-asset/references/ui-side.md +94 -0
  411. package/src/styles/tailwind.css +27 -0
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { defineActions } from "../../core/dist/actions/registry.js";
3
+ import "../../core/dist/index.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
5
+ import { CUSTOMER_ORDER_CANCEL } from "./order-operations.js";
6
+ import { useMutation } from "@apollo/client/react";
7
+ import { useCallback, useMemo } from "react";
8
+ //#region src/sdk/orders/use-order-actions.ts
9
+ const NETWORK_RESULT = {
10
+ customerOrder: null,
11
+ userErrors: [{
12
+ code: "NETWORK_ERROR",
13
+ message: "Unable to cancel the order. Please try again."
14
+ }]
15
+ };
16
+ function cancelVariables(input) {
17
+ return {
18
+ id: input.id,
19
+ input: input.reason == null ? {} : { reason: input.reason }
20
+ };
21
+ }
22
+ function useOrderActions() {
23
+ const [cancelMutation] = useMutation(CUSTOMER_ORDER_CANCEL);
24
+ const cancel = useCallback(async (input) => {
25
+ try {
26
+ const payload = (await cancelMutation({ variables: cancelVariables(input) })).data?.customerOrderCancel;
27
+ if (!payload) return NETWORK_RESULT;
28
+ return {
29
+ customerOrder: payload.customerOrder,
30
+ userErrors: payload.userErrors
31
+ };
32
+ } catch (error) {
33
+ console.error("[order.cancel] customerOrderCancel failed", loggableErrorName(error));
34
+ return NETWORK_RESULT;
35
+ }
36
+ }, [cancelMutation]);
37
+ return useMemo(() => ({ cancel }), [cancel]);
38
+ }
39
+ defineActions({
40
+ namespace: "order",
41
+ description: "Mutation-backed cancellation of one of the shopper's orders.",
42
+ provider: {
43
+ name: "OrderActionProvider",
44
+ importPath: "@vtex/faststore/internal/client"
45
+ },
46
+ methods: { cancel: {
47
+ description: "Request cancellation of one order (async/pessimistic). Resolves the payload, including a null order after an accepted write.",
48
+ payload: [{
49
+ name: "id",
50
+ type: "string"
51
+ }, {
52
+ name: "reason",
53
+ type: "string",
54
+ optional: true
55
+ }]
56
+ } },
57
+ use: useOrderActions
58
+ });
59
+ //#endregion
60
+ export { useOrderActions };
61
+
62
+ //# sourceMappingURL=use-order-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-order-actions.js","names":[],"sources":["../../../src/sdk/orders/use-order-actions.ts"],"sourcesContent":["'use client';\n\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { CUSTOMER_ORDER_CANCEL, type OrderCancelOrder, type OrderCancelUserError } from './order-operations.js';\n\nexport type { OrderCancelOrder, OrderCancelUserError } from './order-operations.js';\n\n/**\n * The `order` action namespace. `cancel` awaits `customerOrderCancel` and returns the payload.\n * It does not throw: a typed refusal stays in `userErrors`, and a transport failure becomes one\n * `NETWORK_ERROR`. A null order with empty `userErrors` means the write was accepted and the\n * re-read failed. The order id and the reason are never logged.\n */\nexport type OrderCancelInput = Readonly<{\n id: string;\n reason?: string | null;\n}>;\n\nexport type OrderCancelResult = Readonly<{\n customerOrder: OrderCancelOrder | null;\n userErrors: readonly OrderCancelUserError[];\n}>;\n\nexport type OrderActions = Readonly<{\n cancel: (input: OrderCancelInput) => Promise<OrderCancelResult>;\n}>;\n\nconst NETWORK_ERROR: OrderCancelUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to cancel the order. Please try again.',\n};\n\nconst NETWORK_RESULT: OrderCancelResult = { customerOrder: null, userErrors: [NETWORK_ERROR] };\n\nfunction cancelVariables(input: OrderCancelInput) {\n return {\n id: input.id,\n input: input.reason == null ? {} : { reason: input.reason },\n };\n}\n\nexport function useOrderActions(): OrderActions {\n const [cancelMutation] = useMutation(CUSTOMER_ORDER_CANCEL);\n\n const cancel = useCallback<OrderActions['cancel']>(\n async (input) => {\n try {\n const result = await cancelMutation({ variables: cancelVariables(input) });\n const payload = result.data?.customerOrderCancel;\n if (!payload) return NETWORK_RESULT;\n return { customerOrder: payload.customerOrder, userErrors: payload.userErrors };\n } catch (error) {\n console.error('[order.cancel] customerOrderCancel failed', loggableErrorName(error));\n return NETWORK_RESULT;\n }\n },\n [cancelMutation],\n );\n\n return useMemo(() => ({ cancel }), [cancel]);\n}\n\nexport const orderActions = defineActions({\n namespace: 'order',\n description: \"Mutation-backed cancellation of one of the shopper's orders.\",\n provider: { name: 'OrderActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n cancel: {\n description:\n 'Request cancellation of one order (async/pessimistic). Resolves the payload, including a null order after an accepted write.',\n payload: [\n { name: 'id', type: 'string' },\n { name: 'reason', type: 'string', optional: true },\n ],\n },\n },\n use: useOrderActions,\n});\n"],"mappings":";;;;;;;;AAmCA,MAAM,iBAAoC;CAAE,eAAe;CAAM,YAAY,CAAC;EAJ5E,MAAM;EACN,SAAS;CAG+E,CAAC;AAAE;AAE7F,SAAS,gBAAgB,OAAyB;CAChD,OAAO;EACL,IAAI,MAAM;EACV,OAAO,MAAM,UAAU,OAAO,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;CAC5D;AACF;AAEA,SAAgB,kBAAgC;CAC9C,MAAM,CAAC,kBAAkB,YAAY,qBAAqB;CAE1D,MAAM,SAAS,YACb,OAAO,UAAU;EACf,IAAI;GAEF,MAAM,WAAU,MADK,eAAe,EAAE,WAAW,gBAAgB,KAAK,EAAE,CAAC,EAAA,CAClD,MAAM;GAC7B,IAAI,CAAC,SAAS,OAAO;GACrB,OAAO;IAAE,eAAe,QAAQ;IAAe,YAAY,QAAQ;GAAW;EAChF,SAAS,OAAO;GACd,QAAQ,MAAM,6CAA6C,kBAAkB,KAAK,CAAC;GACnF,OAAO;EACT;CACF,GACA,CAAC,cAAc,CACjB;CAEA,OAAO,eAAe,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC;AAC7C;AAE4B,cAAc;CACxC,WAAW;CACX,aAAa;CACb,UAAU;EAAE,MAAM;EAAuB,YAAY;CAAkC;CACvF,SAAS,EACP,QAAQ;EACN,aACE;EACF,SAAS,CACP;GAAE,MAAM;GAAM,MAAM;EAAS,GAC7B;GAAE,MAAM;GAAU,MAAM;GAAU,UAAU;EAAK,CACnD;CACF,EACF;CACA,KAAK;AACP,CAAC"}
@@ -1,33 +1,46 @@
1
1
  //#region src/sdk/payment/gateway-origin.ts
2
+ const VAULT_HOST_SUFFIX = ".vtexvault.com";
2
3
  /**
3
4
  * The one rule deciding whether a gateway origin may be interpolated into the card POST's URL
4
- * (specs/use-place-order.md, Decision 4). It lives in its own module rather than in `gateway.ts`
5
- * because `usePlaceOrder` needs it too, and that hook imports nothing executable from the module that
6
- * touches card data — a boundary its own tests assert against the file's source text.
5
+ * (specs/use-place-order.md, Decision 4; specs/route-send-payments-through-vtex-vault.md, Decision 3). It
6
+ * lives in its own module rather than in `gateway.ts` because `usePlaceOrder` needs it too, and that hook
7
+ * imports nothing executable from the module that touches card data — a boundary its own tests assert
8
+ * against the file's source text.
7
9
  *
8
10
  * `PaymentStartTransactionPayload.gatewayUrl` is nullable, and `buildGatewayPaymentsRequest`
9
- * concatenates it (`${gatewayUrl}/api/pub/transactions/…`). Three untrusted values are real rather
10
- * than hypothetical, and each produces a URL that resolves against the storefront's own origin or
11
- * sends the card in plaintext:
11
+ * concatenates it (`${gatewayUrl}/api/payments/transactions/…`). A value is trusted only when it is a
12
+ * canonical `https:` origin (the string equals what the URL parser normalises it to) made of one account
13
+ * label followed by `.vtexvault.com`, with no credentials, port, path, query, fragment, stray whitespace
14
+ * or backslash. The label's characters and length are not checked here; the host suffix is what is
15
+ * pinned. That rejects, besides every foreign host, the three values that are
16
+ * real rather than hypothetical because each produces a URL that resolves against the storefront's own
17
+ * origin or sends the card in plaintext:
12
18
  *
13
- * - `null` / `undefined` / `''` — the payload's own error shape (T18 nulls every field beside
14
- * `userErrors`), yielding a relative path.
19
+ * - `null` / `undefined` / `''` — the payload's own error shape (every field beside `userErrors` is
20
+ * nulled), yielding a relative path.
15
21
  * - the four-character string `"null"` — what `new URL('mailto:x').origin` evaluates to, so a
16
22
  * non-special scheme upstream survives a parse-only check.
17
23
  * - an `http:` origin — parses fine and sends the PAN and CVV unencrypted.
18
24
  *
19
- * The `.vtexpayments.com.br` host suffix is deliberately *not* re-checked here. T18 resolves and
20
- * validates the origin server-side and is the authoritative source; repeating the suffix in shipped
21
- * client code would add nothing against the three failures above while hard-coding a deployment
22
- * assumption a sandbox or a future gateway host would break.
25
+ * The host is pinned because VTEX documents one gateway host family for Send Payments and blocks every
26
+ * other with a 404, so a host outside it can never succeed and the only thing left to defend against is a
27
+ * backend that names one. A second gateway host (a sandbox, say) needs one more line here, on purpose.
23
28
  */
24
29
  function isTrustedGatewayOrigin(value) {
25
30
  if (!value) return false;
31
+ let url;
26
32
  try {
27
- return new URL(value).protocol === "https:";
33
+ url = new URL(value);
28
34
  } catch {
29
35
  return false;
30
36
  }
37
+ if (url.protocol !== "https:") return false;
38
+ if (url.username !== "" || url.password !== "" || url.port !== "") return false;
39
+ if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return false;
40
+ if (url.origin !== value) return false;
41
+ if (!url.hostname.endsWith(VAULT_HOST_SUFFIX)) return false;
42
+ const label = url.hostname.slice(0, -14);
43
+ return label !== "" && !label.includes(".");
31
44
  }
32
45
  //#endregion
33
46
  export { isTrustedGatewayOrigin };
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-origin.js","names":[],"sources":["../../../src/sdk/payment/gateway-origin.ts"],"sourcesContent":["/**\n * The one rule deciding whether a gateway origin may be interpolated into the card POST's URL\n * (specs/use-place-order.md, Decision 4). It lives in its own module rather than in `gateway.ts`\n * because `usePlaceOrder` needs it too, and that hook imports nothing executable from the module that\n * touches card data — a boundary its own tests assert against the file's source text.\n *\n * `PaymentStartTransactionPayload.gatewayUrl` is nullable, and `buildGatewayPaymentsRequest`\n * concatenates it (`${gatewayUrl}/api/pub/transactions/…`). Three untrusted values are real rather\n * than hypothetical, and each produces a URL that resolves against the storefront's own origin or\n * sends the card in plaintext:\n *\n * - `null` / `undefined` / `''` — the payload's own error shape (T18 nulls every field beside\n * `userErrors`), yielding a relative path.\n * - the four-character string `\"null\"` — what `new URL('mailto:x').origin` evaluates to, so a\n * non-special scheme upstream survives a parse-only check.\n * - an `http:` origin — parses fine and sends the PAN and CVV unencrypted.\n *\n * The `.vtexpayments.com.br` host suffix is deliberately *not* re-checked here. T18 resolves and\n * validates the origin server-side and is the authoritative source; repeating the suffix in shipped\n * client code would add nothing against the three failures above while hard-coding a deployment\n * assumption a sandbox or a future gateway host would break.\n */\nexport function isTrustedGatewayOrigin(value: string | null | undefined): value is string {\n if (!value) return false;\n\n try {\n return new URL(value).protocol === 'https:';\n } catch {\n // Not an absolute URL — `'/api'`, `'acme.vtexpayments.com.br'`, `'not-a-url'`.\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,uBAAuB,OAAmD;CACxF,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI;EACF,OAAO,IAAI,IAAI,KAAK,CAAC,CAAC,aAAa;CACrC,QAAQ;EAEN,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"gateway-origin.js","names":[],"sources":["../../../src/sdk/payment/gateway-origin.ts"],"sourcesContent":["const VAULT_HOST_SUFFIX = '.vtexvault.com';\n\n/**\n * The one rule deciding whether a gateway origin may be interpolated into the card POST's URL\n * (specs/use-place-order.md, Decision 4; specs/route-send-payments-through-vtex-vault.md, Decision 3). It\n * lives in its own module rather than in `gateway.ts` because `usePlaceOrder` needs it too, and that hook\n * imports nothing executable from the module that touches card data — a boundary its own tests assert\n * against the file's source text.\n *\n * `PaymentStartTransactionPayload.gatewayUrl` is nullable, and `buildGatewayPaymentsRequest`\n * concatenates it (`${gatewayUrl}/api/payments/transactions/…`). A value is trusted only when it is a\n * canonical `https:` origin (the string equals what the URL parser normalises it to) made of one account\n * label followed by `.vtexvault.com`, with no credentials, port, path, query, fragment, stray whitespace\n * or backslash. The label's characters and length are not checked here; the host suffix is what is\n * pinned. That rejects, besides every foreign host, the three values that are\n * real rather than hypothetical because each produces a URL that resolves against the storefront's own\n * origin or sends the card in plaintext:\n *\n * - `null` / `undefined` / `''` — the payload's own error shape (every field beside `userErrors` is\n * nulled), yielding a relative path.\n * - the four-character string `\"null\"` — what `new URL('mailto:x').origin` evaluates to, so a\n * non-special scheme upstream survives a parse-only check.\n * - an `http:` origin — parses fine and sends the PAN and CVV unencrypted.\n *\n * The host is pinned because VTEX documents one gateway host family for Send Payments and blocks every\n * other with a 404, so a host outside it can never succeed and the only thing left to defend against is a\n * backend that names one. A second gateway host (a sandbox, say) needs one more line here, on purpose.\n */\nexport function isTrustedGatewayOrigin(value: string | null | undefined): value is string {\n if (!value) return false;\n\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n // Not an absolute URL — `'/api'`, `'acme.vtexvault.com'`, `'not-a-url'`.\n return false;\n }\n\n if (url.protocol !== 'https:') return false;\n if (url.username !== '' || url.password !== '' || url.port !== '') return false;\n if (url.pathname !== '/' || url.search !== '' || url.hash !== '') return false;\n // The parser forgives `https://acme.vtexvault.com?`, a trailing `/`, a leading space or an explicit\n // `:443`; the concatenation in `buildGatewayPaymentsRequest` does not.\n if (url.origin !== value) return false;\n if (!url.hostname.endsWith(VAULT_HOST_SUFFIX)) return false;\n\n const label = url.hostname.slice(0, -VAULT_HOST_SUFFIX.length);\n return label !== '' && !label.includes('.');\n}\n"],"mappings":";AAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B1B,SAAgB,uBAAuB,OAAmD;CACxF,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,KAAK;CACrB,QAAQ;EAEN,OAAO;CACT;CAEA,IAAI,IAAI,aAAa,UAAU,OAAO;CACtC,IAAI,IAAI,aAAa,MAAM,IAAI,aAAa,MAAM,IAAI,SAAS,IAAI,OAAO;CAC1E,IAAI,IAAI,aAAa,OAAO,IAAI,WAAW,MAAM,IAAI,SAAS,IAAI,OAAO;CAGzE,IAAI,IAAI,WAAW,OAAO,OAAO;CACjC,IAAI,CAAC,IAAI,SAAS,SAAS,iBAAiB,GAAG,OAAO;CAEtD,MAAM,QAAQ,IAAI,SAAS,MAAM,GAAG,GAAyB;CAC7D,OAAO,UAAU,MAAM,CAAC,MAAM,SAAS,GAAG;AAC5C"}
@@ -1,4 +1,4 @@
1
- import "./operations.js";
1
+ import { PaymentUserError } from "./operations.js";
2
2
  //#region src/sdk/payment/gateway.d.ts
3
3
  /**
4
4
  * Non-sensitive descriptor of the open transaction. Every field maps to a value the caller already
@@ -9,7 +9,7 @@ import "./operations.js";
9
9
  */
10
10
  export type PaymentGatewayTransaction = Readonly<{
11
11
  /**
12
- * Gateway origin, e.g. `https://acme.vtexpayments.com.br`. Server-resolved by T18 and read off
12
+ * Gateway origin, e.g. `https://acme.vtexvault.com`. Server-resolved by T18 and read off
13
13
  * `paymentStartTransaction`'s payload; never derived here. It is nullable there and required here,
14
14
  * so the builder re-checks it (`isTrustedGatewayOrigin`) rather than trusting the type.
15
15
  */
@@ -81,5 +81,17 @@ export type SendPaymentsRequest = Readonly<{
81
81
  transaction: PaymentGatewayTransaction;
82
82
  card: PaymentGatewayCard;
83
83
  }>;
84
+ /**
85
+ * What a card POST resolves (T112). `reachedGateway` is `false` only when this module can show no request
86
+ * was issued — the request builder refused before any `fetch`. Anything it cannot classify (a rejection, a
87
+ * timeout, an abort, a malformed result) is `true`: a browser cannot tell whether a request that never
88
+ * answered was processed, and a `false` frees the shopper to post the card again. Beside it, `userErrors`
89
+ * keeps the `{ ..., userErrors }` payload shape (ADR-00005); it carries no card value.
90
+ */
91
+ export type PaymentGatewayResult = Readonly<{
92
+ /** false only when no request was issued to the gateway. Anything unclassified is true. */
93
+ reachedGateway: boolean;
94
+ userErrors: readonly PaymentUserError[];
95
+ }>;
84
96
  //#endregion
85
97
  //# sourceMappingURL=gateway.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
1
2
  import { isTrustedGatewayOrigin } from "./gateway-origin.js";
2
3
  //#region src/sdk/payment/gateway.ts
3
4
  /**
@@ -22,7 +23,7 @@ import { isTrustedGatewayOrigin } from "./gateway-origin.js";
22
23
  */
23
24
  /** Client-synthesized code for a failed gateway leg — distinct from the BFF's `NETWORK_ERROR`. */
24
25
  const PAYMENT_GATEWAY_ERROR_CODE = "GATEWAY_ERROR";
25
- /** The single userError both a rejected request and a non-2xx response resolve to. */
26
+ /** The single userError a rejected request, a non-2xx response and a request the builder refused all resolve to. */
26
27
  const PAYMENT_GATEWAY_USER_ERROR = {
27
28
  code: PAYMENT_GATEWAY_ERROR_CODE,
28
29
  message: "Unable to complete the payment. Please try again."
@@ -85,7 +86,8 @@ function buildGatewayPaymentsRequest({ transaction, card }) {
85
86
  const params = new URLSearchParams({ orderId: transaction.orderGroup });
86
87
  if (transaction.userProfileId !== null) params.append("userProfileId", transaction.userProfileId);
87
88
  if (transaction.callbackUrl !== void 0) params.append("callbackUrl", transaction.callbackUrl);
88
- const url = `${transaction.gatewayUrl}/api/pub/transactions/${transaction.transactionId}/payments?${params}`;
89
+ const transactionId = encodeURIComponent(transaction.transactionId);
90
+ const url = `${transaction.gatewayUrl}/api/payments/transactions/${transactionId}/payments?${params}`;
89
91
  const { bin, fields } = toCardBody(card);
90
92
  const billingAddressDifferent = transaction.billingAddressDifferent ?? false;
91
93
  return {
@@ -136,11 +138,14 @@ function buildGatewayPaymentsRequest({ transaction, card }) {
136
138
  */
137
139
  const GATEWAY_REQUEST_TIMEOUT_MS = 3e4;
138
140
  /**
139
- * Posts the card straight to the gateway and resolves the gateway leg's `userErrors` (empty on success).
140
- * A non-2xx response resolves one `GATEWAY_ERROR`; a rejected request — including this leg's own
141
- * timeout firing, or `options.signal` aborting — propagates, and the handler in `use-payment-actions.ts`
142
- * collapses it to the same one. Neither outcome reads the response body: it may echo the request, and
143
- * it tells the shopper nothing more actionable than "try again".
141
+ * Posts the card straight to the gateway and resolves a `PaymentGatewayResult`. A non-2xx response
142
+ * resolves `{ reachedGateway: true, userErrors: [GATEWAY_ERROR] }`; a request the builder refuses
143
+ * (an untrusted origin, a malformed card) resolves `{ reachedGateway: false, userErrors: [GATEWAY_ERROR] }`
144
+ * without issuing a `fetch` or arming a timer, logging only the error's name. A rejected request —
145
+ * including this leg's own timeout firing, or `options.signal` aborting — propagates, and the handler in
146
+ * `use-payment-actions.ts` collapses it to a `reachedGateway: true` result: nothing here can prove it
147
+ * never left. Neither outcome reads the response body: it may echo the request, and it tells the shopper
148
+ * nothing more actionable than "try again".
144
149
  *
145
150
  * `options.signal`, when given, aborts this request in *addition to* — never instead of — this module's
146
151
  * own timeout: a caller opts into an earlier or externally triggered abort, but cannot opt out of the
@@ -156,7 +161,17 @@ const GATEWAY_REQUEST_TIMEOUT_MS = 3e4;
156
161
  * dead `AbortController`, per call that resolved normally.
157
162
  */
158
163
  async function postPaymentsToGateway(request, options) {
159
- const { url, body } = buildGatewayPaymentsRequest(request);
164
+ let built;
165
+ try {
166
+ built = buildGatewayPaymentsRequest(request);
167
+ } catch (error) {
168
+ console.error("[payment.sendPayments] the gateway request was refused before it was sent", loggableErrorName(error));
169
+ return {
170
+ reachedGateway: false,
171
+ userErrors: [PAYMENT_GATEWAY_USER_ERROR]
172
+ };
173
+ }
174
+ const { url, body } = built;
160
175
  const controller = new AbortController();
161
176
  const timeoutId = setTimeout(() => controller.abort(new DOMException("The gateway request timed out.", "TimeoutError")), GATEWAY_REQUEST_TIMEOUT_MS);
162
177
  const externalSignal = options?.signal;
@@ -166,12 +181,15 @@ async function postPaymentsToGateway(request, options) {
166
181
  else externalSignal.addEventListener("abort", onExternalAbort, { once: true });
167
182
  }
168
183
  try {
169
- return (await fetch(url, {
170
- method: "POST",
171
- headers: { "Content-Type": "application/json" },
172
- body: JSON.stringify(body),
173
- signal: controller.signal
174
- })).ok ? [] : [PAYMENT_GATEWAY_USER_ERROR];
184
+ return {
185
+ reachedGateway: true,
186
+ userErrors: (await fetch(url, {
187
+ method: "POST",
188
+ headers: { "Content-Type": "application/json" },
189
+ body: JSON.stringify(body),
190
+ signal: controller.signal
191
+ })).ok ? [] : [PAYMENT_GATEWAY_USER_ERROR]
192
+ };
175
193
  } finally {
176
194
  clearTimeout(timeoutId);
177
195
  externalSignal?.removeEventListener("abort", onExternalAbort);
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","names":[],"sources":["../../../src/sdk/payment/gateway.ts"],"sourcesContent":["/**\n * The direct-to-gateway card POST (specs/payment-action-namespace.md, US-6) — the PCI boundary of the\n * credit-card feature. A new card's number and CVV, or a saved card's CVV, go from the browser straight\n * to the VTEX payment gateway and never transit our GraphQL layer or the normalized Apollo cache\n * (RFC D13; ADR-0010's sanctioned façade flavor).\n *\n * This module imports no Apollo and no GraphQL symbol on purpose: the code that holds card data has no\n * route to the cache, and that property is checkable by reading the imports above. Card data arrives as\n * a runtime argument from the card-entry component's local state (T7) — it is never a declared action\n * payload, a fragment field, or a schema-bindable prop, so the AI Store Builder and the visual editor\n * have no name to map a value onto.\n *\n * Nothing on this path is ever logged, serialized, or stored anywhere but the request body: the caller\n * in `use-payment-actions.ts` logs a static message plus the error's `name` only.\n *\n * The request shape is behavior evidence from the legacy checkout\n * (`fastcheckout@cd09bec3`, `packages/apps/client/src/screens/Payment/components/CardForm/services/gateway.service.ts`)\n * — never a port. Where the legacy hardcoded a value under a `TODO` (installment count, interest rate,\n * reference value) this builder reads it off the transaction descriptor instead.\n */\n\nimport { isTrustedGatewayOrigin } from './gateway-origin.js';\nimport type { PaymentUserError } from './operations.js';\n\n/** Client-synthesized code for a failed gateway leg — distinct from the BFF's `NETWORK_ERROR`. */\nexport const PAYMENT_GATEWAY_ERROR_CODE = 'GATEWAY_ERROR';\n\n/** The single userError both a rejected request and a non-2xx response resolve to. */\nexport const PAYMENT_GATEWAY_USER_ERROR: PaymentUserError = {\n code: PAYMENT_GATEWAY_ERROR_CODE,\n message: 'Unable to complete the payment. Please try again.',\n};\n\n/**\n * Non-sensitive descriptor of the open transaction. Every field maps to a value the caller already\n * holds — `paymentStartTransaction`'s payload (T3) or the `Payment` read model (T1) — except\n * `gatewayUrl` and `merchantName`, which that payload does not carry today (Gaps 1 and 2 in the spec).\n * Amounts are in the currency's **minor units**; `PaymentStartTransactionPayload.value.amount` is a\n * decimal, so the caller converts once, visibly, rather than having this module assume an exponent.\n */\nexport type PaymentGatewayTransaction = Readonly<{\n /**\n * Gateway origin, e.g. `https://acme.vtexpayments.com.br`. Server-resolved by T18 and read off\n * `paymentStartTransaction`'s payload; never derived here. It is nullable there and required here,\n * so the builder re-checks it (`isTrustedGatewayOrigin`) rather than trusting the type.\n */\n gatewayUrl: string;\n /** `PaymentStartTransactionPayload.transactionId`. */\n transactionId: string;\n /** VTEX merchant name for this transaction. Resolved server-side by T3 but not exposed on its payload. */\n merchantName: string;\n /** `PaymentStartTransactionPayload.orderGroup` — the gateway's `orderId` query parameter. */\n orderGroup: string;\n /** `PaymentStartTransactionPayload.userProfileId`; null for a guest order, so the query parameter is left out. */\n userProfileId: string | null;\n /** `Payment.selectedMethodId` — the VTEX payment-system id. */\n paymentSystem: string;\n /** `PaymentMethod.groupName`, e.g. `creditCardPaymentGroup`. */\n groupName: string;\n /** `PaymentStartTransactionPayload.value.currencyCode`. */\n currencyCode: string;\n /** Transaction total, in minor units. */\n valueInCents: number;\n /** Pre-interest base (`PaymentInstallmentOption.baseValue`), in minor units. */\n referenceValueInCents: number;\n /** `Payment.selectedInstallment.count`; 1 when the shopper never picked a plan. */\n installments: number;\n /** Per-installment amount (`PaymentInstallment.value`), in minor units. */\n installmentsValueInCents: number;\n /** `PaymentInstallment.interestRate`; 0 for the interest-free 1x default. */\n interestRate: number;\n /** Absolute return URL. Phase-2 redirect mode only; omitted in v1's direct mode. */\n callbackUrl?: string;\n /**\n * Billing differs from the delivery address. Defaults to `false`, because `setBillingAddress` persists\n * billing on the order form's `invoiceData` (T3) and the gateway reads it from there rather than from\n * this body. The call site that would override it is T13's `usePlaceOrder`, the one place the\n * descriptor is assembled; T11 owns the live verification of the assumption and publishes the flag to\n * T5's `draft` for T13 to read. Confirming it never reopens this module.\n */\n billingAddressDifferent?: boolean;\n}>;\n\n/** A newly entered card. Runtime argument only — never declared, never logged, never cached. */\nexport type PaymentGatewayNewCard = Readonly<{\n kind: 'new';\n /** Full card number. The builder strips whatever separators the method's `numberMask` inserted. */\n number: string;\n /** Security code (CVV). */\n securityCode: string;\n /** Expiry. Normalized to `MM/YY`, so a `MM/YYYY` mask is accepted. */\n expirationDate: string;\n holderName: string;\n /** Shopper document (a CPF). The builder strips its punctuation. */\n document?: string;\n /** Shopper-assigned label, when the save-card control collected one. */\n cardLabel?: string;\n /** The card-save flag itself — the other half of `payment.saveCard`'s consent write (RFC D5). */\n saveCard?: boolean;\n}>;\n\n/** A previously saved card: its account reference plus the CVV the shopper re-enters. */\nexport type PaymentGatewaySavedCard = Readonly<{\n kind: 'saved';\n /** `SavedCard.accountId`. */\n accountId: string;\n /** `SavedCard.bin` — not sensitive; the read model exposes it for installment lookup. */\n bin: string;\n /** Security code (CVV). */\n securityCode: string;\n}>;\n\nexport type PaymentGatewayCard = PaymentGatewayNewCard | PaymentGatewaySavedCard;\n\nexport type SendPaymentsRequest = Readonly<{\n transaction: PaymentGatewayTransaction;\n card: PaymentGatewayCard;\n}>;\n\n/** The assembled request. Exported so the body shape is unit-testable without issuing a POST. */\nexport type GatewayPaymentsRequest = Readonly<{ url: string; body: readonly unknown[] }>;\n\n/** VTEX bins the leading eight digits, not six — the legacy's own `sanitizedBin` slice. */\nconst BIN_LENGTH = 8;\n\n/**\n * Strips the separators a mask inserted. `PaymentMethodValidator.numberMask` is server-driven (T1) and the\n * card-entry component (T7) renders the input through it, so its local state holds `4111 1111 1111 1111`\n * rather than the digits. The legacy normalized here, in the builder, before its own BIN slice\n * (`card.cardNumber = card.cardNumber.replace(/ /g, '')`) — the boundary is the one place the obligation\n * cannot be forgotten, and a spaced BIN is a lookup the gateway fails with no diagnosable error.\n */\nfunction toDigits(value: string): string {\n return value.replace(/\\D/g, '');\n}\n\n/** `MM/YY` whatever the mask produced (`MM/YYYY`, `MMYY`) — the legacy's own two-slice normalization. */\nfunction toDueDate(expirationDate: string): string {\n const digits = toDigits(expirationDate);\n return `${digits.slice(0, 2)}/${digits.slice(-2)}`;\n}\n\n/** The card half of the body — the BIN and the `fields` map, both derived from one normalization pass. */\nfunction toCardBody(card: PaymentGatewayCard): { bin: string; fields: Record<string, unknown> } {\n if (card.kind === 'saved') {\n return { bin: card.bin, fields: { bin: card.bin, validationCode: card.securityCode } };\n }\n\n const number = toDigits(card.number);\n const bin = number.slice(0, BIN_LENGTH);\n\n return {\n bin,\n fields: {\n bin,\n cardNumber: number,\n // The legacy's own `\\W` strip, so a CPF typed `123.456.789-00` reaches the gateway unpunctuated.\n document: card.document === undefined ? null : card.document.replace(/\\W/g, ''),\n dueDate: toDueDate(card.expirationDate),\n holderName: card.holderName,\n validationCode: card.securityCode,\n cardLabel: card.cardLabel,\n savePaymentData: card.saveCard ?? false,\n },\n };\n}\n\n/**\n * Builds the gateway URL and body. Billing is deliberately absent from the body: `setBillingAddress`\n * already persisted it on the order form's `invoiceData` (T3), so the gateway reads it from there — hence\n * the `billingAddressDifferent: false` default the two billing flags derive from. `originalPaymentIndex`\n * is the legacy's own constant for a single-payment order.\n *\n * The origin check is the last line of defence, not the first: `usePlaceOrder` already refuses an\n * untrusted origin *before* asking a holder for the card (T13, Decision 4). A builder has no userError\n * channel, so it throws — `sendPayments` catches, collapses it to `GATEWAY_ERROR`, and logs the error's\n * name only, so nothing about the card reaches a log. The throw happens before the body is assembled.\n */\nexport function buildGatewayPaymentsRequest({ transaction, card }: SendPaymentsRequest): GatewayPaymentsRequest {\n if (!isTrustedGatewayOrigin(transaction.gatewayUrl)) {\n throw new Error('Refusing to post card data: the transaction carries no trusted https gateway origin.');\n }\n\n const params = new URLSearchParams({ orderId: transaction.orderGroup });\n if (transaction.userProfileId !== null) params.append('userProfileId', transaction.userProfileId);\n if (transaction.callbackUrl !== undefined) params.append('callbackUrl', transaction.callbackUrl);\n\n const url = `${transaction.gatewayUrl}/api/pub/transactions/${transaction.transactionId}/payments?${params}`;\n\n const { bin, fields } = toCardBody(card);\n const billingAddressDifferent = transaction.billingAddressDifferent ?? false;\n\n const payment = {\n accountId: card.kind === 'saved' ? card.accountId : null,\n bin,\n chooseToUseNewCard: card.kind === 'new',\n currencyCode: transaction.currencyCode,\n fields,\n groupName: transaction.groupName,\n hasDefaultBillingAddress: !billingAddressDifferent,\n id: transaction.merchantName,\n installmentValue: transaction.installmentsValueInCents,\n installments: transaction.installments,\n installmentsInterestRate: transaction.interestRate,\n installmentsValue: transaction.installmentsValueInCents,\n interestRate: transaction.interestRate,\n isBillingAddressDifferent: billingAddressDifferent,\n originalPaymentIndex: 1,\n paymentSystem: transaction.paymentSystem,\n referenceValue: transaction.referenceValueInCents,\n tokenId: null,\n transaction: { id: transaction.transactionId, merchantName: transaction.merchantName },\n value: transaction.valueInCents,\n };\n\n return { url, body: [payment] };\n}\n\n/**\n * T29 (FR-6, OQ-7): this leg's own abort budget. Before this task the direct-to-gateway POST carried no\n * `AbortSignal` and no timeout at all, so a gateway that never answered left `placing` true and the CTA\n * dead for the life of the mount (Route C, `place-order.md`'s Known limitations). The BFF's own default\n * is 10s (`apps/storefront-api-core/.../api-timeout.ts:9`), but a card authorization can legitimately\n * run longer than a GraphQL round trip, and this exact number is not confirmed with payments (spec\n * OQ-7) — a placeholder pending that answer, not a tuned production value.\n *\n * Exported so `gateway.test.ts`'s own abort-budget test can assert the abort fires at exactly this\n * duration, rather than against `vi.runAllTimersAsync()`, which fires any pending timer regardless of\n * duration and would stay green even if this were edited to `300_000`. That mechanism test alone is\n * still self-referential about this constant's own *value* — it advances the fake clock by whatever\n * `GATEWAY_REQUEST_TIMEOUT_MS` currently holds, so on its own it cannot catch an edit to the constant\n * either (fix round 2, verification finding V2). `gateway.test.ts` also asserts this constant against\n * the literal `30_000` directly, in its own dedicated test — that is what actually fails if this\n * constant's value ever changes.\n */\nexport const GATEWAY_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * Posts the card straight to the gateway and resolves the gateway leg's `userErrors` (empty on success).\n * A non-2xx response resolves one `GATEWAY_ERROR`; a rejected request — including this leg's own\n * timeout firing, or `options.signal` aborting — propagates, and the handler in `use-payment-actions.ts`\n * collapses it to the same one. Neither outcome reads the response body: it may echo the request, and\n * it tells the shopper nothing more actionable than \"try again\".\n *\n * `options.signal`, when given, aborts this request in *addition to* — never instead of — this module's\n * own timeout: a caller opts into an earlier or externally triggered abort, but cannot opt out of the\n * budget that keeps this leg from hanging forever (FR-6, US-3). Composed with a plain `AbortController`\n * rather than `AbortSignal.any`/`AbortSignal.timeout` so the timeout is driven by an ordinary\n * `setTimeout`, the one implementation a test can advance deterministically with fake timers.\n *\n * No caller in this package passes `options.signal` today — it exists to satisfy the spec's own\n * Technical Contract (`specs/make-an-order-attempt-survive-a.md`) ahead of a future integration. Fix\n * pass, Low finding: the listener this composes onto `externalSignal` is now removed in the `finally`\n * below on every exit path, not only when it fires — previously, a caller that supplied a long-lived\n * signal (as opposed to a fresh one per call) would accumulate one listener, and this function's own\n * dead `AbortController`, per call that resolved normally.\n */\nexport async function postPaymentsToGateway(\n request: SendPaymentsRequest,\n options?: { signal?: AbortSignal },\n): Promise<readonly PaymentUserError[]> {\n const { url, body } = buildGatewayPaymentsRequest(request);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new DOMException('The gateway request timed out.', 'TimeoutError')),\n GATEWAY_REQUEST_TIMEOUT_MS,\n );\n const externalSignal = options?.signal;\n const onExternalAbort = () => controller.abort(externalSignal?.reason);\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort(externalSignal.reason);\n } else {\n externalSignal.addEventListener('abort', onExternalAbort, { once: true });\n }\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n return response.ok ? [] : [PAYMENT_GATEWAY_USER_ERROR];\n } finally {\n clearTimeout(timeoutId);\n externalSignal?.removeEventListener('abort', onExternalAbort);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,6BAA6B;;AAG1C,MAAa,6BAA+C;CAC1D,MAAM;CACN,SAAS;AACX;;AA4FA,MAAM,aAAa;;;;;;;;AASnB,SAAS,SAAS,OAAuB;CACvC,OAAO,MAAM,QAAQ,OAAO,EAAE;AAChC;;AAGA,SAAS,UAAU,gBAAgC;CACjD,MAAM,SAAS,SAAS,cAAc;CACtC,OAAO,GAAG,OAAO,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,EAAE;AACjD;;AAGA,SAAS,WAAW,MAA4E;CAC9F,IAAI,KAAK,SAAS,SAChB,OAAO;EAAE,KAAK,KAAK;EAAK,QAAQ;GAAE,KAAK,KAAK;GAAK,gBAAgB,KAAK;EAAa;CAAE;CAGvF,MAAM,SAAS,SAAS,KAAK,MAAM;CACnC,MAAM,MAAM,OAAO,MAAM,GAAG,UAAU;CAEtC,OAAO;EACL;EACA,QAAQ;GACN;GACA,YAAY;GAEZ,UAAU,KAAK,aAAa,KAAA,IAAY,OAAO,KAAK,SAAS,QAAQ,OAAO,EAAE;GAC9E,SAAS,UAAU,KAAK,cAAc;GACtC,YAAY,KAAK;GACjB,gBAAgB,KAAK;GACrB,WAAW,KAAK;GAChB,iBAAiB,KAAK,YAAY;EACpC;CACF;AACF;;;;;;;;;;;;AAaA,SAAgB,4BAA4B,EAAE,aAAa,QAAqD;CAC9G,IAAI,CAAC,uBAAuB,YAAY,UAAU,GAChD,MAAM,IAAI,MAAM,sFAAsF;CAGxG,MAAM,SAAS,IAAI,gBAAgB,EAAE,SAAS,YAAY,WAAW,CAAC;CACtE,IAAI,YAAY,kBAAkB,MAAM,OAAO,OAAO,iBAAiB,YAAY,aAAa;CAChG,IAAI,YAAY,gBAAgB,KAAA,GAAW,OAAO,OAAO,eAAe,YAAY,WAAW;CAE/F,MAAM,MAAM,GAAG,YAAY,WAAW,wBAAwB,YAAY,cAAc,YAAY;CAEpG,MAAM,EAAE,KAAK,WAAW,WAAW,IAAI;CACvC,MAAM,0BAA0B,YAAY,2BAA2B;CAyBvE,OAAO;EAAE;EAAK,MAAM,CAAC;GAtBnB,WAAW,KAAK,SAAS,UAAU,KAAK,YAAY;GACpD;GACA,oBAAoB,KAAK,SAAS;GAClC,cAAc,YAAY;GAC1B;GACA,WAAW,YAAY;GACvB,0BAA0B,CAAC;GAC3B,IAAI,YAAY;GAChB,kBAAkB,YAAY;GAC9B,cAAc,YAAY;GAC1B,0BAA0B,YAAY;GACtC,mBAAmB,YAAY;GAC/B,cAAc,YAAY;GAC1B,2BAA2B;GAC3B,sBAAsB;GACtB,eAAe,YAAY;GAC3B,gBAAgB,YAAY;GAC5B,SAAS;GACT,aAAa;IAAE,IAAI,YAAY;IAAe,cAAc,YAAY;GAAa;GACrF,OAAO,YAAY;EAGM,CAAC;CAAE;AAChC;;;;;;;;;;;;;;;;;;AAmBA,MAAa,6BAA6B;;;;;;;;;;;;;;;;;;;;;AAsB1C,eAAsB,sBACpB,SACA,SACsC;CACtC,MAAM,EAAE,KAAK,SAAS,4BAA4B,OAAO;CAEzD,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,YAAY,iBACV,WAAW,MAAM,IAAI,aAAa,kCAAkC,cAAc,CAAC,GACzF,0BACF;CACA,MAAM,iBAAiB,SAAS;CAChC,MAAM,wBAAwB,WAAW,MAAM,gBAAgB,MAAM;CACrE,IAAI,gBAAgB;EAClB,IAAI,eAAe,SACjB,WAAW,MAAM,eAAe,MAAM;OAEtC,eAAe,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,KAAK,CAAC;CAE5E;CAEA,IAAI;EAQF,QAAO,MAPgB,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU,IAAI;GACzB,QAAQ,WAAW;EACrB,CAAC,EAAA,CAEe,KAAK,CAAC,IAAI,CAAC,0BAA0B;CACvD,UAAU;EACR,aAAa,SAAS;EACtB,gBAAgB,oBAAoB,SAAS,eAAe;CAC9D;AACF"}
1
+ {"version":3,"file":"gateway.js","names":[],"sources":["../../../src/sdk/payment/gateway.ts"],"sourcesContent":["/**\n * The direct-to-gateway card POST (specs/payment-action-namespace.md, US-6) — the PCI boundary of the\n * credit-card feature. A new card's number and CVV, or a saved card's CVV, go from the browser straight\n * to the VTEX payment gateway and never transit our GraphQL layer or the normalized Apollo cache\n * (RFC D13; ADR-0010's sanctioned façade flavor).\n *\n * This module imports no Apollo and no GraphQL symbol on purpose: the code that holds card data has no\n * route to the cache, and that property is checkable by reading the imports above. Card data arrives as\n * a runtime argument from the card-entry component's local state (T7) — it is never a declared action\n * payload, a fragment field, or a schema-bindable prop, so the AI Store Builder and the visual editor\n * have no name to map a value onto.\n *\n * Nothing on this path is ever logged, serialized, or stored anywhere but the request body: the caller\n * in `use-payment-actions.ts` logs a static message plus the error's `name` only.\n *\n * The request shape is behavior evidence from the legacy checkout\n * (`fastcheckout@cd09bec3`, `packages/apps/client/src/screens/Payment/components/CardForm/services/gateway.service.ts`)\n * — never a port. Where the legacy hardcoded a value under a `TODO` (installment count, interest rate,\n * reference value) this builder reads it off the transaction descriptor instead.\n */\n\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { isTrustedGatewayOrigin } from './gateway-origin.js';\nimport type { PaymentUserError } from './operations.js';\n\n/** Client-synthesized code for a failed gateway leg — distinct from the BFF's `NETWORK_ERROR`. */\nexport const PAYMENT_GATEWAY_ERROR_CODE = 'GATEWAY_ERROR';\n\n/** The single userError a rejected request, a non-2xx response and a request the builder refused all resolve to. */\nexport const PAYMENT_GATEWAY_USER_ERROR: PaymentUserError = {\n code: PAYMENT_GATEWAY_ERROR_CODE,\n message: 'Unable to complete the payment. Please try again.',\n};\n\n/**\n * Non-sensitive descriptor of the open transaction. Every field maps to a value the caller already\n * holds — `paymentStartTransaction`'s payload (T3) or the `Payment` read model (T1) — except\n * `gatewayUrl` and `merchantName`, which that payload does not carry today (Gaps 1 and 2 in the spec).\n * Amounts are in the currency's **minor units**; `PaymentStartTransactionPayload.value.amount` is a\n * decimal, so the caller converts once, visibly, rather than having this module assume an exponent.\n */\nexport type PaymentGatewayTransaction = Readonly<{\n /**\n * Gateway origin, e.g. `https://acme.vtexvault.com`. Server-resolved by T18 and read off\n * `paymentStartTransaction`'s payload; never derived here. It is nullable there and required here,\n * so the builder re-checks it (`isTrustedGatewayOrigin`) rather than trusting the type.\n */\n gatewayUrl: string;\n /** `PaymentStartTransactionPayload.transactionId`. */\n transactionId: string;\n /** VTEX merchant name for this transaction. Resolved server-side by T3 but not exposed on its payload. */\n merchantName: string;\n /** `PaymentStartTransactionPayload.orderGroup` — the gateway's `orderId` query parameter. */\n orderGroup: string;\n /** `PaymentStartTransactionPayload.userProfileId`; null for a guest order, so the query parameter is left out. */\n userProfileId: string | null;\n /** `Payment.selectedMethodId` — the VTEX payment-system id. */\n paymentSystem: string;\n /** `PaymentMethod.groupName`, e.g. `creditCardPaymentGroup`. */\n groupName: string;\n /** `PaymentStartTransactionPayload.value.currencyCode`. */\n currencyCode: string;\n /** Transaction total, in minor units. */\n valueInCents: number;\n /** Pre-interest base (`PaymentInstallmentOption.baseValue`), in minor units. */\n referenceValueInCents: number;\n /** `Payment.selectedInstallment.count`; 1 when the shopper never picked a plan. */\n installments: number;\n /** Per-installment amount (`PaymentInstallment.value`), in minor units. */\n installmentsValueInCents: number;\n /** `PaymentInstallment.interestRate`; 0 for the interest-free 1x default. */\n interestRate: number;\n /** Absolute return URL. Phase-2 redirect mode only; omitted in v1's direct mode. */\n callbackUrl?: string;\n /**\n * Billing differs from the delivery address. Defaults to `false`, because `setBillingAddress` persists\n * billing on the order form's `invoiceData` (T3) and the gateway reads it from there rather than from\n * this body. The call site that would override it is T13's `usePlaceOrder`, the one place the\n * descriptor is assembled; T11 owns the live verification of the assumption and publishes the flag to\n * T5's `draft` for T13 to read. Confirming it never reopens this module.\n */\n billingAddressDifferent?: boolean;\n}>;\n\n/** A newly entered card. Runtime argument only — never declared, never logged, never cached. */\nexport type PaymentGatewayNewCard = Readonly<{\n kind: 'new';\n /** Full card number. The builder strips whatever separators the method's `numberMask` inserted. */\n number: string;\n /** Security code (CVV). */\n securityCode: string;\n /** Expiry. Normalized to `MM/YY`, so a `MM/YYYY` mask is accepted. */\n expirationDate: string;\n holderName: string;\n /** Shopper document (a CPF). The builder strips its punctuation. */\n document?: string;\n /** Shopper-assigned label, when the save-card control collected one. */\n cardLabel?: string;\n /** The card-save flag itself — the other half of `payment.saveCard`'s consent write (RFC D5). */\n saveCard?: boolean;\n}>;\n\n/** A previously saved card: its account reference plus the CVV the shopper re-enters. */\nexport type PaymentGatewaySavedCard = Readonly<{\n kind: 'saved';\n /** `SavedCard.accountId`. */\n accountId: string;\n /** `SavedCard.bin` — not sensitive; the read model exposes it for installment lookup. */\n bin: string;\n /** Security code (CVV). */\n securityCode: string;\n}>;\n\nexport type PaymentGatewayCard = PaymentGatewayNewCard | PaymentGatewaySavedCard;\n\nexport type SendPaymentsRequest = Readonly<{\n transaction: PaymentGatewayTransaction;\n card: PaymentGatewayCard;\n}>;\n\n/** The assembled request. Exported so the body shape is unit-testable without issuing a POST. */\nexport type GatewayPaymentsRequest = Readonly<{ url: string; body: readonly unknown[] }>;\n\n/** VTEX bins the leading eight digits, not six — the legacy's own `sanitizedBin` slice. */\nconst BIN_LENGTH = 8;\n\n/**\n * Strips the separators a mask inserted. `PaymentMethodValidator.numberMask` is server-driven (T1) and the\n * card-entry component (T7) renders the input through it, so its local state holds `4111 1111 1111 1111`\n * rather than the digits. The legacy normalized here, in the builder, before its own BIN slice\n * (`card.cardNumber = card.cardNumber.replace(/ /g, '')`) — the boundary is the one place the obligation\n * cannot be forgotten, and a spaced BIN is a lookup the gateway fails with no diagnosable error.\n */\nfunction toDigits(value: string): string {\n return value.replace(/\\D/g, '');\n}\n\n/** `MM/YY` whatever the mask produced (`MM/YYYY`, `MMYY`) — the legacy's own two-slice normalization. */\nfunction toDueDate(expirationDate: string): string {\n const digits = toDigits(expirationDate);\n return `${digits.slice(0, 2)}/${digits.slice(-2)}`;\n}\n\n/** The card half of the body — the BIN and the `fields` map, both derived from one normalization pass. */\nfunction toCardBody(card: PaymentGatewayCard): { bin: string; fields: Record<string, unknown> } {\n if (card.kind === 'saved') {\n return { bin: card.bin, fields: { bin: card.bin, validationCode: card.securityCode } };\n }\n\n const number = toDigits(card.number);\n const bin = number.slice(0, BIN_LENGTH);\n\n return {\n bin,\n fields: {\n bin,\n cardNumber: number,\n // The legacy's own `\\W` strip, so a CPF typed `123.456.789-00` reaches the gateway unpunctuated.\n document: card.document === undefined ? null : card.document.replace(/\\W/g, ''),\n dueDate: toDueDate(card.expirationDate),\n holderName: card.holderName,\n validationCode: card.securityCode,\n cardLabel: card.cardLabel,\n savePaymentData: card.saveCard ?? false,\n },\n };\n}\n\n/**\n * Builds the gateway URL and body. Billing is deliberately absent from the body: `setBillingAddress`\n * already persisted it on the order form's `invoiceData` (T3), so the gateway reads it from there — hence\n * the `billingAddressDifferent: false` default the two billing flags derive from. `originalPaymentIndex`\n * is the legacy's own constant for a single-payment order.\n *\n * The origin check is the last line of defence, not the first: `usePlaceOrder` already refuses an\n * untrusted origin *before* asking a holder for the card (T13, Decision 4). A builder has no userError\n * channel, so it throws — `sendPayments` catches, collapses it to `GATEWAY_ERROR`, and logs the error's\n * name only, so nothing about the card reaches a log. The throw happens before the body is assembled.\n */\nexport function buildGatewayPaymentsRequest({ transaction, card }: SendPaymentsRequest): GatewayPaymentsRequest {\n if (!isTrustedGatewayOrigin(transaction.gatewayUrl)) {\n throw new Error('Refusing to post card data: the transaction carries no trusted https gateway origin.');\n }\n\n const params = new URLSearchParams({ orderId: transaction.orderGroup });\n if (transaction.userProfileId !== null) params.append('userProfileId', transaction.userProfileId);\n if (transaction.callbackUrl !== undefined) params.append('callbackUrl', transaction.callbackUrl);\n\n const transactionId = encodeURIComponent(transaction.transactionId);\n const url = `${transaction.gatewayUrl}/api/payments/transactions/${transactionId}/payments?${params}`;\n\n const { bin, fields } = toCardBody(card);\n const billingAddressDifferent = transaction.billingAddressDifferent ?? false;\n\n const payment = {\n accountId: card.kind === 'saved' ? card.accountId : null,\n bin,\n chooseToUseNewCard: card.kind === 'new',\n currencyCode: transaction.currencyCode,\n fields,\n groupName: transaction.groupName,\n hasDefaultBillingAddress: !billingAddressDifferent,\n id: transaction.merchantName,\n installmentValue: transaction.installmentsValueInCents,\n installments: transaction.installments,\n installmentsInterestRate: transaction.interestRate,\n installmentsValue: transaction.installmentsValueInCents,\n interestRate: transaction.interestRate,\n isBillingAddressDifferent: billingAddressDifferent,\n originalPaymentIndex: 1,\n paymentSystem: transaction.paymentSystem,\n referenceValue: transaction.referenceValueInCents,\n tokenId: null,\n transaction: { id: transaction.transactionId, merchantName: transaction.merchantName },\n value: transaction.valueInCents,\n };\n\n return { url, body: [payment] };\n}\n\n/**\n * T29 (FR-6, OQ-7): this leg's own abort budget. Before this task the direct-to-gateway POST carried no\n * `AbortSignal` and no timeout at all, so a gateway that never answered left `placing` true and the CTA\n * dead for the life of the mount (Route C, `place-order.md`'s Known limitations). The BFF's own default\n * is 10s (`apps/storefront-api-core/.../api-timeout.ts:9`), but a card authorization can legitimately\n * run longer than a GraphQL round trip, and this exact number is not confirmed with payments (spec\n * OQ-7) — a placeholder pending that answer, not a tuned production value.\n *\n * Exported so `gateway.test.ts`'s own abort-budget test can assert the abort fires at exactly this\n * duration, rather than against `vi.runAllTimersAsync()`, which fires any pending timer regardless of\n * duration and would stay green even if this were edited to `300_000`. That mechanism test alone is\n * still self-referential about this constant's own *value* — it advances the fake clock by whatever\n * `GATEWAY_REQUEST_TIMEOUT_MS` currently holds, so on its own it cannot catch an edit to the constant\n * either (fix round 2, verification finding V2). `gateway.test.ts` also asserts this constant against\n * the literal `30_000` directly, in its own dedicated test — that is what actually fails if this\n * constant's value ever changes.\n */\nexport const GATEWAY_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * What a card POST resolves (T112). `reachedGateway` is `false` only when this module can show no request\n * was issued — the request builder refused before any `fetch`. Anything it cannot classify (a rejection, a\n * timeout, an abort, a malformed result) is `true`: a browser cannot tell whether a request that never\n * answered was processed, and a `false` frees the shopper to post the card again. Beside it, `userErrors`\n * keeps the `{ ..., userErrors }` payload shape (ADR-00005); it carries no card value.\n */\nexport type PaymentGatewayResult = Readonly<{\n /** false only when no request was issued to the gateway. Anything unclassified is true. */\n reachedGateway: boolean;\n userErrors: readonly PaymentUserError[];\n}>;\n\n/**\n * Posts the card straight to the gateway and resolves a `PaymentGatewayResult`. A non-2xx response\n * resolves `{ reachedGateway: true, userErrors: [GATEWAY_ERROR] }`; a request the builder refuses\n * (an untrusted origin, a malformed card) resolves `{ reachedGateway: false, userErrors: [GATEWAY_ERROR] }`\n * without issuing a `fetch` or arming a timer, logging only the error's name. A rejected request —\n * including this leg's own timeout firing, or `options.signal` aborting — propagates, and the handler in\n * `use-payment-actions.ts` collapses it to a `reachedGateway: true` result: nothing here can prove it\n * never left. Neither outcome reads the response body: it may echo the request, and it tells the shopper\n * nothing more actionable than \"try again\".\n *\n * `options.signal`, when given, aborts this request in *addition to* — never instead of — this module's\n * own timeout: a caller opts into an earlier or externally triggered abort, but cannot opt out of the\n * budget that keeps this leg from hanging forever (FR-6, US-3). Composed with a plain `AbortController`\n * rather than `AbortSignal.any`/`AbortSignal.timeout` so the timeout is driven by an ordinary\n * `setTimeout`, the one implementation a test can advance deterministically with fake timers.\n *\n * No caller in this package passes `options.signal` today — it exists to satisfy the spec's own\n * Technical Contract (`specs/make-an-order-attempt-survive-a.md`) ahead of a future integration. Fix\n * pass, Low finding: the listener this composes onto `externalSignal` is now removed in the `finally`\n * below on every exit path, not only when it fires — previously, a caller that supplied a long-lived\n * signal (as opposed to a fresh one per call) would accumulate one listener, and this function's own\n * dead `AbortController`, per call that resolved normally.\n */\nexport async function postPaymentsToGateway(\n request: SendPaymentsRequest,\n options?: { signal?: AbortSignal },\n): Promise<PaymentGatewayResult> {\n let built: GatewayPaymentsRequest;\n try {\n built = buildGatewayPaymentsRequest(request);\n } catch (error) {\n // Name only: the builder's message and the request it rejected can carry the card.\n console.error(\n '[payment.sendPayments] the gateway request was refused before it was sent',\n loggableErrorName(error),\n );\n return { reachedGateway: false, userErrors: [PAYMENT_GATEWAY_USER_ERROR] };\n }\n const { url, body } = built;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(new DOMException('The gateway request timed out.', 'TimeoutError')),\n GATEWAY_REQUEST_TIMEOUT_MS,\n );\n const externalSignal = options?.signal;\n const onExternalAbort = () => controller.abort(externalSignal?.reason);\n if (externalSignal) {\n if (externalSignal.aborted) {\n controller.abort(externalSignal.reason);\n } else {\n externalSignal.addEventListener('abort', onExternalAbort, { once: true });\n }\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n return { reachedGateway: true, userErrors: response.ok ? [] : [PAYMENT_GATEWAY_USER_ERROR] };\n } finally {\n clearTimeout(timeoutId);\n externalSignal?.removeEventListener('abort', onExternalAbort);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,6BAA6B;;AAG1C,MAAa,6BAA+C;CAC1D,MAAM;CACN,SAAS;AACX;;AA4FA,MAAM,aAAa;;;;;;;;AASnB,SAAS,SAAS,OAAuB;CACvC,OAAO,MAAM,QAAQ,OAAO,EAAE;AAChC;;AAGA,SAAS,UAAU,gBAAgC;CACjD,MAAM,SAAS,SAAS,cAAc;CACtC,OAAO,GAAG,OAAO,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,MAAM,EAAE;AACjD;;AAGA,SAAS,WAAW,MAA4E;CAC9F,IAAI,KAAK,SAAS,SAChB,OAAO;EAAE,KAAK,KAAK;EAAK,QAAQ;GAAE,KAAK,KAAK;GAAK,gBAAgB,KAAK;EAAa;CAAE;CAGvF,MAAM,SAAS,SAAS,KAAK,MAAM;CACnC,MAAM,MAAM,OAAO,MAAM,GAAG,UAAU;CAEtC,OAAO;EACL;EACA,QAAQ;GACN;GACA,YAAY;GAEZ,UAAU,KAAK,aAAa,KAAA,IAAY,OAAO,KAAK,SAAS,QAAQ,OAAO,EAAE;GAC9E,SAAS,UAAU,KAAK,cAAc;GACtC,YAAY,KAAK;GACjB,gBAAgB,KAAK;GACrB,WAAW,KAAK;GAChB,iBAAiB,KAAK,YAAY;EACpC;CACF;AACF;;;;;;;;;;;;AAaA,SAAgB,4BAA4B,EAAE,aAAa,QAAqD;CAC9G,IAAI,CAAC,uBAAuB,YAAY,UAAU,GAChD,MAAM,IAAI,MAAM,sFAAsF;CAGxG,MAAM,SAAS,IAAI,gBAAgB,EAAE,SAAS,YAAY,WAAW,CAAC;CACtE,IAAI,YAAY,kBAAkB,MAAM,OAAO,OAAO,iBAAiB,YAAY,aAAa;CAChG,IAAI,YAAY,gBAAgB,KAAA,GAAW,OAAO,OAAO,eAAe,YAAY,WAAW;CAE/F,MAAM,gBAAgB,mBAAmB,YAAY,aAAa;CAClE,MAAM,MAAM,GAAG,YAAY,WAAW,6BAA6B,cAAc,YAAY;CAE7F,MAAM,EAAE,KAAK,WAAW,WAAW,IAAI;CACvC,MAAM,0BAA0B,YAAY,2BAA2B;CAyBvE,OAAO;EAAE;EAAK,MAAM,CAAC;GAtBnB,WAAW,KAAK,SAAS,UAAU,KAAK,YAAY;GACpD;GACA,oBAAoB,KAAK,SAAS;GAClC,cAAc,YAAY;GAC1B;GACA,WAAW,YAAY;GACvB,0BAA0B,CAAC;GAC3B,IAAI,YAAY;GAChB,kBAAkB,YAAY;GAC9B,cAAc,YAAY;GAC1B,0BAA0B,YAAY;GACtC,mBAAmB,YAAY;GAC/B,cAAc,YAAY;GAC1B,2BAA2B;GAC3B,sBAAsB;GACtB,eAAe,YAAY;GAC3B,gBAAgB,YAAY;GAC5B,SAAS;GACT,aAAa;IAAE,IAAI,YAAY;IAAe,cAAc,YAAY;GAAa;GACrF,OAAO,YAAY;EAGM,CAAC;CAAE;AAChC;;;;;;;;;;;;;;;;;;AAmBA,MAAa,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;AAsC1C,eAAsB,sBACpB,SACA,SAC+B;CAC/B,IAAI;CACJ,IAAI;EACF,QAAQ,4BAA4B,OAAO;CAC7C,SAAS,OAAO;EAEd,QAAQ,MACN,6EACA,kBAAkB,KAAK,CACzB;EACA,OAAO;GAAE,gBAAgB;GAAO,YAAY,CAAC,0BAA0B;EAAE;CAC3E;CACA,MAAM,EAAE,KAAK,SAAS;CAEtB,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,YAAY,iBACV,WAAW,MAAM,IAAI,aAAa,kCAAkC,cAAc,CAAC,GACzF,0BACF;CACA,MAAM,iBAAiB,SAAS;CAChC,MAAM,wBAAwB,WAAW,MAAM,gBAAgB,MAAM;CACrE,IAAI,gBAAgB;EAClB,IAAI,eAAe,SACjB,WAAW,MAAM,eAAe,MAAM;OAEtC,eAAe,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,KAAK,CAAC;CAE5E;CAEA,IAAI;EAQF,OAAO;GAAE,gBAAgB;GAAM,aAAY,MAPpB,MAAM,KAAK;IAChC,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,IAAI;IACzB,QAAQ,WAAW;GACrB,CAAC,EAAA,CAEmD,KAAK,CAAC,IAAI,CAAC,0BAA0B;EAAE;CAC7F,UAAU;EACR,aAAa,SAAS;EACtB,gBAAgB,oBAAoB,SAAS,eAAe;CAC9D;AACF"}
@@ -22,6 +22,17 @@ const PaymentFragment = gql`
22
22
  selectedMethodId
23
23
  selectedAccountId
24
24
  selectedBin
25
+ storeCountryCode
26
+ countries {
27
+ __typename
28
+ countryCode
29
+ documents {
30
+ __typename
31
+ type
32
+ displayable
33
+ required
34
+ }
35
+ }
25
36
  selectedInstallment {
26
37
  __typename
27
38
  count
@@ -1 +1 @@
1
- {"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/payment/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 * Payment write-model GraphQL operations (specs/payment-action-namespace.md, T4) — the five mutations\n * `api-module:PaymentWriteModel` shipped (T3, `checkout/schema.graphql` § 11). Nothing here is\n * invented: every mutation, input field, and payload field is pinned to that schema.\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive read\n * path — and excluded from the codegen `documents` glob (see `codegen.ts`): the `gql` tag alone is\n * still plucked by `graphql-codegen`, which would duplicate these hand-written types in\n * `sdk/generated/`. Mirrors `shipping/option-select-operations.ts` and `identity/operations.ts`.\n *\n * No field at any nesting depth carries a card number or CVV — the read model guarantees it (RFC D13),\n * and the one call that does carry them never touches GraphQL at all (see `gateway.ts`).\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`;\n * transport and top-level GraphQL failures are infrastructure, collapsed by the handlers in\n * `use-payment-actions.ts` to the one client-synthesized code, `PAYMENT_NETWORK_ERROR_CODE`.\n */\n\n// ---------------------------------------------------------------------------\n// Domain types — mirror the shipped checkout schema\n// ---------------------------------------------------------------------------\n\n/** A payment domain error. Every mutation's error type is `{ code, message }`; codes stay strings. */\nexport type PaymentUserError = Readonly<{ code: string; message: string }>;\n\n/**\n * The one client-synthesized error code, carried by the userError every mutation-backed method\n * *resolves* (never throws) when its mutation fails at the transport or top-level-GraphQL layer.\n * `gateway.ts` owns the separate code for a failed gateway leg (Decision 7).\n */\nexport const PAYMENT_NETWORK_ERROR_CODE = 'NETWORK_ERROR';\n\nexport type PaymentMoney = Readonly<{ __typename?: 'Money'; amount: number; currencyCode: string }>;\n\ntype PaymentInstallmentEntity = Readonly<{\n __typename?: 'PaymentInstallment';\n count: number;\n value: PaymentMoney;\n total: PaymentMoney;\n interestRate: number;\n}>;\n\ntype PaymentMethodValidatorEntity = Readonly<{\n __typename?: 'PaymentMethodValidator';\n numberMask: string | null;\n numberRegex: string | null;\n cvvMask: string | null;\n cvvRegex: string | null;\n cvvRequired: boolean;\n expirationRequired: boolean;\n holderNameRequired: boolean;\n billingAddressRequired: boolean;\n documentDisplayable: boolean;\n documentRequired: boolean;\n}>;\n\ntype PaymentMethodEntity = Readonly<{\n __typename?: 'PaymentMethod';\n id: string;\n name: string;\n groupName: string;\n validator: PaymentMethodValidatorEntity;\n}>;\n\ntype PaymentInstallmentOptionEntity = Readonly<{\n __typename?: 'PaymentInstallmentOption';\n methodId: string;\n bin: string | null;\n baseValue: PaymentMoney;\n installments: readonly PaymentInstallmentEntity[];\n}>;\n\ntype SavedCardEntity = Readonly<{\n __typename?: 'SavedCard';\n id: string;\n accountId: string;\n methodId: string;\n network: string;\n lastFourDigits: string;\n bin: string;\n label: string | null;\n expired: boolean;\n cvvRequired: boolean;\n}>;\n\n/** The full `Payment` entity every selection mutation echoes back. Never carries a PAN or CVV. */\nexport type PaymentEntity = Readonly<{\n __typename?: 'Payment';\n id: string;\n methods: readonly PaymentMethodEntity[];\n selectedMethodId: string | null;\n selectedAccountId: string | null;\n selectedBin: string | null;\n selectedInstallment: PaymentInstallmentEntity | null;\n installmentOptions: readonly PaymentInstallmentOptionEntity[];\n savedCards: readonly SavedCardEntity[];\n}>;\n\n/** The billing-address echo on the selection payloads — the schema's shared `Address` type. */\nexport type PaymentBillingAddressEntity = Readonly<{\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\n// ---------------------------------------------------------------------------\n// Mutation inputs — mirror the schema's input types verbatim\n// ---------------------------------------------------------------------------\n\n/** A `bin` with an `accountId` is validated against the saved card's own BIN (MISMATCHED_BIN_FOR_SAVED_CARD). */\nexport type PaymentMethodSelectInput = Readonly<{ methodId: string; bin?: string; accountId?: string }>;\n\nexport type PaymentInstallmentSelectInput = Readonly<{ count: number }>;\n\n/** With `sameAsDelivery: true` every other field is ignored and the server performs no upstream write. */\nexport type PaymentBillingAddressUpdateInput = Readonly<{\n sameAsDelivery: boolean;\n addressType?: 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 reference?: string;\n}>;\n\nexport type PaymentGatewayCallbackInput = Readonly<{ orderGroup: string }>;\n\n// ---------------------------------------------------------------------------\n// Shared fragment\n// ---------------------------------------------------------------------------\n\n/**\n * The canonical `Payment` selection set, spread by every selection mutation so one response\n * re-normalizes the whole entity and every reactive subscriber re-renders with no refetch — the\n * payload-completeness invariant writes must honor (ADR-0010). Selecting the entire entity mirrors\n * `CartFragment` and `SHIPPING_ADDRESS_UPDATE`'s full-`Shipping` selection: the method list (T5), the\n * validator config (T7), `installmentOptions` (T9), and the summary's selection fields (T6) are all\n * subscribed independently, and a partial selection would leave one of them incomplete.\n */\nexport const PaymentFragment = gql`\n fragment PaymentFragment on Payment {\n __typename\n id\n selectedMethodId\n selectedAccountId\n selectedBin\n selectedInstallment {\n __typename\n count\n value {\n amount\n currencyCode\n }\n total {\n amount\n currencyCode\n }\n interestRate\n }\n installmentOptions {\n __typename\n methodId\n bin\n baseValue {\n amount\n currencyCode\n }\n installments {\n __typename\n count\n value {\n amount\n currencyCode\n }\n total {\n amount\n currencyCode\n }\n interestRate\n }\n }\n methods {\n __typename\n id\n name\n groupName\n validator {\n __typename\n numberMask\n numberRegex\n cvvMask\n cvvRegex\n cvvRequired\n expirationRequired\n holderNameRequired\n billingAddressRequired\n documentDisplayable\n documentRequired\n }\n }\n savedCards {\n __typename\n id\n accountId\n methodId\n network\n lastFourDigits\n bin\n label\n expired\n cvvRequired\n }\n }\n`;\n\n/** The billing-address echo, spread by the three selection mutations that return one. */\nexport const PaymentBillingAddressFragment = gql`\n fragment PaymentBillingAddressFragment on 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`;\n\n// ---------------------------------------------------------------------------\n// Mutation operations\n// ---------------------------------------------------------------------------\n\ntype PaymentMethodSelectMutation = Readonly<{\n paymentMethodSelect: Readonly<{\n __typename?: 'PaymentMethodSelectPayload';\n payment: PaymentEntity | null;\n billingAddress: PaymentBillingAddressEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_METHOD_SELECT: TypedDocumentNode<\n PaymentMethodSelectMutation,\n Readonly<{ input: PaymentMethodSelectInput }>\n> = gql`\n mutation PaymentMethodSelect($input: PaymentMethodSelectInput!) {\n paymentMethodSelect(input: $input) {\n __typename\n payment {\n ...PaymentFragment\n }\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n`;\n\ntype PaymentInstallmentSelectMutation = Readonly<{\n paymentInstallmentSelect: Readonly<{\n __typename?: 'PaymentInstallmentSelectPayload';\n payment: PaymentEntity | null;\n cart: CartEntity | null;\n billingAddress: PaymentBillingAddressEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\n/**\n * Selects `cart { ...CartFragment }` alongside `payment` so the interest-inclusive order total lands\n * in the normalized cache in the same round trip (REQ-03) — the same reason `shippingOptionSelect`\n * selects the cart.\n */\nexport const PAYMENT_INSTALLMENT_SELECT: TypedDocumentNode<\n PaymentInstallmentSelectMutation,\n Readonly<{ input: PaymentInstallmentSelectInput }>\n> = gql`\n mutation PaymentInstallmentSelect($input: PaymentInstallmentSelectInput!) {\n paymentInstallmentSelect(input: $input) {\n __typename\n payment {\n ...PaymentFragment\n }\n cart {\n ...CartFragment\n }\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n ${CartFragment}\n`;\n\ntype PaymentBillingAddressUpdateMutation = Readonly<{\n paymentBillingAddressUpdate: Readonly<{\n __typename?: 'PaymentBillingAddressUpdatePayload';\n billingAddress: PaymentBillingAddressEntity | null;\n payment: PaymentEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_BILLING_ADDRESS_UPDATE: TypedDocumentNode<\n PaymentBillingAddressUpdateMutation,\n Readonly<{ input: PaymentBillingAddressUpdateInput }>\n> = gql`\n mutation PaymentBillingAddressUpdate($input: PaymentBillingAddressUpdateInput!) {\n paymentBillingAddressUpdate(input: $input) {\n __typename\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n payment {\n ...PaymentFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n`;\n\ntype PaymentStartTransactionMutation = Readonly<{\n paymentStartTransaction: Readonly<{\n __typename?: 'PaymentStartTransactionPayload';\n transactionId: string | null;\n merchantName: string | null;\n gatewayUrl: string | null;\n orderGroup: string | null;\n userProfileId: string | null;\n value: PaymentMoney | null;\n valueInCents: number | null;\n referenceValueInCents: number | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\n/**\n * Takes no input: every field VTEX's transaction endpoint needs is derived server-side from the\n * already-persisted selection (T3 Decision 9). The transaction cookies it mints ride on the HTTP\n * response, not on the payload.\n *\n * `merchantName`, `gatewayUrl`, `valueInCents`, and `referenceValueInCents` are T18's additions\n * (specs/payment-transaction-payload-gaps.md), selected here by T13: `PaymentGatewayTransaction`\n * requires all four, so the descriptor cannot be assembled without them. `value` stays selected\n * beside the minor-unit pair — it is the display decimal, and the `purchase` analytics event reports\n * it rather than a client-side division.\n */\nexport const PAYMENT_START_TRANSACTION: TypedDocumentNode<PaymentStartTransactionMutation, Record<string, never>> = gql`\n mutation PaymentStartTransaction {\n paymentStartTransaction {\n __typename\n transactionId\n merchantName\n gatewayUrl\n orderGroup\n userProfileId\n value {\n amount\n currencyCode\n }\n valueInCents\n referenceValueInCents\n userErrors {\n code\n message\n }\n }\n }\n`;\n\ntype PaymentGatewayCallbackMutation = Readonly<{\n paymentGatewayCallback: Readonly<{\n __typename?: 'PaymentGatewayCallbackPayload';\n orderId: string | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_GATEWAY_CALLBACK: TypedDocumentNode<\n PaymentGatewayCallbackMutation,\n Readonly<{ input: PaymentGatewayCallbackInput }>\n> = gql`\n mutation PaymentGatewayCallback($input: PaymentGatewayCallbackInput!) {\n paymentGatewayCallback(input: $input) {\n __typename\n orderId\n userErrors {\n code\n message\n }\n }\n }\n`;\n"],"mappings":";;;;;;;;AAkCA,MAAa,6BAA6B;;;;;;;;;AAyH1C,MAAa,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6ElC,MAAa,gCAAgC,GAAG;;;;;;;;;;;;;;;AA6BhD,MAAa,wBAGT,GAAG;;;;;;;;;;;;;;;;IAgBH,gBAAgB;IAChB,8BAA8B;;;;;;;AAkBlC,MAAa,6BAGT,GAAG;;;;;;;;;;;;;;;;;;;IAmBH,gBAAgB;IAChB,8BAA8B;IAC9B,aAAa;;AAYjB,MAAa,iCAGT,GAAG;;;;;;;;;;;;;;;;IAgBH,gBAAgB;IAChB,8BAA8B;;;;;;;;;;;;;AA6BlC,MAAa,4BAAuG,GAAG;;;;;;;;;;;;;;;;;;;;;;AA+BvH,MAAa,2BAGT,GAAG"}
1
+ {"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/payment/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 * Payment write-model GraphQL operations (specs/payment-action-namespace.md, T4) — the five mutations\n * `api-module:PaymentWriteModel` shipped (T3, `checkout/schema.graphql` § 11). Nothing here is\n * invented: every mutation, input field, and payload field is pinned to that schema.\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive read\n * path — and excluded from the codegen `documents` glob (see `codegen.ts`): the `gql` tag alone is\n * still plucked by `graphql-codegen`, which would duplicate these hand-written types in\n * `sdk/generated/`. Mirrors `shipping/option-select-operations.ts` and `identity/operations.ts`.\n *\n * No field at any nesting depth carries a card number or CVV — the read model guarantees it (RFC D13),\n * and the one call that does carry them never touches GraphQL at all (see `gateway.ts`).\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`;\n * transport and top-level GraphQL failures are infrastructure, collapsed by the handlers in\n * `use-payment-actions.ts` to the one client-synthesized code, `PAYMENT_NETWORK_ERROR_CODE`.\n */\n\n// ---------------------------------------------------------------------------\n// Domain types — mirror the shipped checkout schema\n// ---------------------------------------------------------------------------\n\n/** A payment domain error. Every mutation's error type is `{ code, message }`; codes stay strings. */\nexport type PaymentUserError = Readonly<{ code: string; message: string }>;\n\n/**\n * The one client-synthesized error code, carried by the userError every mutation-backed method\n * *resolves* (never throws) when its mutation fails at the transport or top-level-GraphQL layer.\n * `gateway.ts` owns the separate code for a failed gateway leg (Decision 7).\n */\nexport const PAYMENT_NETWORK_ERROR_CODE = 'NETWORK_ERROR';\n\nexport type PaymentMoney = Readonly<{ __typename?: 'Money'; amount: number; currencyCode: string }>;\n\ntype PaymentInstallmentEntity = Readonly<{\n __typename?: 'PaymentInstallment';\n count: number;\n value: PaymentMoney;\n total: PaymentMoney;\n interestRate: number;\n}>;\n\ntype PaymentMethodValidatorEntity = Readonly<{\n __typename?: 'PaymentMethodValidator';\n numberMask: string | null;\n numberRegex: string | null;\n cvvMask: string | null;\n cvvRegex: string | null;\n cvvRequired: boolean;\n expirationRequired: boolean;\n holderNameRequired: boolean;\n billingAddressRequired: boolean;\n documentDisplayable: boolean;\n documentRequired: boolean;\n}>;\n\ntype PaymentCountryDocumentEntity = Readonly<{\n __typename?: 'PaymentCountryDocument';\n type: string;\n displayable: boolean;\n required: boolean;\n}>;\n\ntype PaymentCountryEntity = Readonly<{\n __typename?: 'PaymentCountry';\n countryCode: string;\n documents: readonly PaymentCountryDocumentEntity[];\n}>;\n\ntype PaymentMethodEntity = Readonly<{\n __typename?: 'PaymentMethod';\n id: string;\n name: string;\n groupName: string;\n validator: PaymentMethodValidatorEntity;\n}>;\n\ntype PaymentInstallmentOptionEntity = Readonly<{\n __typename?: 'PaymentInstallmentOption';\n methodId: string;\n bin: string | null;\n baseValue: PaymentMoney;\n installments: readonly PaymentInstallmentEntity[];\n}>;\n\ntype SavedCardEntity = Readonly<{\n __typename?: 'SavedCard';\n id: string;\n accountId: string;\n methodId: string;\n network: string;\n lastFourDigits: string;\n bin: string;\n label: string | null;\n expired: boolean;\n cvvRequired: boolean;\n}>;\n\n/** The full `Payment` entity every selection mutation echoes back. Never carries a PAN or CVV. */\nexport type PaymentEntity = Readonly<{\n __typename?: 'Payment';\n id: string;\n methods: readonly PaymentMethodEntity[];\n selectedMethodId: string | null;\n selectedAccountId: string | null;\n selectedBin: string | null;\n storeCountryCode: string | null;\n countries: readonly PaymentCountryEntity[];\n selectedInstallment: PaymentInstallmentEntity | null;\n installmentOptions: readonly PaymentInstallmentOptionEntity[];\n savedCards: readonly SavedCardEntity[];\n}>;\n\n/** The billing-address echo on the selection payloads — the schema's shared `Address` type. */\nexport type PaymentBillingAddressEntity = Readonly<{\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\n// ---------------------------------------------------------------------------\n// Mutation inputs — mirror the schema's input types verbatim\n// ---------------------------------------------------------------------------\n\n/** A `bin` with an `accountId` is validated against the saved card's own BIN (MISMATCHED_BIN_FOR_SAVED_CARD). */\nexport type PaymentMethodSelectInput = Readonly<{ methodId: string; bin?: string; accountId?: string }>;\n\nexport type PaymentInstallmentSelectInput = Readonly<{ count: number }>;\n\n/** With `sameAsDelivery: true` every other field is ignored and the server performs no upstream write. */\nexport type PaymentBillingAddressUpdateInput = Readonly<{\n sameAsDelivery: boolean;\n addressType?: 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 reference?: string;\n}>;\n\nexport type PaymentGatewayCallbackInput = Readonly<{ orderGroup: string }>;\n\n// ---------------------------------------------------------------------------\n// Shared fragment\n// ---------------------------------------------------------------------------\n\n/**\n * The canonical `Payment` selection set, spread by every selection mutation so one response\n * re-normalizes the whole entity and every reactive subscriber re-renders with no refetch — the\n * payload-completeness invariant writes must honor (ADR-0010). Selecting the entire entity mirrors\n * `CartFragment` and `SHIPPING_ADDRESS_UPDATE`'s full-`Shipping` selection: the method list (T5), the\n * validator config (T7), `installmentOptions` (T9), and the summary's selection fields (T6) are all\n * subscribed independently, and a partial selection would leave one of them incomplete.\n */\nexport const PaymentFragment = gql`\n fragment PaymentFragment on Payment {\n __typename\n id\n selectedMethodId\n selectedAccountId\n selectedBin\n storeCountryCode\n countries {\n __typename\n countryCode\n documents {\n __typename\n type\n displayable\n required\n }\n }\n selectedInstallment {\n __typename\n count\n value {\n amount\n currencyCode\n }\n total {\n amount\n currencyCode\n }\n interestRate\n }\n installmentOptions {\n __typename\n methodId\n bin\n baseValue {\n amount\n currencyCode\n }\n installments {\n __typename\n count\n value {\n amount\n currencyCode\n }\n total {\n amount\n currencyCode\n }\n interestRate\n }\n }\n methods {\n __typename\n id\n name\n groupName\n validator {\n __typename\n numberMask\n numberRegex\n cvvMask\n cvvRegex\n cvvRequired\n expirationRequired\n holderNameRequired\n billingAddressRequired\n documentDisplayable\n documentRequired\n }\n }\n savedCards {\n __typename\n id\n accountId\n methodId\n network\n lastFourDigits\n bin\n label\n expired\n cvvRequired\n }\n }\n`;\n\n/** The billing-address echo, spread by the three selection mutations that return one. */\nexport const PaymentBillingAddressFragment = gql`\n fragment PaymentBillingAddressFragment on 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`;\n\n// ---------------------------------------------------------------------------\n// Mutation operations\n// ---------------------------------------------------------------------------\n\ntype PaymentMethodSelectMutation = Readonly<{\n paymentMethodSelect: Readonly<{\n __typename?: 'PaymentMethodSelectPayload';\n payment: PaymentEntity | null;\n billingAddress: PaymentBillingAddressEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_METHOD_SELECT: TypedDocumentNode<\n PaymentMethodSelectMutation,\n Readonly<{ input: PaymentMethodSelectInput }>\n> = gql`\n mutation PaymentMethodSelect($input: PaymentMethodSelectInput!) {\n paymentMethodSelect(input: $input) {\n __typename\n payment {\n ...PaymentFragment\n }\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n`;\n\ntype PaymentInstallmentSelectMutation = Readonly<{\n paymentInstallmentSelect: Readonly<{\n __typename?: 'PaymentInstallmentSelectPayload';\n payment: PaymentEntity | null;\n cart: CartEntity | null;\n billingAddress: PaymentBillingAddressEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\n/**\n * Selects `cart { ...CartFragment }` alongside `payment` so the interest-inclusive order total lands\n * in the normalized cache in the same round trip (REQ-03) — the same reason `shippingOptionSelect`\n * selects the cart.\n */\nexport const PAYMENT_INSTALLMENT_SELECT: TypedDocumentNode<\n PaymentInstallmentSelectMutation,\n Readonly<{ input: PaymentInstallmentSelectInput }>\n> = gql`\n mutation PaymentInstallmentSelect($input: PaymentInstallmentSelectInput!) {\n paymentInstallmentSelect(input: $input) {\n __typename\n payment {\n ...PaymentFragment\n }\n cart {\n ...CartFragment\n }\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n ${CartFragment}\n`;\n\ntype PaymentBillingAddressUpdateMutation = Readonly<{\n paymentBillingAddressUpdate: Readonly<{\n __typename?: 'PaymentBillingAddressUpdatePayload';\n billingAddress: PaymentBillingAddressEntity | null;\n payment: PaymentEntity | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_BILLING_ADDRESS_UPDATE: TypedDocumentNode<\n PaymentBillingAddressUpdateMutation,\n Readonly<{ input: PaymentBillingAddressUpdateInput }>\n> = gql`\n mutation PaymentBillingAddressUpdate($input: PaymentBillingAddressUpdateInput!) {\n paymentBillingAddressUpdate(input: $input) {\n __typename\n billingAddress {\n ...PaymentBillingAddressFragment\n }\n payment {\n ...PaymentFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${PaymentFragment}\n ${PaymentBillingAddressFragment}\n`;\n\ntype PaymentStartTransactionMutation = Readonly<{\n paymentStartTransaction: Readonly<{\n __typename?: 'PaymentStartTransactionPayload';\n transactionId: string | null;\n merchantName: string | null;\n gatewayUrl: string | null;\n orderGroup: string | null;\n userProfileId: string | null;\n value: PaymentMoney | null;\n valueInCents: number | null;\n referenceValueInCents: number | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\n/**\n * Takes no input: every field VTEX's transaction endpoint needs is derived server-side from the\n * already-persisted selection (T3 Decision 9). The transaction cookies it mints ride on the HTTP\n * response, not on the payload.\n *\n * `merchantName`, `gatewayUrl`, `valueInCents`, and `referenceValueInCents` are T18's additions\n * (specs/payment-transaction-payload-gaps.md), selected here by T13: `PaymentGatewayTransaction`\n * requires all four, so the descriptor cannot be assembled without them. `value` stays selected\n * beside the minor-unit pair — it is the display decimal, and the `purchase` analytics event reports\n * it rather than a client-side division.\n */\nexport const PAYMENT_START_TRANSACTION: TypedDocumentNode<PaymentStartTransactionMutation, Record<string, never>> = gql`\n mutation PaymentStartTransaction {\n paymentStartTransaction {\n __typename\n transactionId\n merchantName\n gatewayUrl\n orderGroup\n userProfileId\n value {\n amount\n currencyCode\n }\n valueInCents\n referenceValueInCents\n userErrors {\n code\n message\n }\n }\n }\n`;\n\ntype PaymentGatewayCallbackMutation = Readonly<{\n paymentGatewayCallback: Readonly<{\n __typename?: 'PaymentGatewayCallbackPayload';\n orderId: string | null;\n userErrors: readonly PaymentUserError[];\n }>;\n}>;\n\nexport const PAYMENT_GATEWAY_CALLBACK: TypedDocumentNode<\n PaymentGatewayCallbackMutation,\n Readonly<{ input: PaymentGatewayCallbackInput }>\n> = gql`\n mutation PaymentGatewayCallback($input: PaymentGatewayCallbackInput!) {\n paymentGatewayCallback(input: $input) {\n __typename\n orderId\n userErrors {\n code\n message\n }\n }\n }\n`;\n"],"mappings":";;;;;;;;AAkCA,MAAa,6BAA6B;;;;;;;;;AAwI1C,MAAa,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwFlC,MAAa,gCAAgC,GAAG;;;;;;;;;;;;;;;AA6BhD,MAAa,wBAGT,GAAG;;;;;;;;;;;;;;;;IAgBH,gBAAgB;IAChB,8BAA8B;;;;;;;AAkBlC,MAAa,6BAGT,GAAG;;;;;;;;;;;;;;;;;;;IAmBH,gBAAgB;IAChB,8BAA8B;IAC9B,aAAa;;AAYjB,MAAa,iCAGT,GAAG;;;;;;;;;;;;;;;;IAgBH,gBAAgB;IAChB,8BAA8B;;;;;;;;;;;;;AA6BlC,MAAa,4BAAuG,GAAG;;;;;;;;;;;;;;;;;;;;;;AA+BvH,MAAa,2BAGT,GAAG"}
@@ -8,7 +8,8 @@ import { ReactNode } from "react";
8
8
  *
9
9
  * T7 (new card) and T12 (saved card) each register a submit-time continuation here. Each closes over
10
10
  * its own card fields, builds the gateway card object inside that closure, calls
11
- * `$actions.payment.sendPayments` itself, and returns only the gateway leg's `userErrors`. T13's
11
+ * `$actions.payment.sendPayments` itself, and returns only the gateway leg's result: its `userErrors` and
12
+ * whether a request reached the gateway (T112). T13's
12
13
  * `usePlaceOrder` resolves one by `path` and invokes it between start-transaction and
13
14
  * gateway-callback, so no card-shaped field appears anywhere in this channel's type signature.
14
15
  *
@@ -9,17 +9,19 @@ function PaymentSubmissionProvider({ path, children }) {
9
9
  const submissions = useRef(/* @__PURE__ */ new Map());
10
10
  const channel = useMemo(() => ({
11
11
  path,
12
- register: (registeredPath, submit, preflight) => {
12
+ register: (registeredPath, submit, preflight, explainMissingMethod) => {
13
13
  submissions.current.set(registeredPath, {
14
14
  submit,
15
- preflight: preflight ?? null
15
+ preflight: preflight ?? null,
16
+ explainMissingMethod: explainMissingMethod ?? null
16
17
  });
17
18
  return () => {
18
19
  if (submissions.current.get(registeredPath)?.submit === submit) submissions.current.delete(registeredPath);
19
20
  };
20
21
  },
21
22
  resolve: (registeredPath) => submissions.current.get(registeredPath)?.submit ?? null,
22
- resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null
23
+ resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null,
24
+ resolveMissingMethodExplainer: (registeredPath) => submissions.current.get(registeredPath)?.explainMissingMethod ?? null
23
25
  }), [path]);
24
26
  return /* @__PURE__ */ jsx(PaymentSubmissionContext, {
25
27
  value: channel,
@@ -38,18 +40,20 @@ function usePaymentSubmission() {
38
40
  return channel;
39
41
  }
40
42
  /**
41
- * The holder-facing signature (T7, T12; `preflight` added by T27). Registers `submit` — and,
42
- * optionally, its pre-flight check — for `path`, and unregisters on unmount or on any argument
43
+ * The holder-facing signature (T7, T12; `preflight` added by T27, `explainMissingMethod` by T47).
44
+ * Registers `submit` — and, optionally, its pre-flight check and its missing-method explainer — for
45
+ * `path`, and unregisters on unmount or on any argument
43
46
  * changing, so the map always holds the latest closures over the holder's card fields — a stale one
44
47
  * would pay with the previous keystroke's CVV.
45
48
  */
46
- function useRegisterPaymentSubmission(path, submit, preflight) {
49
+ function useRegisterPaymentSubmission(path, submit, preflight, explainMissingMethod) {
47
50
  const { register } = usePaymentSubmission();
48
- useEffect(() => register(path, submit, preflight), [
51
+ useEffect(() => register(path, submit, preflight, explainMissingMethod), [
49
52
  register,
50
53
  path,
51
54
  submit,
52
- preflight
55
+ preflight,
56
+ explainMissingMethod
53
57
  ]);
54
58
  }
55
59
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"submission-registry.js","names":[],"sources":["../../../src/sdk/payment/submission-registry.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, type ReactNode, useContext, useEffect, useMemo, useRef } from 'react';\nimport type { PaymentGatewayTransaction } from './gateway.js';\nimport type { PaymentUserError } from './operations.js';\n\n/**\n * The card-data submission channel (specs/use-place-order.md, Decision 1; specs/epics/credit-card.md\n * § \"The card-data submission channel\"). **The holder submits; the orchestrator never holds.**\n *\n * T7 (new card) and T12 (saved card) each register a submit-time continuation here. Each closes over\n * its own card fields, builds the gateway card object inside that closure, calls\n * `$actions.payment.sendPayments` itself, and returns only the gateway leg's `userErrors`. T13's\n * `usePlaceOrder` resolves one by `path` and invokes it between start-transaction and\n * gateway-callback, so no card-shaped field appears anywhere in this channel's type signature.\n *\n * It is a *second*, narrow context beside T5's `payment` context rather than a field on it, because\n * the two have different shapes and different readers: `draft` is render state every leaf reads, this\n * is an imperative registry exactly two components write and one hook reads. Registration is a\n * ref-held `Map`, not state — T7 re-registers a fresh closure on every keystroke, and making that a\n * render would re-render the whole payment section per character.\n *\n * Values that are **not** sensitive travel on T5's `draft`, never here: the save-card flag and label\n * (T10), the cardholder document (T8), and the billing-address-differs flag (T11). The holder folds\n * them into the card object inside its own closure.\n *\n * This module lives in the SDK rather than beside T5's roots so the layering stays `matter → sdk`:\n * `usePlaceOrder` is an SDK hook and cannot import from `matter/`. \"Provided by T5's root\" means the\n * root renders `PaymentSubmissionProvider`, which it does — both of them, for the same ADR-0009\n * reason the `payment` context has two providers.\n */\n\n/** Which entry path a submission serves. The canonical key type; T5's `PaymentPath` aliases it. */\nexport type PaymentSubmissionPath = 'new-card' | 'saved-card';\n\n/**\n * A holder's submit-time continuation — the whole channel. It takes the non-sensitive transaction\n * descriptor and resolves the gateway leg's `userErrors` (empty on success). It must not log,\n * serialize, or return the card.\n */\nexport type PaymentSubmission = (transaction: PaymentGatewayTransaction) => Promise<readonly PaymentUserError[]>;\n\n/**\n * A holder's pre-flight verdict on its own draft, resolved before any transaction opens (T27,\n * specs/place-order-preflight-card-validation.md). Returns the refusals that would make this\n * submission pointless, or an empty array to proceed. Synchronous by contract (Decision 6): a holder\n * validates what it already holds and performs no I/O.\n *\n * Card-free by the same rule the submission itself follows — it returns `PaymentUserError`s and never\n * the fields it inspected. It may have side effects inside its own component (rendering field errors,\n * moving focus); that is the half a value-shaped gate cannot carry.\n */\nexport type PaymentPreflightCheck = () => readonly PaymentUserError[];\n\n/** One path's registration. `preflight` is `null` when its holder registered none (FR-6). */\ntype PaymentSubmissionEntry = Readonly<{\n submit: PaymentSubmission;\n preflight: PaymentPreflightCheck | null;\n}>;\n\nexport type PaymentSubmissionChannel = Readonly<{\n /**\n * The entry path the shopper is on — T5's `draft.path`, mirrored here so the place-order sequence\n * resolves it without reading the matter context. One-way and derived: the root passes it through\n * on every render.\n */\n path: PaymentSubmissionPath | null;\n /** Registers (or replaces) the continuation, and optionally its pre-flight check, for a path. Returns its unregister function. */\n register: (path: PaymentSubmissionPath, submit: PaymentSubmission, preflight?: PaymentPreflightCheck) => () => void;\n /** Unchanged: the continuation registered for a path, or `null` when its holder is not composed or unmounted. */\n resolve: (path: PaymentSubmissionPath) => PaymentSubmission | null;\n /** The pre-flight check registered for a path, or `null` when its holder registered none. */\n resolvePreflight: (path: PaymentSubmissionPath) => PaymentPreflightCheck | null;\n}>;\n\nconst SUBMISSION_CONTEXT_UNSET = Symbol('PaymentSubmissionContextUnset');\n\nconst PaymentSubmissionContext = createContext<PaymentSubmissionChannel | typeof SUBMISSION_CONTEXT_UNSET>(\n SUBMISSION_CONTEXT_UNSET,\n);\n\nexport type PaymentSubmissionProviderProps = Readonly<{\n /** T5's `draft.path`. */\n path: PaymentSubmissionPath | null;\n children: ReactNode;\n}>;\n\n/** Rendered by `PaymentSectionRoot` and `PaymentSectionController` around the section composition. */\nexport function PaymentSubmissionProvider({ path, children }: PaymentSubmissionProviderProps) {\n const submissions = useRef(new Map<PaymentSubmissionPath, PaymentSubmissionEntry>());\n\n const channel = useMemo<PaymentSubmissionChannel>(\n () => ({\n path,\n register: (registeredPath, submit, preflight) => {\n submissions.current.set(registeredPath, { submit, preflight: preflight ?? null });\n return () => {\n // Delete only if this registration is still the one on file: a Map holds one entry per\n // path, so an unmounting holder whose registration was already superseded by a still-mounted\n // sibling under the same path must not wipe that sibling's live continuation (or its check).\n if (submissions.current.get(registeredPath)?.submit === submit) {\n submissions.current.delete(registeredPath);\n }\n };\n },\n resolve: (registeredPath) => submissions.current.get(registeredPath)?.submit ?? null,\n resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null,\n }),\n [path],\n );\n\n return <PaymentSubmissionContext value={channel}>{children}</PaymentSubmissionContext>;\n}\n\n/**\n * Read the submission channel from the nearest `PaymentSectionRoot` or `PaymentSectionController`.\n * Throws outside either subtree, mirroring `usePayment()`: a misplaced holder or CTA is a composition\n * bug the author should see immediately. Distinct from the two *runtime* states — no path chosen, no\n * continuation registered — which `usePlaceOrder` resolves as a userError.\n */\nexport function usePaymentSubmission(): PaymentSubmissionChannel {\n const channel = useContext(PaymentSubmissionContext);\n if (channel === SUBMISSION_CONTEXT_UNSET) {\n throw new Error(\n 'usePaymentSubmission() must be used inside a <PaymentSectionRoot> or <PaymentSectionController> subtree.',\n );\n }\n return channel;\n}\n\n/**\n * The holder-facing signature (T7, T12; `preflight` added by T27). Registers `submit` — and,\n * optionally, its pre-flight check — for `path`, and unregisters on unmount or on any argument\n * changing, so the map always holds the latest closures over the holder's card fields — a stale one\n * would pay with the previous keystroke's CVV.\n */\nexport function useRegisterPaymentSubmission(\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n): void {\n const { register } = usePaymentSubmission();\n\n useEffect(() => register(path, submit, preflight), [register, path, submit, preflight]);\n}\n"],"mappings":";;;;AA2EA,MAAM,2BAA2B,OAAO,+BAA+B;AAEvE,MAAM,2BAA2B,cAC/B,wBACF;;AASA,SAAgB,0BAA0B,EAAE,MAAM,YAA4C;CAC5F,MAAM,cAAc,uBAAO,IAAI,IAAmD,CAAC;CAEnF,MAAM,UAAU,eACP;EACL;EACA,WAAW,gBAAgB,QAAQ,cAAc;GAC/C,YAAY,QAAQ,IAAI,gBAAgB;IAAE;IAAQ,WAAW,aAAa;GAAK,CAAC;GAChF,aAAa;IAIX,IAAI,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,WAAW,QACtD,YAAY,QAAQ,OAAO,cAAc;GAE7C;EACF;EACA,UAAU,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,UAAU;EAChF,mBAAmB,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,aAAa;CAC9F,IACA,CAAC,IAAI,CACP;CAEA,OAAO,oBAAC,0BAAD;EAA0B,OAAO;EAAU;CAAmC,CAAA;AACvF;;;;;;;AAQA,SAAgB,uBAAiD;CAC/D,MAAM,UAAU,WAAW,wBAAwB;CACnD,IAAI,YAAY,0BACd,MAAM,IAAI,MACR,0GACF;CAEF,OAAO;AACT;;;;;;;AAQA,SAAgB,6BACd,MACA,QACA,WACM;CACN,MAAM,EAAE,aAAa,qBAAqB;CAE1C,gBAAgB,SAAS,MAAM,QAAQ,SAAS,GAAG;EAAC;EAAU;EAAM;EAAQ;CAAS,CAAC;AACxF"}
1
+ {"version":3,"file":"submission-registry.js","names":[],"sources":["../../../src/sdk/payment/submission-registry.tsx"],"sourcesContent":["'use client';\n\nimport { createContext, type ReactNode, useContext, useEffect, useMemo, useRef } from 'react';\nimport type { PaymentGatewayResult, PaymentGatewayTransaction } from './gateway.js';\nimport type { PaymentUserError } from './operations.js';\n\n/**\n * The card-data submission channel (specs/use-place-order.md, Decision 1; specs/epics/credit-card.md\n * § \"The card-data submission channel\"). **The holder submits; the orchestrator never holds.**\n *\n * T7 (new card) and T12 (saved card) each register a submit-time continuation here. Each closes over\n * its own card fields, builds the gateway card object inside that closure, calls\n * `$actions.payment.sendPayments` itself, and returns only the gateway leg's result: its `userErrors` and\n * whether a request reached the gateway (T112). T13's\n * `usePlaceOrder` resolves one by `path` and invokes it between start-transaction and\n * gateway-callback, so no card-shaped field appears anywhere in this channel's type signature.\n *\n * It is a *second*, narrow context beside T5's `payment` context rather than a field on it, because\n * the two have different shapes and different readers: `draft` is render state every leaf reads, this\n * is an imperative registry exactly two components write and one hook reads. Registration is a\n * ref-held `Map`, not state — T7 re-registers a fresh closure on every keystroke, and making that a\n * render would re-render the whole payment section per character.\n *\n * Values that are **not** sensitive travel on T5's `draft`, never here: the save-card flag and label\n * (T10), the cardholder document (T8), and the billing-address-differs flag (T11). The holder folds\n * them into the card object inside its own closure.\n *\n * This module lives in the SDK rather than beside T5's roots so the layering stays `matter → sdk`:\n * `usePlaceOrder` is an SDK hook and cannot import from `matter/`. \"Provided by T5's root\" means the\n * root renders `PaymentSubmissionProvider`, which it does — both of them, for the same ADR-0009\n * reason the `payment` context has two providers.\n */\n\n/** Which entry path a submission serves. The canonical key type; T5's `PaymentPath` aliases it. */\nexport type PaymentSubmissionPath = 'new-card' | 'saved-card';\n\n/**\n * What a continuation resolves (T112): the gateway leg's `userErrors` (empty on success) and\n * `reachedGateway`, which is `false` only when the holder can show it refused before issuing any\n * request. `usePlaceOrder` frees the attempt for exactly that case and locks it for every other one,\n * including a missing or non-boolean flag. Defined by the producer, `gateway.ts`; re-exported here so the\n * hook imports it from this module and keeps `./gateway.js` to the transaction type alone.\n */\nexport type PaymentSubmissionResult = PaymentGatewayResult;\n\n/**\n * A holder's submit-time continuation — the whole channel. It takes the non-sensitive transaction\n * descriptor and resolves a `PaymentSubmissionResult`. It must not log, serialize, or return the card.\n */\nexport type PaymentSubmission = (transaction: PaymentGatewayTransaction) => Promise<PaymentSubmissionResult>;\n\n/**\n * A holder's pre-flight verdict on its own draft, resolved before any transaction opens (T27,\n * specs/place-order-preflight-card-validation.md). Returns the refusals that would make this\n * submission pointless, or an empty array to proceed. Synchronous by contract (Decision 6): a holder\n * validates what it already holds and performs no I/O.\n *\n * Card-free by the same rule the submission itself follows — it returns `PaymentUserError`s and never\n * the fields it inspected. It may have side effects inside its own component (rendering field errors,\n * moving focus); that is the half a value-shaped gate cannot carry.\n */\nexport type PaymentPreflightCheck = () => readonly PaymentUserError[];\n\n/**\n * A holder's explanation of why no payment method is selected (T47, specs/distinguish-a-pan-that-\n * matches-no-configured.md, Decision 2/4/5). Consulted only by `usePlaceOrder`'s method step, and only\n * when nothing is selected, so it can never reorder the checks. Returns the refusal to show in place of\n * the generic missing-method one, or `null` when the holder has nothing more specific to say.\n *\n * Synchronous and side-effect-free, unlike the pre-flight: it returns a value and touches nothing in its\n * own component. Fixed copy and a fixed code only — it must never echo anything the shopper typed.\n */\nexport type PaymentMissingMethodExplainer = () => PaymentUserError | null;\n\n/** One path's registration. `preflight` and `explainMissingMethod` are `null` when its holder registered none (FR-6). */\ntype PaymentSubmissionEntry = Readonly<{\n submit: PaymentSubmission;\n preflight: PaymentPreflightCheck | null;\n explainMissingMethod: PaymentMissingMethodExplainer | null;\n}>;\n\nexport type PaymentSubmissionChannel = Readonly<{\n /**\n * The entry path the shopper is on — T5's `draft.path`, mirrored here so the place-order sequence\n * resolves it without reading the matter context. One-way and derived: the root passes it through\n * on every render.\n */\n path: PaymentSubmissionPath | null;\n /**\n * Registers (or replaces) the continuation, and optionally its pre-flight check and its missing-method\n * explainer, for a path. Returns its unregister function.\n */\n register: (\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n ) => () => void;\n /** Unchanged: the continuation registered for a path, or `null` when its holder is not composed or unmounted. */\n resolve: (path: PaymentSubmissionPath) => PaymentSubmission | null;\n /** The pre-flight check registered for a path, or `null` when its holder registered none. */\n resolvePreflight: (path: PaymentSubmissionPath) => PaymentPreflightCheck | null;\n /** The missing-method explainer registered for a path, or `null` when its holder registered none (T47). */\n resolveMissingMethodExplainer: (path: PaymentSubmissionPath) => PaymentMissingMethodExplainer | null;\n}>;\n\nconst SUBMISSION_CONTEXT_UNSET = Symbol('PaymentSubmissionContextUnset');\n\nconst PaymentSubmissionContext = createContext<PaymentSubmissionChannel | typeof SUBMISSION_CONTEXT_UNSET>(\n SUBMISSION_CONTEXT_UNSET,\n);\n\nexport type PaymentSubmissionProviderProps = Readonly<{\n /** T5's `draft.path`. */\n path: PaymentSubmissionPath | null;\n children: ReactNode;\n}>;\n\n/** Rendered by `PaymentSectionRoot` and `PaymentSectionController` around the section composition. */\nexport function PaymentSubmissionProvider({ path, children }: PaymentSubmissionProviderProps) {\n const submissions = useRef(new Map<PaymentSubmissionPath, PaymentSubmissionEntry>());\n\n const channel = useMemo<PaymentSubmissionChannel>(\n () => ({\n path,\n register: (registeredPath, submit, preflight, explainMissingMethod) => {\n submissions.current.set(registeredPath, {\n submit,\n preflight: preflight ?? null,\n explainMissingMethod: explainMissingMethod ?? null,\n });\n return () => {\n // Delete only if this registration is still the one on file: a Map holds one entry per\n // path, so an unmounting holder whose registration was already superseded by a still-mounted\n // sibling under the same path must not wipe that sibling's live continuation (or its check).\n if (submissions.current.get(registeredPath)?.submit === submit) {\n submissions.current.delete(registeredPath);\n }\n };\n },\n resolve: (registeredPath) => submissions.current.get(registeredPath)?.submit ?? null,\n resolvePreflight: (registeredPath) => submissions.current.get(registeredPath)?.preflight ?? null,\n resolveMissingMethodExplainer: (registeredPath) =>\n submissions.current.get(registeredPath)?.explainMissingMethod ?? null,\n }),\n [path],\n );\n\n return <PaymentSubmissionContext value={channel}>{children}</PaymentSubmissionContext>;\n}\n\n/**\n * Read the submission channel from the nearest `PaymentSectionRoot` or `PaymentSectionController`.\n * Throws outside either subtree, mirroring `usePayment()`: a misplaced holder or CTA is a composition\n * bug the author should see immediately. Distinct from the two *runtime* states — no path chosen, no\n * continuation registered — which `usePlaceOrder` resolves as a userError.\n */\nexport function usePaymentSubmission(): PaymentSubmissionChannel {\n const channel = useContext(PaymentSubmissionContext);\n if (channel === SUBMISSION_CONTEXT_UNSET) {\n throw new Error(\n 'usePaymentSubmission() must be used inside a <PaymentSectionRoot> or <PaymentSectionController> subtree.',\n );\n }\n return channel;\n}\n\n/**\n * The holder-facing signature (T7, T12; `preflight` added by T27, `explainMissingMethod` by T47).\n * Registers `submit` — and, optionally, its pre-flight check and its missing-method explainer — for\n * `path`, and unregisters on unmount or on any argument\n * changing, so the map always holds the latest closures over the holder's card fields — a stale one\n * would pay with the previous keystroke's CVV.\n */\nexport function useRegisterPaymentSubmission(\n path: PaymentSubmissionPath,\n submit: PaymentSubmission,\n preflight?: PaymentPreflightCheck,\n explainMissingMethod?: PaymentMissingMethodExplainer,\n): void {\n const { register } = usePaymentSubmission();\n\n useEffect(\n () => register(path, submit, preflight, explainMissingMethod),\n [register, path, submit, preflight, explainMissingMethod],\n );\n}\n"],"mappings":";;;;AA0GA,MAAM,2BAA2B,OAAO,+BAA+B;AAEvE,MAAM,2BAA2B,cAC/B,wBACF;;AASA,SAAgB,0BAA0B,EAAE,MAAM,YAA4C;CAC5F,MAAM,cAAc,uBAAO,IAAI,IAAmD,CAAC;CAEnF,MAAM,UAAU,eACP;EACL;EACA,WAAW,gBAAgB,QAAQ,WAAW,yBAAyB;GACrE,YAAY,QAAQ,IAAI,gBAAgB;IACtC;IACA,WAAW,aAAa;IACxB,sBAAsB,wBAAwB;GAChD,CAAC;GACD,aAAa;IAIX,IAAI,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,WAAW,QACtD,YAAY,QAAQ,OAAO,cAAc;GAE7C;EACF;EACA,UAAU,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,UAAU;EAChF,mBAAmB,mBAAmB,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,aAAa;EAC5F,gCAAgC,mBAC9B,YAAY,QAAQ,IAAI,cAAc,CAAC,EAAE,wBAAwB;CACrE,IACA,CAAC,IAAI,CACP;CAEA,OAAO,oBAAC,0BAAD;EAA0B,OAAO;EAAU;CAAmC,CAAA;AACvF;;;;;;;AAQA,SAAgB,uBAAiD;CAC/D,MAAM,UAAU,WAAW,wBAAwB;CACnD,IAAI,YAAY,0BACd,MAAM,IAAI,MACR,0GACF;CAEF,OAAO;AACT;;;;;;;;AASA,SAAgB,6BACd,MACA,QACA,WACA,sBACM;CACN,MAAM,EAAE,aAAa,qBAAqB;CAE1C,gBACQ,SAAS,MAAM,QAAQ,WAAW,oBAAoB,GAC5D;EAAC;EAAU;EAAM;EAAQ;EAAW;CAAoB,CAC1D;AACF"}
@@ -1,6 +1,6 @@
1
1
  import "../../core/dist/index.js";
2
2
  import { PaymentBillingAddressUpdateInput, PaymentMethodSelectInput, PaymentMoney, PaymentUserError } from "./operations.js";
3
- import { SendPaymentsRequest } from "./gateway.js";
3
+ import { PaymentGatewayResult, SendPaymentsRequest } from "./gateway.js";
4
4
  //#region src/sdk/payment/use-payment-actions.d.ts
5
5
  /**
6
6
  * The `payment` action namespace — the sanctioned client write surface for credit-card payment
@@ -70,9 +70,11 @@ export type PaymentActions = Readonly<{
70
70
  gatewayCallback: (orderGroup: string) => Promise<PaymentGatewayCallbackResult>;
71
71
  /**
72
72
  * Façade: post the card straight to the payment gateway. Issues no GraphQL operation and writes
73
- * nothing to the cache. Resolves one `GATEWAY_ERROR` userError when the gateway rejects the call.
73
+ * nothing to the cache. Never rejects: resolves `{ reachedGateway, userErrors }`, with one `GATEWAY_ERROR`
74
+ * userError when the gateway rejects the call or it could not be issued. `reachedGateway` is `false`
75
+ * only when no request was issued; every outcome it cannot classify is `true`.
74
76
  */
75
- sendPayments: (request: SendPaymentsRequest) => Promise<readonly PaymentUserError[]>;
77
+ sendPayments: (request: SendPaymentsRequest) => Promise<PaymentGatewayResult>;
76
78
  }>;
77
79
  //#endregion
78
80
  //# sourceMappingURL=use-payment-actions.d.ts.map
@@ -110,7 +110,10 @@ function usePaymentActions() {
110
110
  return await postPaymentsToGateway(request);
111
111
  } catch (error) {
112
112
  console.error("[payment.sendPayments] gateway request failed", loggableErrorName(error));
113
- return [PAYMENT_GATEWAY_USER_ERROR];
113
+ return {
114
+ reachedGateway: true,
115
+ userErrors: [PAYMENT_GATEWAY_USER_ERROR]
116
+ };
114
117
  }
115
118
  }, []);
116
119
  return useMemo(() => ({
@@ -243,7 +246,7 @@ defineActions({
243
246
  }]
244
247
  },
245
248
  sendPayments: {
246
- description: "Façade: post the card directly from the browser to the payment gateway. Issues no GraphQL operation and writes nothing to the cache. The card number and CVV are runtime-only arguments and are deliberately absent from this payload — they are never a bindable field (RFC D13).",
249
+ description: "Façade: post the card directly from the browser to the payment gateway. Issues no GraphQL operation and writes nothing to the cache. Resolves { reachedGateway, userErrors }: reachedGateway is false only when no request was issued. The card number and CVV are runtime-only arguments and are deliberately absent from this payload — they are never a bindable field (RFC D13).",
247
250
  payload: [
248
251
  {
249
252
  name: "gatewayUrl",