@vtex/faststore 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/actions.json +181 -0
  3. package/dist/catalog.json +1595 -481
  4. package/dist/client.d.ts +2 -1
  5. package/dist/client.js +2 -1
  6. package/dist/components.d.ts +31 -7
  7. package/dist/components.js +35 -13
  8. package/dist/content-types.json +73 -0
  9. package/dist/docs/access-code-sign-in.md +1 -1
  10. package/dist/docs/account-access-gate.md +153 -0
  11. package/dist/docs/account-entry-point.md +1 -2
  12. package/dist/docs/account-menu.md +164 -0
  13. package/dist/docs/address-summary.md +24 -3
  14. package/dist/docs/alert-dialog.md +204 -0
  15. package/dist/docs/billing-address.md +284 -0
  16. package/dist/docs/buy-button.md +1 -1
  17. package/dist/docs/card-entry.md +250 -0
  18. package/dist/docs/cardholder-document.md +142 -0
  19. package/dist/docs/cart.md +1 -1
  20. package/dist/docs/client-preferences-fieldset.md +148 -0
  21. package/dist/docs/client-preferences.md +2 -1
  22. package/dist/docs/client-profile-fieldset.md +184 -0
  23. package/dist/docs/client-profile.md +1 -1
  24. package/dist/docs/document-field.md +58 -4
  25. package/dist/docs/field.md +317 -0
  26. package/dist/docs/form.md +307 -0
  27. package/dist/docs/identity-edit.md +6 -6
  28. package/dist/docs/identity-summary.md +5 -5
  29. package/dist/docs/installments.md +248 -0
  30. package/dist/docs/my-account-profile.md +1 -0
  31. package/dist/docs/order-placed-payment-summary.md +138 -0
  32. package/dist/docs/payment-method-badges.md +232 -0
  33. package/dist/docs/payment-methods.md +1 -0
  34. package/dist/docs/payment.md +218 -0
  35. package/dist/docs/phone-field.md +58 -4
  36. package/dist/docs/place-order.md +157 -0
  37. package/dist/docs/save-card.md +186 -0
  38. package/dist/docs/saved-cards.md +218 -0
  39. package/dist/docs/select.md +465 -0
  40. package/dist/docs/session.md +1 -1
  41. package/dist/docs/shipping-address.md +110 -258
  42. package/dist/docs/sign-in-redirect.md +1 -1
  43. package/dist/index.d.ts +4 -1
  44. package/dist/internal/client.d.ts +3 -1
  45. package/dist/internal/client.js +3 -1
  46. package/dist/matter/access-code-sign-in/access-code-sign-in.js +9 -8
  47. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -1
  48. package/dist/matter/account-access-gate/account-access-gate.d.ts +86 -0
  49. package/dist/matter/account-access-gate/account-access-gate.js +283 -0
  50. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -0
  51. package/dist/matter/account-access-gate/sign-out-intent.d.ts +17 -0
  52. package/dist/matter/account-access-gate/sign-out-intent.js +62 -0
  53. package/dist/matter/account-access-gate/sign-out-intent.js.map +1 -0
  54. package/dist/matter/account-entry-point/account-entry-point.js +2 -2
  55. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  56. package/dist/matter/account-menu/account-menu.d.ts +88 -0
  57. package/dist/matter/account-menu/account-menu.js +246 -0
  58. package/dist/matter/account-menu/account-menu.js.map +1 -0
  59. package/dist/matter/billing-address/billing-address.d.ts +165 -0
  60. package/dist/matter/billing-address/billing-address.js +408 -0
  61. package/dist/matter/billing-address/billing-address.js.map +1 -0
  62. package/dist/matter/card-entry/card-capture.d.ts +25 -0
  63. package/dist/matter/card-entry/card-capture.js +25 -0
  64. package/dist/matter/card-entry/card-capture.js.map +1 -0
  65. package/dist/matter/card-entry/card-entry.d.ts +120 -0
  66. package/dist/matter/card-entry/card-entry.js +832 -0
  67. package/dist/matter/card-entry/card-entry.js.map +1 -0
  68. package/dist/matter/cardholder-document/cardholder-document.d.ts +45 -0
  69. package/dist/matter/cardholder-document/cardholder-document.js +70 -0
  70. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -0
  71. package/dist/matter/cart/cart.d.ts +1 -1
  72. package/dist/matter/cart/cart.js +2 -2
  73. package/dist/matter/cart/cart.js.map +1 -1
  74. package/dist/matter/client-preferences/client-preferences-fieldset.d.ts +77 -0
  75. package/dist/matter/client-preferences/client-preferences-fieldset.js +299 -0
  76. package/dist/matter/client-preferences/client-preferences-fieldset.js.map +1 -0
  77. package/dist/matter/client-preferences/client-preferences.d.ts +3 -5
  78. package/dist/matter/client-preferences/client-preferences.js +6 -6
  79. package/dist/matter/client-preferences/client-preferences.js.map +1 -1
  80. package/dist/matter/client-profile/client-profile.d.ts +4 -6
  81. package/dist/matter/client-profile/client-profile.js +9 -6
  82. package/dist/matter/client-profile/client-profile.js.map +1 -1
  83. package/dist/matter/client-profile-form/client-profile-fieldset.d.ts +119 -0
  84. package/dist/matter/client-profile-form/client-profile-fieldset.js +488 -0
  85. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -0
  86. package/dist/matter/delivery-options/delivery-options.js.map +1 -1
  87. package/dist/matter/identity-edit/identity-edit.js +2 -2
  88. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  89. package/dist/matter/identity-summary/identity-summary.js +2 -2
  90. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  91. package/dist/matter/installments/installments-select.d.ts +42 -0
  92. package/dist/matter/installments/installments-select.js +167 -0
  93. package/dist/matter/installments/installments-select.js.map +1 -0
  94. package/dist/matter/installments/installments.d.ts +58 -0
  95. package/dist/matter/installments/installments.js +176 -0
  96. package/dist/matter/installments/installments.js.map +1 -0
  97. package/dist/matter/installments/use-installments-selection.d.ts +29 -0
  98. package/dist/matter/installments/use-installments-selection.js +95 -0
  99. package/dist/matter/installments/use-installments-selection.js.map +1 -0
  100. package/dist/matter/my-account-profile/my-account-profile.js +5 -5
  101. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  102. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +63 -0
  103. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +305 -0
  104. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -0
  105. package/dist/matter/payment/payment-card-capture.d.ts +19 -0
  106. package/dist/matter/payment/payment-card-capture.js +129 -0
  107. package/dist/matter/payment/payment-card-capture.js.map +1 -0
  108. package/dist/matter/payment/payment-controller.d.ts +24 -0
  109. package/dist/matter/payment/payment-controller.js +107 -0
  110. package/dist/matter/payment/payment-controller.js.map +1 -0
  111. package/dist/matter/payment/payment-method-badges.d.ts +57 -0
  112. package/dist/matter/payment/payment-method-badges.js +192 -0
  113. package/dist/matter/payment/payment-method-badges.js.map +1 -0
  114. package/dist/matter/payment/payment.d.ts +89 -0
  115. package/dist/matter/payment/payment.js +263 -0
  116. package/dist/matter/payment/payment.js.map +1 -0
  117. package/dist/matter/payment/use-payment-method-selection.d.ts +302 -0
  118. package/dist/matter/payment/use-payment-method-selection.js +458 -0
  119. package/dist/matter/payment/use-payment-method-selection.js.map +1 -0
  120. package/dist/matter/payment/use-payment-submit-gate.d.ts +111 -0
  121. package/dist/matter/payment/use-payment-submit-gate.js +144 -0
  122. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -0
  123. package/dist/matter/place-order/place-order.d.ts +74 -0
  124. package/dist/matter/place-order/place-order.js +379 -0
  125. package/dist/matter/place-order/place-order.js.map +1 -0
  126. package/dist/matter/product-list/product-list.d.ts +1 -0
  127. package/dist/matter/product-list/product-list.js.map +1 -1
  128. package/dist/matter/product-shelf/product-shelf.d.ts +1 -0
  129. package/dist/matter/product-shelf/product-shelf.js +2 -0
  130. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  131. package/dist/matter/region/region.js +1 -1
  132. package/dist/matter/region/region.js.map +1 -1
  133. package/dist/matter/save-card/save-card.d.ts +49 -0
  134. package/dist/matter/save-card/save-card.js +188 -0
  135. package/dist/matter/save-card/save-card.js.map +1 -0
  136. package/dist/matter/saved-cards/saved-cards.d.ts +79 -0
  137. package/dist/matter/saved-cards/saved-cards.js +387 -0
  138. package/dist/matter/saved-cards/saved-cards.js.map +1 -0
  139. package/dist/matter/shipping-address/country-descriptors.js +20 -10
  140. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  141. package/dist/matter/shipping-address/shipping-address.d.ts +113 -174
  142. package/dist/matter/shipping-address/shipping-address.js +481 -792
  143. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  144. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  145. package/dist/matter/variant-selector/variant-selector.js +1 -1
  146. package/dist/particles/address-summary/address-summary.d.ts +24 -0
  147. package/dist/particles/address-summary/address-summary.js +83 -2
  148. package/dist/particles/address-summary/address-summary.js.map +1 -1
  149. package/dist/particles/alert-dialog/alert-dialog.d.ts +68 -0
  150. package/dist/particles/alert-dialog/alert-dialog.js +187 -0
  151. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -0
  152. package/dist/particles/checkbox/checkbox.d.ts +7 -3
  153. package/dist/particles/checkbox/checkbox.js +4 -1
  154. package/dist/particles/checkbox/checkbox.js.map +1 -1
  155. package/dist/particles/document-field/document-field.d.ts +48 -5
  156. package/dist/particles/document-field/document-field.js +189 -32
  157. package/dist/particles/document-field/document-field.js.map +1 -1
  158. package/dist/particles/field/bound-field-registry.js +52 -0
  159. package/dist/particles/field/bound-field-registry.js.map +1 -0
  160. package/dist/particles/field/field.d.ts +116 -0
  161. package/dist/particles/field/field.js +497 -6
  162. package/dist/particles/field/field.js.map +1 -1
  163. package/dist/particles/fieldset/fieldset.js +2 -2
  164. package/dist/particles/fieldset/fieldset.js.map +1 -1
  165. package/dist/particles/footer-social/footer-social.js +1 -1
  166. package/dist/particles/form/form.d.ts +104 -0
  167. package/dist/particles/form/form.js +485 -0
  168. package/dist/particles/form/form.js.map +1 -0
  169. package/dist/particles/incentives/incentives.js +1 -1
  170. package/dist/particles/phone-field/phone-field.d.ts +38 -10
  171. package/dist/particles/phone-field/phone-field.js +183 -39
  172. package/dist/particles/phone-field/phone-field.js.map +1 -1
  173. package/dist/particles/postal-code-field/postal-code-field.js +2 -2
  174. package/dist/particles/postal-code-field/postal-code-field.js.map +1 -1
  175. package/dist/particles/select/field-select.d.ts +43 -0
  176. package/dist/particles/select/field-select.js +150 -0
  177. package/dist/particles/select/field-select.js.map +1 -0
  178. package/dist/particles/select/select.d.ts +2 -0
  179. package/dist/particles/select/select.js.map +1 -1
  180. package/dist/particles/shared/compose-refs.js +21 -0
  181. package/dist/particles/shared/compose-refs.js.map +1 -0
  182. package/dist/schema.graphql +701 -2
  183. package/dist/sdk/actions/analytics-action-provider.d.ts +15 -0
  184. package/dist/sdk/actions/analytics-action-provider.js +19 -0
  185. package/dist/sdk/actions/analytics-action-provider.js.map +1 -0
  186. package/dist/sdk/actions/cart-action-provider.d.ts +1 -1
  187. package/dist/sdk/actions/cart-action-provider.js +1 -1
  188. package/dist/sdk/actions/cart-action-provider.js.map +1 -1
  189. package/dist/sdk/actions/index.d.ts +3 -1
  190. package/dist/sdk/actions/index.js +3 -1
  191. package/dist/sdk/actions/payment-action-provider.d.ts +22 -0
  192. package/dist/sdk/actions/payment-action-provider.js +26 -0
  193. package/dist/sdk/actions/payment-action-provider.js.map +1 -0
  194. package/dist/sdk/actions/session-action-provider.d.ts +1 -1
  195. package/dist/sdk/actions/session-action-provider.js +1 -1
  196. package/dist/sdk/actions/session-action-provider.js.map +1 -1
  197. package/dist/sdk/actions/shipping-action-provider.d.ts +1 -1
  198. package/dist/sdk/actions/shipping-action-provider.js +1 -1
  199. package/dist/sdk/actions/shipping-action-provider.js.map +1 -1
  200. package/dist/sdk/actions/types.d.ts +6 -2
  201. package/dist/sdk/analytics/analytics-destination.d.ts +43 -0
  202. package/dist/sdk/analytics/analytics-destination.js +90 -0
  203. package/dist/sdk/analytics/analytics-destination.js.map +1 -0
  204. package/dist/sdk/analytics/use-analytics-actions.d.ts +57 -0
  205. package/dist/sdk/analytics/use-analytics-actions.js +108 -0
  206. package/dist/sdk/analytics/use-analytics-actions.js.map +1 -0
  207. package/dist/sdk/cache/storefront-cache.js +1 -1
  208. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  209. package/dist/sdk/cart/operations.d.ts +4 -4
  210. package/dist/sdk/cart/operations.js +1 -1
  211. package/dist/sdk/cart/operations.js.map +1 -1
  212. package/dist/sdk/cart/optimistic.js +1 -1
  213. package/dist/sdk/cart/optimistic.js.map +1 -1
  214. package/dist/sdk/cart/use-cart-actions.d.ts +1 -1
  215. package/dist/sdk/cart/use-cart-actions.js +4 -4
  216. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  217. package/dist/sdk/cart/use-cart-validate-on-open.js +1 -1
  218. package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -1
  219. package/dist/sdk/cart/write-gate.js +1 -1
  220. package/dist/sdk/cart/write-gate.js.map +1 -1
  221. package/dist/sdk/data/entity-resolution-context.js +31 -0
  222. package/dist/sdk/data/entity-resolution-context.js.map +1 -0
  223. package/dist/sdk/data/entity-subscriber.js +18 -8
  224. package/dist/sdk/data/entity-subscriber.js.map +1 -1
  225. package/dist/sdk/data/index.js +1 -0
  226. package/dist/sdk/data/page-reactive-data-root.d.ts +38 -2
  227. package/dist/sdk/data/page-reactive-data-root.js +4 -2
  228. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  229. package/dist/sdk/data/reactive-data-provider.d.ts +1 -1
  230. package/dist/sdk/data/reactive-data-provider.js +8 -4
  231. package/dist/sdk/data/reactive-data-provider.js.map +1 -1
  232. package/dist/sdk/data/reactive-list-item-data-provider.d.ts +1 -1
  233. package/dist/sdk/data/reactive-list-item-data-provider.js +13 -5
  234. package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -1
  235. package/dist/sdk/data/use-reactive-data-settled.js +39 -0
  236. package/dist/sdk/data/use-reactive-data-settled.js.map +1 -0
  237. package/dist/sdk/data/use-reactive-entity.js +6 -2
  238. package/dist/sdk/data/use-reactive-entity.js.map +1 -1
  239. package/dist/sdk/generated/fragment-types.js +2 -0
  240. package/dist/sdk/generated/fragment-types.js.map +1 -1
  241. package/dist/sdk/generated/gql.js +2 -1
  242. package/dist/sdk/generated/gql.js.map +1 -1
  243. package/dist/sdk/generated/graphql.js +85 -1
  244. package/dist/sdk/generated/graphql.js.map +1 -1
  245. package/dist/sdk/i18n/messages/en-US.js +3 -0
  246. package/dist/sdk/i18n/messages/en-US.json +3 -0
  247. package/dist/sdk/i18n/messages/en-US.json.d.ts +3 -0
  248. package/dist/sdk/i18n/messages/es-ES.js +3 -0
  249. package/dist/sdk/i18n/messages/es-ES.json +3 -0
  250. package/dist/sdk/i18n/messages/pt-BR.js +3 -0
  251. package/dist/sdk/i18n/messages/pt-BR.json +3 -0
  252. package/dist/sdk/identity/operations.js.map +1 -1
  253. package/dist/sdk/identity/use-identity-actions.d.ts +1 -1
  254. package/dist/sdk/identity/use-identity-actions.js +3 -2
  255. package/dist/sdk/identity/use-identity-actions.js.map +1 -1
  256. package/dist/sdk/payment/gateway-origin.js +35 -0
  257. package/dist/sdk/payment/gateway-origin.js.map +1 -0
  258. package/dist/sdk/payment/gateway.d.ts +85 -0
  259. package/dist/sdk/payment/gateway.js +183 -0
  260. package/dist/sdk/payment/gateway.js.map +1 -0
  261. package/dist/sdk/payment/operations.d.ts +52 -0
  262. package/dist/sdk/payment/operations.js +223 -0
  263. package/dist/sdk/payment/operations.js.map +1 -0
  264. package/dist/sdk/payment/security-code-mask.js +71 -0
  265. package/dist/sdk/payment/security-code-mask.js.map +1 -0
  266. package/dist/sdk/payment/submission-registry.d.ts +33 -0
  267. package/dist/sdk/payment/submission-registry.js +58 -0
  268. package/dist/sdk/payment/submission-registry.js.map +1 -0
  269. package/dist/sdk/payment/use-payment-actions.d.ts +78 -0
  270. package/dist/sdk/payment/use-payment-actions.js +276 -0
  271. package/dist/sdk/payment/use-payment-actions.js.map +1 -0
  272. package/dist/sdk/payment/use-place-order.d.ts +65 -0
  273. package/dist/sdk/payment/use-place-order.js +640 -0
  274. package/dist/sdk/payment/use-place-order.js.map +1 -0
  275. package/dist/sdk/session/auth-operations.d.ts +1 -1
  276. package/dist/sdk/session/auth-operations.js.map +1 -1
  277. package/dist/sdk/session/use-session-actions.d.ts +1 -1
  278. package/dist/sdk/session/use-session-actions.js.map +1 -1
  279. package/dist/sdk/session/use-session-revalidation.js +65 -0
  280. package/dist/sdk/session/use-session-revalidation.js.map +1 -0
  281. package/dist/sdk/shipping/option-select-operations.d.ts +1 -1
  282. package/dist/sdk/shipping/option-select-operations.js.map +1 -1
  283. package/dist/sdk/shipping/request-timeout.js +1 -1
  284. package/dist/sdk/shipping/request-timeout.js.map +1 -1
  285. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  286. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  287. package/dist/sdk/shipping/use-shipping-actions.d.ts +2 -2
  288. package/dist/sdk/shipping/use-shipping-actions.js +1 -1
  289. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -1
  290. package/dist/sdk/state/cart.d.ts +3 -4
  291. package/dist/sdk/state/cart.js +6 -7
  292. package/dist/sdk/state/cart.js.map +1 -1
  293. package/dist/utils/loggable-error-name.js +49 -0
  294. package/dist/utils/loggable-error-name.js.map +1 -0
  295. package/dist/utils/resolve-authored-copy.js +18 -0
  296. package/dist/utils/resolve-authored-copy.js.map +1 -0
  297. package/dist/utils/safe-href.js +3 -3
  298. package/dist/utils/safe-href.js.map +1 -1
  299. package/dist/utils/substitute-template.js +33 -0
  300. package/dist/utils/substitute-template.js.map +1 -0
  301. package/package.json +2 -1
  302. package/src/styles/tailwind.css +34 -0
  303. package/dist/docs/client-profile-form.md +0 -192
  304. package/dist/matter/client-profile-form/client-profile-form.d.ts +0 -126
  305. package/dist/matter/client-profile-form/client-profile-form.js +0 -662
  306. package/dist/matter/client-profile-form/client-profile-form.js.map +0 -1
@@ -1,6 +1,9 @@
1
1
  //#region src/sdk/i18n/messages/en-US.json
2
2
  var en_US_default = {
3
3
  "fs/a11y.close": "Close",
4
+ "fs/form.clear": "Clear",
5
+ "fs/form.reset": "Reset",
6
+ "fs/form.submit": "Continue",
4
7
  "fs/region.error.invalid-postal-code": "Enter a valid postal code.",
5
8
  "fs/region.error.network": "Unable to set your region. Please try again.",
6
9
  "fs/region.error.unserved-postal-code": "We do not deliver to this postal code yet.",
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "fs/a11y.close": "Close",
3
+ "fs/form.clear": "Clear",
4
+ "fs/form.reset": "Reset",
5
+ "fs/form.submit": "Continue",
3
6
  "fs/region.error.invalid-postal-code": "Enter a valid postal code.",
4
7
  "fs/region.error.network": "Unable to set your region. Please try again.",
5
8
  "fs/region.error.unserved-postal-code": "We do not deliver to this postal code yet.",
@@ -1,6 +1,9 @@
1
1
  //#region src/sdk/i18n/messages/en-US.json.d.ts
2
2
  declare const _exports: {
3
3
  "fs/a11y.close": string;
4
+ "fs/form.clear": string;
5
+ "fs/form.reset": string;
6
+ "fs/form.submit": string;
4
7
  "fs/region.error.invalid-postal-code": string;
5
8
  "fs/region.error.network": string;
6
9
  "fs/region.error.unserved-postal-code": string;
@@ -1,6 +1,9 @@
1
1
  //#region src/sdk/i18n/messages/es-ES.json
2
2
  var es_ES_default = {
3
3
  "fs/a11y.close": "Cerrar",
4
+ "fs/form.clear": "Limpiar",
5
+ "fs/form.reset": "Restablecer",
6
+ "fs/form.submit": "Continuar",
4
7
  "fs/region.error.invalid-postal-code": "Introduce un código postal válido.",
5
8
  "fs/region.error.network": "No se pudo definir tu región. Inténtalo de nuevo.",
6
9
  "fs/region.error.unserved-postal-code": "Todavía no hacemos entregas en este código postal.",
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "fs/a11y.close": "Cerrar",
3
+ "fs/form.clear": "Limpiar",
4
+ "fs/form.reset": "Restablecer",
5
+ "fs/form.submit": "Continuar",
3
6
  "fs/region.error.invalid-postal-code": "Introduce un código postal válido.",
4
7
  "fs/region.error.network": "No se pudo definir tu región. Inténtalo de nuevo.",
5
8
  "fs/region.error.unserved-postal-code": "Todavía no hacemos entregas en este código postal.",
@@ -1,6 +1,9 @@
1
1
  //#region src/sdk/i18n/messages/pt-BR.json
2
2
  var pt_BR_default = {
3
3
  "fs/a11y.close": "Fechar",
4
+ "fs/form.clear": "Limpar",
5
+ "fs/form.reset": "Redefinir",
6
+ "fs/form.submit": "Continuar",
4
7
  "fs/region.error.invalid-postal-code": "Informe um CEP válido.",
5
8
  "fs/region.error.network": "Não foi possível definir sua região. Tente novamente.",
6
9
  "fs/region.error.unserved-postal-code": "Ainda não entregamos neste CEP.",
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "fs/a11y.close": "Fechar",
3
+ "fs/form.clear": "Limpar",
4
+ "fs/form.reset": "Redefinir",
5
+ "fs/form.submit": "Continuar",
3
6
  "fs/region.error.invalid-postal-code": "Informe um CEP válido.",
4
7
  "fs/region.error.network": "Não foi possível definir sua região. Tente novamente.",
5
8
  "fs/region.error.unserved-postal-code": "Ainda não entregamos neste CEP.",
@@ -1 +1 @@
1
- {"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/identity/operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Identity (client-profile / client-preferences / customer-profile) GraphQL operations\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * specs/sfs-3286-customer-profile-update-action.md).\n *\n * The first two writes reuse the EXISTING `clientProfileUpdate` / `clientPreferencesUpdate` mutations — partial\n * writes that touch only the fields they are given. `EmailIdentificationControl` sends `{ email }`\n * through `clientProfileUpdate` (flipping `Session.isIdentified`); the consent opt-in Controls send one\n * flag through `clientPreferencesUpdate`. Both live on the User Identity sibling entities of `Cart`,\n * not nested under it.\n *\n * `customerProfileUpdate` is the account-scoped counterpart: it persists to the shopper's saved\n * profile with no cart in play, keyed server-side off the session.\n *\n * Authored with the serializable `gql` tag (not the codegen `graphql()` factory) and explicitly\n * excluded from the codegen `documents` glob (see `codegen.ts`) — the `gql` tag alone is still\n * plucked by `graphql-codegen`, which would duplicate these hand-written types in `sdk/generated/`.\n * The identity writes do not need generated types and stay hand-typed `TypedDocumentNode`s,\n * mirroring how the ShippingSimulator matter authors its raw fragment.\n */\n\n// ---------------------------------------------------------------------------\n// Domain types — mirror the existing checkout schema\n// ---------------------------------------------------------------------------\n\n/** The ClientProfile slice returned by the mutation: the identity-step fields plus the Node identity keys. */\nexport type ClientProfileEntity = Readonly<{\n __typename?: 'ClientProfile';\n id: string;\n email: string | null;\n firstName: string | null;\n lastName: string | null;\n document: string | null;\n phone: string | null;\n}>;\n\n/** A single domain error returned by `clientProfileUpdate` (`ClientProfileUpdateError`). */\nexport type ClientProfileUserError = Readonly<{ code: string; message: string }>;\n\n/** Partial profile input — mirrors the schema's `ClientProfileUpdateInput`; omitted fields are left untouched. */\nexport type ClientProfileUpdateInput = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** The Session slice returned alongside the profile — lets Apollo's normalized cache flip\n * `useSession()`'s isIdentified reactively, with no separate refetch. */\nexport type ClientProfileUpdateSessionEntity = Readonly<{\n __typename?: 'Session';\n id: string;\n loggedIn: boolean;\n canEditData: boolean;\n isIdentified: boolean;\n}>;\n\nexport type ClientProfileUpdateMutation = {\n clientProfileUpdate: {\n __typename?: 'ClientProfileUpdatePayload';\n clientProfile: ClientProfileEntity | null;\n session: ClientProfileUpdateSessionEntity | null;\n userErrors: ClientProfileUserError[];\n };\n};\n\nexport type ClientProfileUpdateMutationVariables = {\n input: ClientProfileUpdateInput;\n};\n\n// ---------------------------------------------------------------------------\n// Mutation operation\n// ---------------------------------------------------------------------------\n\nexport const CLIENT_PROFILE_UPDATE: TypedDocumentNode<\n ClientProfileUpdateMutation,\n ClientProfileUpdateMutationVariables\n> = gql`\n mutation ClientProfileUpdate($input: ClientProfileUpdateInput!) {\n clientProfileUpdate(input: $input) {\n __typename\n clientProfile {\n __typename\n id\n email\n firstName\n lastName\n document\n phone\n }\n session {\n __typename\n id\n loggedIn\n canEditData\n isIdentified\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Client preferences (consent opt-ins) — mirror the profile write\n// ---------------------------------------------------------------------------\n\n/** The ClientPreferences slice this feature reads/writes: the two opt-in flags plus the Node key. */\nexport type ClientPreferencesEntity = Readonly<{\n __typename?: 'ClientPreferences';\n id: string;\n optinNewsLetter: boolean | null;\n savePersonalData: boolean | null;\n}>;\n\n/** The two opt-in fields, keyed exactly as the GraphQL `ClientPreferences` type / input. */\nexport type ClientPreferenceKey = 'optinNewsLetter' | 'savePersonalData';\n\n/** Partial preferences input — a Control sends ONE flag; omitted flags are left untouched. */\nexport type ClientPreferencesUpdateInput = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\nexport type ClientPreferencesUpdateMutation = {\n clientPreferencesUpdate: {\n __typename?: 'ClientPreferencesUpdatePayload';\n clientPreferences: ClientPreferencesEntity | null;\n userErrors: ClientProfileUserError[];\n };\n};\n\nexport type ClientPreferencesUpdateMutationVariables = {\n input: ClientPreferencesUpdateInput;\n};\n\nexport const CLIENT_PREFERENCES_UPDATE: TypedDocumentNode<\n ClientPreferencesUpdateMutation,\n ClientPreferencesUpdateMutationVariables\n> = gql`\n mutation ClientPreferencesUpdate($input: ClientPreferencesUpdateInput!) {\n clientPreferencesUpdate(input: $input) {\n __typename\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Persistent shopper profile — account-scoped, not the cart projection above\n// ---------------------------------------------------------------------------\n\n/** The CustomerProfile slice the mutation returns: every readable field plus the cache key. */\nexport type CustomerProfileEntity = Readonly<{\n __typename?: 'CustomerProfile';\n id: string;\n firstName: string | null;\n lastName: string | null;\n email: string | null;\n homePhone: string | null;\n mobilePhone: string | null;\n document: string | null;\n documentType: string | null;\n birthDate: string | null;\n gender: string | null;\n}>;\n\n/**\n * A single write failure. `code` is a string rather than the server enum because the action adds\n * two client-originated codes — `NETWORK_ERROR` and `UNAUTHORIZED` — to the server's set.\n */\nexport type CustomerProfileUserError = Readonly<{ code: string; message: string }>;\n\n/**\n * Partial profile input — mirrors the schema's `CustomerProfileUpdateInput` verbatim. An omitted\n * field is left untouched upstream; an empty string is an explicit erase. `email` is absent by\n * construction: it is the login identifier and is not writable.\n */\nexport type CustomerProfileUpdateInput = Readonly<{\n firstName?: string;\n lastName?: string;\n homePhone?: string;\n mobilePhone?: string;\n document?: string;\n documentType?: string;\n birthDate?: string;\n gender?: string;\n}>;\n\nexport type CustomerProfileUpdateMutation = {\n customerProfileUpdate: {\n __typename?: 'CustomerProfileUpdatePayload';\n customerProfile: CustomerProfileEntity;\n userErrors: CustomerProfileUserError[];\n };\n};\n\nexport type CustomerProfileUpdateMutationVariables = {\n input: CustomerProfileUpdateInput;\n};\n\n/**\n * Selects the whole entity, not just the written fields: the normalized cache is what re-delivers\n * the new values to the profile Root, so a partial selection would leave it holding stale ones.\n */\nexport const CUSTOMER_PROFILE_UPDATE: TypedDocumentNode<\n CustomerProfileUpdateMutation,\n CustomerProfileUpdateMutationVariables\n> = gql`\n mutation CustomerProfileUpdate($input: CustomerProfileUpdateInput!) {\n customerProfileUpdate(input: $input) {\n __typename\n customerProfile {\n __typename\n id\n firstName\n lastName\n email\n homePhone\n mobilePhone\n document\n documentType\n birthDate\n gender\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n"],"mappings":";;AA8EA,MAAa,wBAGT,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DP,MAAa,4BAGT,GAAG;;;;;;;;;;;;;;;;;;;;;AA2EP,MAAa,0BAGT,GAAG"}
1
+ {"version":3,"file":"operations.js","names":[],"sources":["../../../src/sdk/identity/operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Identity (client-profile / client-preferences / customer-profile) GraphQL operations\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions).\n *\n * The first two writes reuse the EXISTING `clientProfileUpdate` / `clientPreferencesUpdate` mutations — partial\n * writes that touch only the fields they are given. `EmailIdentificationControl` sends `{ email }`\n * through `clientProfileUpdate` (flipping `Session.isIdentified`); the consent opt-in Controls send one\n * flag through `clientPreferencesUpdate`. Both live on the User Identity sibling entities of `Cart`,\n * not nested under it.\n *\n * `customerProfileUpdate` is the account-scoped counterpart: it persists to the shopper's saved\n * profile with no cart in play, keyed server-side off the session.\n *\n * Authored with the serializable `gql` tag (not the codegen `graphql()` factory) and explicitly\n * excluded from the codegen `documents` glob (see `codegen.ts`) — the `gql` tag alone is still\n * plucked by `graphql-codegen`, which would duplicate these hand-written types in `sdk/generated/`.\n * The identity writes do not need generated types and stay hand-typed `TypedDocumentNode`s,\n * mirroring how the ShippingSimulator matter authors its raw fragment.\n */\n\n// ---------------------------------------------------------------------------\n// Domain types — mirror the existing checkout schema\n// ---------------------------------------------------------------------------\n\n/** The ClientProfile slice returned by the mutation: the identity-step fields plus the Node identity keys. */\nexport type ClientProfileEntity = Readonly<{\n __typename?: 'ClientProfile';\n id: string;\n email: string | null;\n firstName: string | null;\n lastName: string | null;\n document: string | null;\n phone: string | null;\n}>;\n\n/** A single domain error returned by `clientProfileUpdate` (`ClientProfileUpdateError`). */\nexport type ClientProfileUserError = Readonly<{ code: string; message: string }>;\n\n/** Partial profile input — mirrors the schema's `ClientProfileUpdateInput`; omitted fields are left untouched. */\nexport type ClientProfileUpdateInput = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** The Session slice returned alongside the profile — lets Apollo's normalized cache flip\n * `useSession()`'s isIdentified reactively, with no separate refetch. */\nexport type ClientProfileUpdateSessionEntity = Readonly<{\n __typename?: 'Session';\n id: string;\n loggedIn: boolean;\n canEditData: boolean;\n isIdentified: boolean;\n}>;\n\nexport type ClientProfileUpdateMutation = {\n clientProfileUpdate: {\n __typename?: 'ClientProfileUpdatePayload';\n clientProfile: ClientProfileEntity | null;\n session: ClientProfileUpdateSessionEntity | null;\n userErrors: ClientProfileUserError[];\n };\n};\n\nexport type ClientProfileUpdateMutationVariables = {\n input: ClientProfileUpdateInput;\n};\n\n// ---------------------------------------------------------------------------\n// Mutation operation\n// ---------------------------------------------------------------------------\n\nexport const CLIENT_PROFILE_UPDATE: TypedDocumentNode<\n ClientProfileUpdateMutation,\n ClientProfileUpdateMutationVariables\n> = gql`\n mutation ClientProfileUpdate($input: ClientProfileUpdateInput!) {\n clientProfileUpdate(input: $input) {\n __typename\n clientProfile {\n __typename\n id\n email\n firstName\n lastName\n document\n phone\n }\n session {\n __typename\n id\n loggedIn\n canEditData\n isIdentified\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Client preferences (consent opt-ins) — mirror the profile write\n// ---------------------------------------------------------------------------\n\n/** The ClientPreferences slice this feature reads/writes: the two opt-in flags plus the Node key. */\nexport type ClientPreferencesEntity = Readonly<{\n __typename?: 'ClientPreferences';\n id: string;\n optinNewsLetter: boolean | null;\n savePersonalData: boolean | null;\n}>;\n\n/** The two opt-in fields, keyed exactly as the GraphQL `ClientPreferences` type / input. */\nexport type ClientPreferenceKey = 'optinNewsLetter' | 'savePersonalData';\n\n/** Partial preferences input — a Control sends ONE flag; omitted flags are left untouched. */\nexport type ClientPreferencesUpdateInput = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\nexport type ClientPreferencesUpdateMutation = {\n clientPreferencesUpdate: {\n __typename?: 'ClientPreferencesUpdatePayload';\n clientPreferences: ClientPreferencesEntity | null;\n userErrors: ClientProfileUserError[];\n };\n};\n\nexport type ClientPreferencesUpdateMutationVariables = {\n input: ClientPreferencesUpdateInput;\n};\n\nexport const CLIENT_PREFERENCES_UPDATE: TypedDocumentNode<\n ClientPreferencesUpdateMutation,\n ClientPreferencesUpdateMutationVariables\n> = gql`\n mutation ClientPreferencesUpdate($input: ClientPreferencesUpdateInput!) {\n clientPreferencesUpdate(input: $input) {\n __typename\n clientPreferences {\n __typename\n id\n optinNewsLetter\n savePersonalData\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Persistent shopper profile — account-scoped, not the cart projection above\n// ---------------------------------------------------------------------------\n\n/** The CustomerProfile slice the mutation returns: every readable field plus the cache key. */\nexport type CustomerProfileEntity = Readonly<{\n __typename?: 'CustomerProfile';\n id: string;\n firstName: string | null;\n lastName: string | null;\n email: string | null;\n homePhone: string | null;\n mobilePhone: string | null;\n document: string | null;\n documentType: string | null;\n birthDate: string | null;\n gender: string | null;\n}>;\n\n/**\n * A single write failure. `code` is a string rather than the server enum because the action adds\n * two client-originated codes — `NETWORK_ERROR` and `UNAUTHORIZED` — to the server's set.\n */\nexport type CustomerProfileUserError = Readonly<{ code: string; message: string }>;\n\n/**\n * Partial profile input — mirrors the schema's `CustomerProfileUpdateInput` verbatim. An omitted\n * field is left untouched upstream; an empty string is an explicit erase. `email` is absent by\n * construction: it is the login identifier and is not writable.\n */\nexport type CustomerProfileUpdateInput = Readonly<{\n firstName?: string;\n lastName?: string;\n homePhone?: string;\n mobilePhone?: string;\n document?: string;\n documentType?: string;\n birthDate?: string;\n gender?: string;\n}>;\n\nexport type CustomerProfileUpdateMutation = {\n customerProfileUpdate: {\n __typename?: 'CustomerProfileUpdatePayload';\n customerProfile: CustomerProfileEntity;\n userErrors: CustomerProfileUserError[];\n };\n};\n\nexport type CustomerProfileUpdateMutationVariables = {\n input: CustomerProfileUpdateInput;\n};\n\n/**\n * Selects the whole entity, not just the written fields: the normalized cache is what re-delivers\n * the new values to the profile Root, so a partial selection would leave it holding stale ones.\n */\nexport const CUSTOMER_PROFILE_UPDATE: TypedDocumentNode<\n CustomerProfileUpdateMutation,\n CustomerProfileUpdateMutationVariables\n> = gql`\n mutation CustomerProfileUpdate($input: CustomerProfileUpdateInput!) {\n customerProfileUpdate(input: $input) {\n __typename\n customerProfile {\n __typename\n id\n firstName\n lastName\n email\n homePhone\n mobilePhone\n document\n documentType\n birthDate\n gender\n }\n userErrors {\n code\n message\n }\n }\n }\n`;\n"],"mappings":";;AA8EA,MAAa,wBAGT,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DP,MAAa,4BAGT,GAAG;;;;;;;;;;;;;;;;;;;;;AA2EP,MAAa,0BAGT,GAAG"}
@@ -5,7 +5,7 @@ import { ClientPreferenceKey, ClientProfileUserError, CustomerProfileUpdateInput
5
5
  * The `identity` action namespace — the context-free owner of the shopper-profile,
6
6
  * consent-preference, and persistent-profile writes
7
7
  * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,
8
- * specs/sfs-3286-customer-profile-update-action.md,
8
+ * docs/storefront-core/reference-free-particle-model.md § Write side — actions,
9
9
  * docs/storefront-core/adr-0010-actions-own-the-write-side.md).
10
10
  *
11
11
  * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { defineActions } from "../../core/dist/actions/registry.js";
3
3
  import "../../core/dist/index.js";
4
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
4
5
  import { CLIENT_PREFERENCES_UPDATE, CLIENT_PROFILE_UPDATE, CUSTOMER_PROFILE_UPDATE } from "./operations.js";
5
6
  import { useMutation } from "@apollo/client/react";
6
7
  import { useCallback, useMemo } from "react";
@@ -46,7 +47,7 @@ function useIdentityActions() {
46
47
  try {
47
48
  return (await profileMutation({ variables: { input: payload } })).data?.clientProfileUpdate?.userErrors ?? [];
48
49
  } catch (error) {
49
- console.error("[identity.clientProfileUpdate] clientProfileUpdate failed", error instanceof Error ? error.name : "UnknownError");
50
+ console.error("[identity.clientProfileUpdate] clientProfileUpdate failed", loggableErrorName(error));
50
51
  return [NETWORK_PROFILE_ERROR];
51
52
  }
52
53
  }, [profileMutation]);
@@ -54,7 +55,7 @@ function useIdentityActions() {
54
55
  try {
55
56
  return (await preferencesMutation({ variables: { input: payload } })).data?.clientPreferencesUpdate?.userErrors ?? [];
56
57
  } catch (error) {
57
- console.error("[identity.clientPreferencesUpdate] clientPreferencesUpdate failed", error instanceof Error ? error.name : "UnknownError");
58
+ console.error("[identity.clientPreferencesUpdate] clientPreferencesUpdate failed", loggableErrorName(error));
58
59
  return [NETWORK_PREFERENCE_ERROR];
59
60
  }
60
61
  }, [preferencesMutation]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * specs/sfs-3286-customer-profile-update-action.md,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile module answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError`. Collapsing it into `NETWORK_ERROR` would offer a retry that cannot succeed, so it\n * gets its own code and the caller can send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error(\n '[identity.clientProfileUpdate] clientProfileUpdate failed',\n error instanceof Error ? error.name : 'UnknownError',\n );\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error(\n '[identity.clientPreferencesUpdate] clientPreferencesUpdate failed',\n error instanceof Error ? error.name : 'UnknownError',\n );\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error(\n '[identity.customerProfileUpdate] customerProfileUpdate failed',\n error instanceof Error ? error.name : 'UnknownError',\n );\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-identity-actions.js","names":[],"sources":["../../../src/sdk/identity/use-identity-actions.ts"],"sourcesContent":["'use client';\n\nimport { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { useMutation } from '@apollo/client/react';\nimport { defineActions } from '@vtex/fs-core';\nimport { useCallback, useMemo } from 'react';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport {\n CLIENT_PREFERENCES_UPDATE,\n CLIENT_PROFILE_UPDATE,\n type ClientPreferenceKey,\n type ClientProfileUserError,\n CUSTOMER_PROFILE_UPDATE,\n type CustomerProfileUpdateInput,\n type CustomerProfileUserError,\n} from './operations.js';\n\n/**\n * The `identity` action namespace — the context-free owner of the shopper-profile,\n * consent-preference, and persistent-profile writes\n * (specs/fspg-859-email-field.md, specs/consent-opt-in-component.md,\n * docs/storefront-core/reference-free-particle-model.md § Write side — actions,\n * docs/storefront-core/adr-0010-actions-own-the-write-side.md).\n *\n * It mirrors `useCartActions`: a component anywhere in the tree dispatches the write through the\n * compiler-injected `$actions.identity.*` prop, and the handler calls the corresponding mutation.\n * Every write is **async / pessimistic** (Decision 1): the caller awaits the persisted result. Each\n * call returns its `userErrors` (empty on success) so the caller can surface server-side failures\n * inline; the returned entity self-updates the normalized cache and every reactive subscriber.\n *\n * The first two writes target the cart's sibling identity entities; `customerProfileUpdate` targets\n * the shopper's account profile, which needs no cart at all.\n */\n\n/**\n * Payload for the profile write. Callers persist only the fields they own; other fields are\n * untouched. The payload is passed through to `ClientProfileUpdateInput` unmapped, so this type\n * mirrors that input verbatim — a stacked field only needs a field to already exist here to reach\n * the wire.\n */\nexport type ClientProfileUpdatePayload = Readonly<{\n email?: string;\n firstName?: string;\n lastName?: string;\n phone?: string;\n document?: string;\n}>;\n\n/** Payload for the preferences write — one opt-in flag; the other flag is left untouched. */\nexport type ClientPreferencesUpdatePayload = Readonly<Partial<Record<ClientPreferenceKey, boolean>>>;\n\n/**\n * Payload for the persistent-profile write. Mirrors `CustomerProfileUpdateInput` verbatim and is\n * forwarded unmapped, so an omitted field stays untouched upstream and an empty string erases.\n */\nexport type CustomerProfileUpdatePayload = CustomerProfileUpdateInput;\n\nexport type IdentityActions = Readonly<{\n /**\n * Persist the provided profile fields (partial) to the active cart's `clientProfileData`.\n * Async — awaits the mutation before resolving. Returns the resulting `userErrors` (empty on\n * success).\n */\n clientProfileUpdate: (payload: ClientProfileUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided consent opt-in flag(s) (partial) to the shopper's `ClientPreferences`\n * entity (order-form-backed). Async — awaits the mutation before resolving. Writes ONLY the\n * requested field. Returns the resulting `userErrors` (empty on success).\n */\n clientPreferencesUpdate: (payload: ClientPreferencesUpdatePayload) => Promise<readonly ClientProfileUserError[]>;\n /**\n * Persist the provided profile fields (partial) to the shopper's persistent, cart-independent\n * account profile. Async — awaits the mutation before resolving. Sends exactly the fields it is\n * given: an omitted field is left untouched, an empty string erases. Returns the resulting\n * `userErrors` (empty on success).\n */\n customerProfileUpdate: (payload: CustomerProfileUpdatePayload) => Promise<readonly CustomerProfileUserError[]>;\n}>;\n\nconst NETWORK_PROFILE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your details. Please try again.',\n};\n\nconst NETWORK_PREFERENCE_ERROR: ClientProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your preference. Please try again.',\n};\n\nconst NETWORK_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'NETWORK_ERROR',\n message: 'Unable to save your profile. Please try again.',\n};\n\nconst UNAUTHORIZED_CUSTOMER_PROFILE_ERROR: CustomerProfileUserError = {\n code: 'UNAUTHORIZED',\n message: 'Your session has expired. Please sign in again.',\n};\n\n/**\n * The profile module answers an anonymous or expired session with a top-level `UNAUTHORIZED`, never\n * a `userError`. Collapsing it into `NETWORK_ERROR` would offer a retry that cannot succeed, so it\n * gets its own code and the caller can send the shopper back to sign-in.\n */\nfunction toCustomerProfileError(error: unknown): CustomerProfileUserError {\n if (CombinedGraphQLErrors.is(error)) {\n const unauthorized = error.errors.some(({ extensions }) => extensions?.code === 'UNAUTHORIZED');\n if (unauthorized) return UNAUTHORIZED_CUSTOMER_PROFILE_ERROR;\n }\n return NETWORK_CUSTOMER_PROFILE_ERROR;\n}\n\n/**\n * The `identity` namespace hook. Registered with the first-party action registry via `identityActions`\n * below; the compiler-emitted `IdentityActionProvider` calls it and threads the narrowed methods into\n * each consumer's `$actions.identity`.\n */\nexport function useIdentityActions(): IdentityActions {\n const [profileMutation] = useMutation(CLIENT_PROFILE_UPDATE);\n const [preferencesMutation] = useMutation(CLIENT_PREFERENCES_UPDATE);\n const [customerProfileMutation] = useMutation(CUSTOMER_PROFILE_UPDATE);\n\n const clientProfileUpdate = useCallback<IdentityActions['clientProfileUpdate']>(\n async (payload) => {\n try {\n const result = await profileMutation({ variables: { input: payload } });\n return result.data?.clientProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo the submitted email (PII).\n console.error('[identity.clientProfileUpdate] clientProfileUpdate failed', loggableErrorName(error));\n return [NETWORK_PROFILE_ERROR];\n }\n },\n [profileMutation],\n );\n\n const clientPreferencesUpdate = useCallback<IdentityActions['clientPreferencesUpdate']>(\n async (payload) => {\n try {\n const result = await preferencesMutation({ variables: { input: payload } });\n return result.data?.clientPreferencesUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — mirrors the profile write's PII-safe logging.\n console.error('[identity.clientPreferencesUpdate] clientPreferencesUpdate failed', loggableErrorName(error));\n return [NETWORK_PREFERENCE_ERROR];\n }\n },\n [preferencesMutation],\n );\n\n const customerProfileUpdate = useCallback<IdentityActions['customerProfileUpdate']>(\n async (payload) => {\n try {\n // Forwarded unmapped: an empty string is an explicit erase and must survive to the wire.\n const result = await customerProfileMutation({ variables: { input: payload } });\n return result.data?.customerProfileUpdate?.userErrors ?? [];\n } catch (error) {\n // Log only the error name — the message can echo a submitted profile value (PII).\n console.error(\n '[identity.customerProfileUpdate] customerProfileUpdate failed',\n error instanceof Error ? error.name : 'UnknownError',\n );\n return [toCustomerProfileError(error)];\n }\n },\n [customerProfileMutation],\n );\n\n return useMemo(\n () => ({ clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate }),\n [clientProfileUpdate, clientPreferencesUpdate, customerProfileUpdate],\n );\n}\n\n/**\n * Declares the `identity` action namespace — the single source of truth for its method/payload\n * metadata, runtime provider, and `use` hook (mirrors `cartActions`). The native catalog builder\n * (`scripts/build-catalog.mjs`) statically reads this call to emit `actions.json`; at runtime\n * `IdentityActionProvider` calls `useIdentityActions` directly.\n */\nexport const identityActions = defineActions({\n namespace: 'identity',\n description:\n 'Mutation-backed writes against the shopper identity entities (client profile, consent preferences, account profile).',\n provider: { name: 'IdentityActionProvider', importPath: '@vtex/faststore/internal/client' },\n methods: {\n clientProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the active cart (async strategy). Sending email flips Session.isIdentified.',\n payload: [\n { name: 'email', type: 'string', optional: true },\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'phone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n ],\n },\n clientPreferencesUpdate: {\n description:\n 'Persist consent opt-in flags (partial) to the active cart (async strategy). Writes only the provided flag(s).',\n payload: [\n { name: 'optinNewsLetter', type: 'boolean', optional: true },\n { name: 'savePersonalData', type: 'boolean', optional: true },\n ],\n },\n customerProfileUpdate: {\n description:\n 'Persist profile fields (partial) to the persistent account profile, not the cart (async strategy). Omitted fields are untouched; an empty string erases.',\n payload: [\n { name: 'firstName', type: 'string', optional: true },\n { name: 'lastName', type: 'string', optional: true },\n { name: 'homePhone', type: 'string', optional: true },\n { name: 'mobilePhone', type: 'string', optional: true },\n { name: 'document', type: 'string', optional: true },\n { name: 'documentType', type: 'string', optional: true },\n { name: 'birthDate', type: 'string', optional: true },\n { name: 'gender', type: 'string', optional: true },\n ],\n },\n },\n use: useIdentityActions,\n});\n"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ //#region src/sdk/payment/gateway-origin.ts
2
+ /**
3
+ * 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.
7
+ *
8
+ * `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:
12
+ *
13
+ * - `null` / `undefined` / `''` — the payload's own error shape (T18 nulls every field beside
14
+ * `userErrors`), yielding a relative path.
15
+ * - the four-character string `"null"` — what `new URL('mailto:x').origin` evaluates to, so a
16
+ * non-special scheme upstream survives a parse-only check.
17
+ * - an `http:` origin — parses fine and sends the PAN and CVV unencrypted.
18
+ *
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.
23
+ */
24
+ function isTrustedGatewayOrigin(value) {
25
+ if (!value) return false;
26
+ try {
27
+ return new URL(value).protocol === "https:";
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+ //#endregion
33
+ export { isTrustedGatewayOrigin };
34
+
35
+ //# sourceMappingURL=gateway-origin.js.map
@@ -0,0 +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"}
@@ -0,0 +1,85 @@
1
+ import "./operations.js";
2
+ //#region src/sdk/payment/gateway.d.ts
3
+ /**
4
+ * Non-sensitive descriptor of the open transaction. Every field maps to a value the caller already
5
+ * holds — `paymentStartTransaction`'s payload (T3) or the `Payment` read model (T1) — except
6
+ * `gatewayUrl` and `merchantName`, which that payload does not carry today (Gaps 1 and 2 in the spec).
7
+ * Amounts are in the currency's **minor units**; `PaymentStartTransactionPayload.value.amount` is a
8
+ * decimal, so the caller converts once, visibly, rather than having this module assume an exponent.
9
+ */
10
+ export type PaymentGatewayTransaction = Readonly<{
11
+ /**
12
+ * Gateway origin, e.g. `https://acme.vtexpayments.com.br`. Server-resolved by T18 and read off
13
+ * `paymentStartTransaction`'s payload; never derived here. It is nullable there and required here,
14
+ * so the builder re-checks it (`isTrustedGatewayOrigin`) rather than trusting the type.
15
+ */
16
+ gatewayUrl: string;
17
+ /** `PaymentStartTransactionPayload.transactionId`. */
18
+ transactionId: string;
19
+ /** VTEX merchant name for this transaction. Resolved server-side by T3 but not exposed on its payload. */
20
+ merchantName: string;
21
+ /** `PaymentStartTransactionPayload.orderGroup` — the gateway's `orderId` query parameter. */
22
+ orderGroup: string;
23
+ /** `PaymentStartTransactionPayload.userProfileId`; null for a guest order, so the query parameter is left out. */
24
+ userProfileId: string | null;
25
+ /** `Payment.selectedMethodId` — the VTEX payment-system id. */
26
+ paymentSystem: string;
27
+ /** `PaymentMethod.groupName`, e.g. `creditCardPaymentGroup`. */
28
+ groupName: string;
29
+ /** `PaymentStartTransactionPayload.value.currencyCode`. */
30
+ currencyCode: string;
31
+ /** Transaction total, in minor units. */
32
+ valueInCents: number;
33
+ /** Pre-interest base (`PaymentInstallmentOption.baseValue`), in minor units. */
34
+ referenceValueInCents: number;
35
+ /** `Payment.selectedInstallment.count`; 1 when the shopper never picked a plan. */
36
+ installments: number;
37
+ /** Per-installment amount (`PaymentInstallment.value`), in minor units. */
38
+ installmentsValueInCents: number;
39
+ /** `PaymentInstallment.interestRate`; 0 for the interest-free 1x default. */
40
+ interestRate: number;
41
+ /** Absolute return URL. Phase-2 redirect mode only; omitted in v1's direct mode. */
42
+ callbackUrl?: string;
43
+ /**
44
+ * Billing differs from the delivery address. Defaults to `false`, because `setBillingAddress` persists
45
+ * billing on the order form's `invoiceData` (T3) and the gateway reads it from there rather than from
46
+ * this body. The call site that would override it is T13's `usePlaceOrder`, the one place the
47
+ * descriptor is assembled; T11 owns the live verification of the assumption and publishes the flag to
48
+ * T5's `draft` for T13 to read. Confirming it never reopens this module.
49
+ */
50
+ billingAddressDifferent?: boolean;
51
+ }>;
52
+ /** A newly entered card. Runtime argument only — never declared, never logged, never cached. */
53
+ export type PaymentGatewayNewCard = Readonly<{
54
+ kind: 'new';
55
+ /** Full card number. The builder strips whatever separators the method's `numberMask` inserted. */
56
+ number: string;
57
+ /** Security code (CVV). */
58
+ securityCode: string;
59
+ /** Expiry. Normalized to `MM/YY`, so a `MM/YYYY` mask is accepted. */
60
+ expirationDate: string;
61
+ holderName: string;
62
+ /** Shopper document (a CPF). The builder strips its punctuation. */
63
+ document?: string;
64
+ /** Shopper-assigned label, when the save-card control collected one. */
65
+ cardLabel?: string;
66
+ /** The card-save flag itself — the other half of `payment.saveCard`'s consent write (RFC D5). */
67
+ saveCard?: boolean;
68
+ }>;
69
+ /** A previously saved card: its account reference plus the CVV the shopper re-enters. */
70
+ export type PaymentGatewaySavedCard = Readonly<{
71
+ kind: 'saved';
72
+ /** `SavedCard.accountId`. */
73
+ accountId: string;
74
+ /** `SavedCard.bin` — not sensitive; the read model exposes it for installment lookup. */
75
+ bin: string;
76
+ /** Security code (CVV). */
77
+ securityCode: string;
78
+ }>;
79
+ export type PaymentGatewayCard = PaymentGatewayNewCard | PaymentGatewaySavedCard;
80
+ export type SendPaymentsRequest = Readonly<{
81
+ transaction: PaymentGatewayTransaction;
82
+ card: PaymentGatewayCard;
83
+ }>;
84
+ //#endregion
85
+ //# sourceMappingURL=gateway.d.ts.map
@@ -0,0 +1,183 @@
1
+ import { isTrustedGatewayOrigin } from "./gateway-origin.js";
2
+ //#region src/sdk/payment/gateway.ts
3
+ /**
4
+ * The direct-to-gateway card POST (specs/payment-action-namespace.md, US-6) — the PCI boundary of the
5
+ * credit-card feature. A new card's number and CVV, or a saved card's CVV, go from the browser straight
6
+ * to the VTEX payment gateway and never transit our GraphQL layer or the normalized Apollo cache
7
+ * (RFC D13; ADR-0010's sanctioned façade flavor).
8
+ *
9
+ * This module imports no Apollo and no GraphQL symbol on purpose: the code that holds card data has no
10
+ * route to the cache, and that property is checkable by reading the imports above. Card data arrives as
11
+ * a runtime argument from the card-entry component's local state (T7) — it is never a declared action
12
+ * payload, a fragment field, or a schema-bindable prop, so the AI Store Builder and the visual editor
13
+ * have no name to map a value onto.
14
+ *
15
+ * Nothing on this path is ever logged, serialized, or stored anywhere but the request body: the caller
16
+ * in `use-payment-actions.ts` logs a static message plus the error's `name` only.
17
+ *
18
+ * The request shape is behavior evidence from the legacy checkout
19
+ * (`fastcheckout@cd09bec3`, `packages/apps/client/src/screens/Payment/components/CardForm/services/gateway.service.ts`)
20
+ * — never a port. Where the legacy hardcoded a value under a `TODO` (installment count, interest rate,
21
+ * reference value) this builder reads it off the transaction descriptor instead.
22
+ */
23
+ /** Client-synthesized code for a failed gateway leg — distinct from the BFF's `NETWORK_ERROR`. */
24
+ const PAYMENT_GATEWAY_ERROR_CODE = "GATEWAY_ERROR";
25
+ /** The single userError both a rejected request and a non-2xx response resolve to. */
26
+ const PAYMENT_GATEWAY_USER_ERROR = {
27
+ code: PAYMENT_GATEWAY_ERROR_CODE,
28
+ message: "Unable to complete the payment. Please try again."
29
+ };
30
+ /** VTEX bins the leading eight digits, not six — the legacy's own `sanitizedBin` slice. */
31
+ const BIN_LENGTH = 8;
32
+ /**
33
+ * Strips the separators a mask inserted. `PaymentMethodValidator.numberMask` is server-driven (T1) and the
34
+ * card-entry component (T7) renders the input through it, so its local state holds `4111 1111 1111 1111`
35
+ * rather than the digits. The legacy normalized here, in the builder, before its own BIN slice
36
+ * (`card.cardNumber = card.cardNumber.replace(/ /g, '')`) — the boundary is the one place the obligation
37
+ * cannot be forgotten, and a spaced BIN is a lookup the gateway fails with no diagnosable error.
38
+ */
39
+ function toDigits(value) {
40
+ return value.replace(/\D/g, "");
41
+ }
42
+ /** `MM/YY` whatever the mask produced (`MM/YYYY`, `MMYY`) — the legacy's own two-slice normalization. */
43
+ function toDueDate(expirationDate) {
44
+ const digits = toDigits(expirationDate);
45
+ return `${digits.slice(0, 2)}/${digits.slice(-2)}`;
46
+ }
47
+ /** The card half of the body — the BIN and the `fields` map, both derived from one normalization pass. */
48
+ function toCardBody(card) {
49
+ if (card.kind === "saved") return {
50
+ bin: card.bin,
51
+ fields: {
52
+ bin: card.bin,
53
+ validationCode: card.securityCode
54
+ }
55
+ };
56
+ const number = toDigits(card.number);
57
+ const bin = number.slice(0, BIN_LENGTH);
58
+ return {
59
+ bin,
60
+ fields: {
61
+ bin,
62
+ cardNumber: number,
63
+ document: card.document === void 0 ? null : card.document.replace(/\W/g, ""),
64
+ dueDate: toDueDate(card.expirationDate),
65
+ holderName: card.holderName,
66
+ validationCode: card.securityCode,
67
+ cardLabel: card.cardLabel,
68
+ savePaymentData: card.saveCard ?? false
69
+ }
70
+ };
71
+ }
72
+ /**
73
+ * Builds the gateway URL and body. Billing is deliberately absent from the body: `setBillingAddress`
74
+ * already persisted it on the order form's `invoiceData` (T3), so the gateway reads it from there — hence
75
+ * the `billingAddressDifferent: false` default the two billing flags derive from. `originalPaymentIndex`
76
+ * is the legacy's own constant for a single-payment order.
77
+ *
78
+ * The origin check is the last line of defence, not the first: `usePlaceOrder` already refuses an
79
+ * untrusted origin *before* asking a holder for the card (T13, Decision 4). A builder has no userError
80
+ * channel, so it throws — `sendPayments` catches, collapses it to `GATEWAY_ERROR`, and logs the error's
81
+ * name only, so nothing about the card reaches a log. The throw happens before the body is assembled.
82
+ */
83
+ function buildGatewayPaymentsRequest({ transaction, card }) {
84
+ if (!isTrustedGatewayOrigin(transaction.gatewayUrl)) throw new Error("Refusing to post card data: the transaction carries no trusted https gateway origin.");
85
+ const params = new URLSearchParams({ orderId: transaction.orderGroup });
86
+ if (transaction.userProfileId !== null) params.append("userProfileId", transaction.userProfileId);
87
+ if (transaction.callbackUrl !== void 0) params.append("callbackUrl", transaction.callbackUrl);
88
+ const url = `${transaction.gatewayUrl}/api/pub/transactions/${transaction.transactionId}/payments?${params}`;
89
+ const { bin, fields } = toCardBody(card);
90
+ const billingAddressDifferent = transaction.billingAddressDifferent ?? false;
91
+ return {
92
+ url,
93
+ body: [{
94
+ accountId: card.kind === "saved" ? card.accountId : null,
95
+ bin,
96
+ chooseToUseNewCard: card.kind === "new",
97
+ currencyCode: transaction.currencyCode,
98
+ fields,
99
+ groupName: transaction.groupName,
100
+ hasDefaultBillingAddress: !billingAddressDifferent,
101
+ id: transaction.merchantName,
102
+ installmentValue: transaction.installmentsValueInCents,
103
+ installments: transaction.installments,
104
+ installmentsInterestRate: transaction.interestRate,
105
+ installmentsValue: transaction.installmentsValueInCents,
106
+ interestRate: transaction.interestRate,
107
+ isBillingAddressDifferent: billingAddressDifferent,
108
+ originalPaymentIndex: 1,
109
+ paymentSystem: transaction.paymentSystem,
110
+ referenceValue: transaction.referenceValueInCents,
111
+ tokenId: null,
112
+ transaction: {
113
+ id: transaction.transactionId,
114
+ merchantName: transaction.merchantName
115
+ },
116
+ value: transaction.valueInCents
117
+ }]
118
+ };
119
+ }
120
+ /**
121
+ * T29 (FR-6, OQ-7): this leg's own abort budget. Before this task the direct-to-gateway POST carried no
122
+ * `AbortSignal` and no timeout at all, so a gateway that never answered left `placing` true and the CTA
123
+ * dead for the life of the mount (Route C, `place-order.md`'s Known limitations). The BFF's own default
124
+ * is 10s (`apps/storefront-api-core/.../api-timeout.ts:9`), but a card authorization can legitimately
125
+ * run longer than a GraphQL round trip, and this exact number is not confirmed with payments (spec
126
+ * OQ-7) — a placeholder pending that answer, not a tuned production value.
127
+ *
128
+ * Exported so `gateway.test.ts`'s own abort-budget test can assert the abort fires at exactly this
129
+ * duration, rather than against `vi.runAllTimersAsync()`, which fires any pending timer regardless of
130
+ * duration and would stay green even if this were edited to `300_000`. That mechanism test alone is
131
+ * still self-referential about this constant's own *value* — it advances the fake clock by whatever
132
+ * `GATEWAY_REQUEST_TIMEOUT_MS` currently holds, so on its own it cannot catch an edit to the constant
133
+ * either (fix round 2, verification finding V2). `gateway.test.ts` also asserts this constant against
134
+ * the literal `30_000` directly, in its own dedicated test — that is what actually fails if this
135
+ * constant's value ever changes.
136
+ */
137
+ const GATEWAY_REQUEST_TIMEOUT_MS = 3e4;
138
+ /**
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".
144
+ *
145
+ * `options.signal`, when given, aborts this request in *addition to* — never instead of — this module's
146
+ * own timeout: a caller opts into an earlier or externally triggered abort, but cannot opt out of the
147
+ * budget that keeps this leg from hanging forever (FR-6, US-3). Composed with a plain `AbortController`
148
+ * rather than `AbortSignal.any`/`AbortSignal.timeout` so the timeout is driven by an ordinary
149
+ * `setTimeout`, the one implementation a test can advance deterministically with fake timers.
150
+ *
151
+ * No caller in this package passes `options.signal` today — it exists to satisfy the spec's own
152
+ * Technical Contract (`specs/make-an-order-attempt-survive-a.md`) ahead of a future integration. Fix
153
+ * pass, Low finding: the listener this composes onto `externalSignal` is now removed in the `finally`
154
+ * below on every exit path, not only when it fires — previously, a caller that supplied a long-lived
155
+ * signal (as opposed to a fresh one per call) would accumulate one listener, and this function's own
156
+ * dead `AbortController`, per call that resolved normally.
157
+ */
158
+ async function postPaymentsToGateway(request, options) {
159
+ const { url, body } = buildGatewayPaymentsRequest(request);
160
+ const controller = new AbortController();
161
+ const timeoutId = setTimeout(() => controller.abort(new DOMException("The gateway request timed out.", "TimeoutError")), GATEWAY_REQUEST_TIMEOUT_MS);
162
+ const externalSignal = options?.signal;
163
+ const onExternalAbort = () => controller.abort(externalSignal?.reason);
164
+ if (externalSignal) {
165
+ if (externalSignal.aborted) controller.abort(externalSignal.reason);
166
+ else externalSignal.addEventListener("abort", onExternalAbort, { once: true });
167
+ }
168
+ 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];
175
+ } finally {
176
+ clearTimeout(timeoutId);
177
+ externalSignal?.removeEventListener("abort", onExternalAbort);
178
+ }
179
+ }
180
+ //#endregion
181
+ export { GATEWAY_REQUEST_TIMEOUT_MS, PAYMENT_GATEWAY_ERROR_CODE, PAYMENT_GATEWAY_USER_ERROR, buildGatewayPaymentsRequest, postPaymentsToGateway };
182
+
183
+ //# sourceMappingURL=gateway.js.map
@@ -0,0 +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":"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"}
@@ -0,0 +1,52 @@
1
+ import "../cart/operations.js";
2
+ import { TypedDocumentNode } from "@apollo/client";
3
+ //#region src/sdk/payment/operations.d.ts
4
+ /**
5
+ * Payment write-model GraphQL operations (specs/payment-action-namespace.md, T4) — the five mutations
6
+ * `api-module:PaymentWriteModel` shipped (T3, `checkout/schema.graphql` § 11). Nothing here is
7
+ * invented: every mutation, input field, and payload field is pinned to that schema.
8
+ *
9
+ * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive read
10
+ * path — and excluded from the codegen `documents` glob (see `codegen.ts`): the `gql` tag alone is
11
+ * still plucked by `graphql-codegen`, which would duplicate these hand-written types in
12
+ * `sdk/generated/`. Mirrors `shipping/option-select-operations.ts` and `identity/operations.ts`.
13
+ *
14
+ * No field at any nesting depth carries a card number or CVV — the read model guarantees it (RFC D13),
15
+ * and the one call that does carry them never touches GraphQL at all (see `gateway.ts`).
16
+ *
17
+ * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`;
18
+ * transport and top-level GraphQL failures are infrastructure, collapsed by the handlers in
19
+ * `use-payment-actions.ts` to the one client-synthesized code, `PAYMENT_NETWORK_ERROR_CODE`.
20
+ */
21
+ /** A payment domain error. Every mutation's error type is `{ code, message }`; codes stay strings. */
22
+ export type PaymentUserError = Readonly<{
23
+ code: string;
24
+ message: string;
25
+ }>;
26
+ export type PaymentMoney = Readonly<{
27
+ __typename?: 'Money';
28
+ amount: number;
29
+ currencyCode: string;
30
+ }>;
31
+ /** A `bin` with an `accountId` is validated against the saved card's own BIN (MISMATCHED_BIN_FOR_SAVED_CARD). */
32
+ export type PaymentMethodSelectInput = Readonly<{
33
+ methodId: string;
34
+ bin?: string;
35
+ accountId?: string;
36
+ }>;
37
+ /** With `sameAsDelivery: true` every other field is ignored and the server performs no upstream write. */
38
+ export type PaymentBillingAddressUpdateInput = Readonly<{
39
+ sameAsDelivery: boolean;
40
+ addressType?: string;
41
+ postalCode?: string;
42
+ country?: string;
43
+ street?: string;
44
+ number?: string;
45
+ complement?: string;
46
+ neighborhood?: string;
47
+ city?: string;
48
+ state?: string;
49
+ reference?: string;
50
+ }>;
51
+ //#endregion
52
+ //# sourceMappingURL=operations.d.ts.map