@vtex/faststore 0.0.7 → 0.0.10

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 (498) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/dist/actions.json +194 -1
  3. package/dist/catalog.json +3449 -1612
  4. package/dist/cli/index.d.ts +512 -63
  5. package/dist/cli/index.js +2098 -686
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/server-runtime.js +44 -24
  8. package/dist/cli/server-runtime.js.map +1 -1
  9. package/dist/client.d.ts +5 -1
  10. package/dist/client.js +5 -1
  11. package/dist/components.d.ts +42 -10
  12. package/dist/components.js +47 -15
  13. package/dist/content-types.json +823 -0
  14. package/dist/core/dist/define-component.d.ts +12 -2
  15. package/dist/docs/account-access-gate.md +4 -4
  16. package/dist/docs/account-address-book.md +519 -0
  17. package/dist/docs/account-entry-point.md +5 -5
  18. package/dist/docs/account-menu.md +7 -7
  19. package/dist/docs/account-saved-cards.md +301 -0
  20. package/dist/docs/alert-dialog.md +2 -2
  21. package/dist/docs/billing-address.md +17 -9
  22. package/dist/docs/binding-switcher.md +154 -0
  23. package/dist/docs/card-entry.md +38 -7
  24. package/dist/docs/card-summary.md +175 -0
  25. package/dist/docs/cardholder-document.md +16 -14
  26. package/dist/docs/cart-destination.md +238 -0
  27. package/dist/docs/cart-item.md +22 -4
  28. package/dist/docs/cart-totalizer.md +1 -1
  29. package/dist/docs/cart.md +126 -19
  30. package/dist/docs/client-profile-fieldset.md +7 -5
  31. package/dist/docs/copy-text.md +84 -0
  32. package/dist/docs/document-field.md +8 -8
  33. package/dist/docs/footer-link-group.md +2 -2
  34. package/dist/docs/footer-social.md +1 -1
  35. package/dist/docs/free-shipping-progress.md +13 -9
  36. package/dist/docs/header-root.md +1 -1
  37. package/dist/docs/incentives.md +4 -4
  38. package/dist/docs/logo.md +6 -6
  39. package/dist/docs/my-account-profile.md +4 -4
  40. package/dist/docs/navigation-link-list.md +2 -2
  41. package/dist/docs/navigation-link.md +3 -3
  42. package/dist/docs/order-cancel.md +52 -0
  43. package/dist/docs/order-delivery-address.md +63 -0
  44. package/dist/docs/order-delivery-group.md +83 -0
  45. package/dist/docs/order-details-back.md +41 -0
  46. package/dist/docs/order-details-header.md +48 -0
  47. package/dist/docs/order-list-row.md +46 -0
  48. package/dist/docs/order-list-search.md +101 -0
  49. package/dist/docs/order-list-views.md +97 -0
  50. package/dist/docs/order-list.md +94 -0
  51. package/dist/docs/order-payment.md +94 -0
  52. package/dist/docs/order-placed-date.md +49 -0
  53. package/dist/docs/order-placed-payment-summary.md +13 -15
  54. package/dist/docs/order-placed.md +225 -0
  55. package/dist/docs/order-progress.md +88 -0
  56. package/dist/docs/order-status-badge.md +91 -0
  57. package/dist/docs/order-summary.md +53 -0
  58. package/dist/docs/payment-method-badges.md +16 -5
  59. package/dist/docs/payment-methods.md +1 -1
  60. package/dist/docs/place-order.md +13 -9
  61. package/dist/docs/product-information.md +2 -2
  62. package/dist/docs/product-shelf.md +7 -0
  63. package/dist/docs/saved-cards.md +2 -2
  64. package/dist/docs/select.md +22 -10
  65. package/dist/docs/session.md +1 -1
  66. package/dist/docs/shipping-address.md +1 -1
  67. package/dist/docs/sign-in-redirect.md +7 -7
  68. package/dist/docs/toast.md +35 -13
  69. package/dist/index.d.ts +7 -2
  70. package/dist/index.js +2 -1
  71. package/dist/internal/client.d.ts +9 -1
  72. package/dist/internal/client.js +10 -2
  73. package/dist/internal/server.d.ts +8 -2
  74. package/dist/internal/server.js +8 -2
  75. package/dist/matter/account-access-gate/account-access-gate.d.ts +2 -1
  76. package/dist/matter/account-access-gate/account-access-gate.js +19 -16
  77. package/dist/matter/account-access-gate/account-access-gate.js.map +1 -1
  78. package/dist/matter/account-address-book/account-address-book-delete.d.ts +60 -0
  79. package/dist/matter/account-address-book/account-address-book-delete.js +184 -0
  80. package/dist/matter/account-address-book/account-address-book-delete.js.map +1 -0
  81. package/dist/matter/account-address-book/account-address-book-deliverability.d.ts +19 -0
  82. package/dist/matter/account-address-book/account-address-book-deliverability.js +50 -0
  83. package/dist/matter/account-address-book/account-address-book-deliverability.js.map +1 -0
  84. package/dist/matter/account-address-book/account-address-book-form-parts.d.ts +42 -0
  85. package/dist/matter/account-address-book/account-address-book-form-parts.js +146 -0
  86. package/dist/matter/account-address-book/account-address-book-form-parts.js.map +1 -0
  87. package/dist/matter/account-address-book/account-address-book-profile-notice.d.ts +25 -0
  88. package/dist/matter/account-address-book/account-address-book-profile-notice.js +72 -0
  89. package/dist/matter/account-address-book/account-address-book-profile-notice.js.map +1 -0
  90. package/dist/matter/account-address-book/account-address-book.d.ts +120 -0
  91. package/dist/matter/account-address-book/account-address-book.js +469 -0
  92. package/dist/matter/account-address-book/account-address-book.js.map +1 -0
  93. package/dist/matter/account-address-book/account-address-country-switch.js +59 -0
  94. package/dist/matter/account-address-book/account-address-country-switch.js.map +1 -0
  95. package/dist/matter/account-address-book/account-address-country.d.ts +36 -0
  96. package/dist/matter/account-address-book/account-address-country.js +151 -0
  97. package/dist/matter/account-address-book/account-address-country.js.map +1 -0
  98. package/dist/matter/account-address-book/account-address-first-line.js +11 -0
  99. package/dist/matter/account-address-book/account-address-first-line.js.map +1 -0
  100. package/dist/matter/account-address-book/account-address-form-context.d.ts +55 -0
  101. package/dist/matter/account-address-book/account-address-form-context.js +14 -0
  102. package/dist/matter/account-address-book/account-address-form-context.js.map +1 -0
  103. package/dist/matter/account-address-book/account-address-form.d.ts +85 -0
  104. package/dist/matter/account-address-book/account-address-form.js +946 -0
  105. package/dist/matter/account-address-book/account-address-form.js.map +1 -0
  106. package/dist/matter/account-address-book/account-address-postal-autofill.js +189 -0
  107. package/dist/matter/account-address-book/account-address-postal-autofill.js.map +1 -0
  108. package/dist/matter/account-address-book/account-address-record.d.ts +26 -0
  109. package/dist/matter/account-address-book/account-address-record.js +138 -0
  110. package/dist/matter/account-address-book/account-address-record.js.map +1 -0
  111. package/dist/matter/account-entry-point/account-entry-point.js +11 -11
  112. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -1
  113. package/dist/matter/account-menu/account-menu.d.ts +7 -3
  114. package/dist/matter/account-menu/account-menu.js +69 -28
  115. package/dist/matter/account-menu/account-menu.js.map +1 -1
  116. package/dist/matter/account-saved-cards/account-saved-cards.d.ts +383 -0
  117. package/dist/matter/account-saved-cards/account-saved-cards.js +956 -0
  118. package/dist/matter/account-saved-cards/account-saved-cards.js.map +1 -0
  119. package/dist/matter/billing-address/billing-address.d.ts +30 -17
  120. package/dist/matter/billing-address/billing-address.js +128 -33
  121. package/dist/matter/billing-address/billing-address.js.map +1 -1
  122. package/dist/matter/breadcrumb/breadcrumb.js +2 -2
  123. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -1
  124. package/dist/matter/card-entry/card-capture.js +4 -3
  125. package/dist/matter/card-entry/card-capture.js.map +1 -1
  126. package/dist/matter/card-entry/card-entry.d.ts +5 -3
  127. package/dist/matter/card-entry/card-entry.js +77 -27
  128. package/dist/matter/card-entry/card-entry.js.map +1 -1
  129. package/dist/matter/cardholder-document/cardholder-document.d.ts +10 -9
  130. package/dist/matter/cardholder-document/cardholder-document.js +36 -16
  131. package/dist/matter/cardholder-document/cardholder-document.js.map +1 -1
  132. package/dist/matter/cart/cart-namespace.d.ts +5 -1
  133. package/dist/matter/cart/cart-namespace.js +5 -1
  134. package/dist/matter/cart/cart-namespace.js.map +1 -1
  135. package/dist/matter/cart/cart.d.ts +41 -6
  136. package/dist/matter/cart/cart.js +267 -54
  137. package/dist/matter/cart/cart.js.map +1 -1
  138. package/dist/matter/cart-destination/cart-destination.d.ts +222 -0
  139. package/dist/matter/cart-destination/cart-destination.js +613 -0
  140. package/dist/matter/cart-destination/cart-destination.js.map +1 -0
  141. package/dist/matter/cart-item/cart-item.d.ts +4 -2
  142. package/dist/matter/cart-item/cart-item.js +76 -17
  143. package/dist/matter/cart-item/cart-item.js.map +1 -1
  144. package/dist/matter/cart-totalizer/cart-totalizer.js +3 -2
  145. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -1
  146. package/dist/matter/client-preferences/client-preferences-fieldset.js +1 -1
  147. package/dist/matter/client-profile-form/client-profile-fieldset.js +8 -5
  148. package/dist/matter/client-profile-form/client-profile-fieldset.js.map +1 -1
  149. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +6 -3
  150. package/dist/matter/free-shipping-progress/free-shipping-progress.js +76 -33
  151. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -1
  152. package/dist/matter/identity-edit/identity-edit.js +3 -3
  153. package/dist/matter/identity-edit/identity-edit.js.map +1 -1
  154. package/dist/matter/identity-summary/identity-summary.js +2 -2
  155. package/dist/matter/identity-summary/identity-summary.js.map +1 -1
  156. package/dist/matter/my-account-profile/my-account-profile.d.ts +3 -3
  157. package/dist/matter/my-account-profile/my-account-profile.js +4 -4
  158. package/dist/matter/my-account-profile/my-account-profile.js.map +1 -1
  159. package/dist/matter/order-cancel/order-cancel.d.ts +110 -0
  160. package/dist/matter/order-cancel/order-cancel.js +344 -0
  161. package/dist/matter/order-cancel/order-cancel.js.map +1 -0
  162. package/dist/matter/order-delivery-address/order-delivery-address.d.ts +73 -0
  163. package/dist/matter/order-delivery-address/order-delivery-address.js +172 -0
  164. package/dist/matter/order-delivery-address/order-delivery-address.js.map +1 -0
  165. package/dist/matter/order-delivery-group/order-delivery-group.d.ts +128 -0
  166. package/dist/matter/order-delivery-group/order-delivery-group.js +408 -0
  167. package/dist/matter/order-delivery-group/order-delivery-group.js.map +1 -0
  168. package/dist/matter/order-details-header/order-details-header.d.ts +104 -0
  169. package/dist/matter/order-details-header/order-details-header.js +190 -0
  170. package/dist/matter/order-details-header/order-details-header.js.map +1 -0
  171. package/dist/matter/order-list/customer-orders-filter.d.ts +12 -0
  172. package/dist/matter/order-list/customer-orders-filter.js +30 -0
  173. package/dist/matter/order-list/customer-orders-filter.js.map +1 -0
  174. package/dist/matter/order-list/order-list.d.ts +121 -0
  175. package/dist/matter/order-list/order-list.js +395 -0
  176. package/dist/matter/order-list/order-list.js.map +1 -0
  177. package/dist/matter/order-list-row/order-list-row.d.ts +44 -0
  178. package/dist/matter/order-list-row/order-list-row.js +127 -0
  179. package/dist/matter/order-list-row/order-list-row.js.map +1 -0
  180. package/dist/matter/order-list-search/order-list-search.d.ts +72 -0
  181. package/dist/matter/order-list-search/order-list-search.js +296 -0
  182. package/dist/matter/order-list-search/order-list-search.js.map +1 -0
  183. package/dist/matter/order-list-views/order-list-views.d.ts +65 -0
  184. package/dist/matter/order-list-views/order-list-views.js +154 -0
  185. package/dist/matter/order-list-views/order-list-views.js.map +1 -0
  186. package/dist/matter/order-payment/order-payment.d.ts +83 -0
  187. package/dist/matter/order-payment/order-payment.js +258 -0
  188. package/dist/matter/order-payment/order-payment.js.map +1 -0
  189. package/dist/matter/order-placed/order-placed-deliveries.d.ts +145 -0
  190. package/dist/matter/order-placed/order-placed-deliveries.js +380 -0
  191. package/dist/matter/order-placed/order-placed-deliveries.js.map +1 -0
  192. package/dist/matter/order-placed/order-placed.d.ts +122 -0
  193. package/dist/matter/order-placed/order-placed.js +452 -0
  194. package/dist/matter/order-placed/order-placed.js.map +1 -0
  195. package/dist/matter/order-placed-date/order-placed-date.d.ts +45 -0
  196. package/dist/matter/order-placed-date/order-placed-date.js +92 -0
  197. package/dist/matter/order-placed-date/order-placed-date.js.map +1 -0
  198. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.d.ts +5 -8
  199. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js +29 -81
  200. package/dist/matter/order-placed-payment-summary/order-placed-payment-summary.js.map +1 -1
  201. package/dist/matter/order-progress/order-progress.d.ts +85 -0
  202. package/dist/matter/order-progress/order-progress.js +203 -0
  203. package/dist/matter/order-progress/order-progress.js.map +1 -0
  204. package/dist/matter/order-summary/order-summary.d.ts +81 -0
  205. package/dist/matter/order-summary/order-summary.js +192 -0
  206. package/dist/matter/order-summary/order-summary.js.map +1 -0
  207. package/dist/matter/payment/cardholder-document-rule.d.ts +35 -0
  208. package/dist/matter/payment/cardholder-document-rule.js +35 -0
  209. package/dist/matter/payment/cardholder-document-rule.js.map +1 -0
  210. package/dist/matter/payment/payment-card-capture.js +38 -23
  211. package/dist/matter/payment/payment-card-capture.js.map +1 -1
  212. package/dist/matter/payment/payment-controller.js +11 -0
  213. package/dist/matter/payment/payment-controller.js.map +1 -1
  214. package/dist/matter/payment/payment-method-badges.js +4 -2
  215. package/dist/matter/payment/payment-method-badges.js.map +1 -1
  216. package/dist/matter/payment/payment.js +11 -0
  217. package/dist/matter/payment/payment.js.map +1 -1
  218. package/dist/matter/payment/use-payment-method-selection.d.ts +39 -0
  219. package/dist/matter/payment/use-payment-method-selection.js +30 -2
  220. package/dist/matter/payment/use-payment-method-selection.js.map +1 -1
  221. package/dist/matter/payment/use-payment-submit-gate.d.ts +16 -2
  222. package/dist/matter/payment/use-payment-submit-gate.js +42 -14
  223. package/dist/matter/payment/use-payment-submit-gate.js.map +1 -1
  224. package/dist/matter/place-order/place-order.d.ts +12 -7
  225. package/dist/matter/place-order/place-order.js +126 -103
  226. package/dist/matter/place-order/place-order.js.map +1 -1
  227. package/dist/matter/pricing/pricing.js +5 -5
  228. package/dist/matter/pricing/pricing.js.map +1 -1
  229. package/dist/matter/product-shelf/product-shelf.d.ts +7 -0
  230. package/dist/matter/product-shelf/product-shelf.js +115 -1
  231. package/dist/matter/product-shelf/product-shelf.js.map +1 -1
  232. package/dist/matter/region/region.js +1 -1
  233. package/dist/matter/saved-cards/saved-cards.js +26 -15
  234. package/dist/matter/saved-cards/saved-cards.js.map +1 -1
  235. package/dist/matter/session/session.js +2 -2
  236. package/dist/matter/session/session.js.map +1 -1
  237. package/dist/matter/shipping-address/country-descriptors.d.ts +1 -0
  238. package/dist/matter/shipping-address/country-descriptors.js +23 -1
  239. package/dist/matter/shipping-address/country-descriptors.js.map +1 -1
  240. package/dist/matter/shipping-address/shipping-address.js +62 -14
  241. package/dist/matter/shipping-address/shipping-address.js.map +1 -1
  242. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +2 -2
  243. package/dist/matter/shipping-simulator/shipping-simulator.js +6 -2
  244. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -1
  245. package/dist/matter/sign-in-redirect/sign-in-redirect.js +48 -10
  246. package/dist/matter/sign-in-redirect/sign-in-redirect.js.map +1 -1
  247. package/dist/matter/variant-selector/variant-selector.js +2 -2
  248. package/dist/matter/variant-selector/variant-selector.js.map +1 -1
  249. package/dist/particles/address-summary/address-summary.js +2 -2
  250. package/dist/particles/address-summary/address-summary.js.map +1 -1
  251. package/dist/particles/alert-dialog/alert-dialog.d.ts +5 -1
  252. package/dist/particles/alert-dialog/alert-dialog.js +5 -2
  253. package/dist/particles/alert-dialog/alert-dialog.js.map +1 -1
  254. package/dist/particles/binding-switcher/binding-switcher.d.ts +38 -0
  255. package/dist/particles/binding-switcher/binding-switcher.js +183 -0
  256. package/dist/particles/binding-switcher/binding-switcher.js.map +1 -0
  257. package/dist/particles/card-summary/card-network.d.ts +17 -0
  258. package/dist/particles/card-summary/card-network.js +25 -0
  259. package/dist/particles/card-summary/card-network.js.map +1 -0
  260. package/dist/particles/card-summary/card-summary.d.ts +83 -0
  261. package/dist/particles/card-summary/card-summary.js +188 -0
  262. package/dist/particles/card-summary/card-summary.js.map +1 -0
  263. package/dist/particles/copy-text/copy-text.d.ts +28 -0
  264. package/dist/particles/copy-text/copy-text.js +140 -0
  265. package/dist/particles/copy-text/copy-text.js.map +1 -0
  266. package/dist/particles/document-field/document-field.d.ts +34 -5
  267. package/dist/particles/document-field/document-field.js +115 -19
  268. package/dist/particles/document-field/document-field.js.map +1 -1
  269. package/dist/particles/field/field.js +1 -1
  270. package/dist/particles/field/field.js.map +1 -1
  271. package/dist/particles/footer-link-group/footer-link-group.d.ts +6 -2
  272. package/dist/particles/footer-link-group/footer-link-group.js +18 -7
  273. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -1
  274. package/dist/particles/footer-social/footer-social.d.ts +1 -1
  275. package/dist/particles/footer-social/footer-social.js +1 -1
  276. package/dist/particles/footer-social/footer-social.js.map +1 -1
  277. package/dist/particles/incentives/incentives.d.ts +7 -3
  278. package/dist/particles/incentives/incentives.js +8 -3
  279. package/dist/particles/incentives/incentives.js.map +1 -1
  280. package/dist/particles/logo/logo.d.ts +3 -2
  281. package/dist/particles/logo/logo.js +20 -8
  282. package/dist/particles/logo/logo.js.map +1 -1
  283. package/dist/particles/navigation-link/navigation-link.d.ts +2 -3
  284. package/dist/particles/navigation-link/navigation-link.js +4 -4
  285. package/dist/particles/navigation-link/navigation-link.js.map +1 -1
  286. package/dist/particles/navigation-link-list/navigation-link-list.d.ts +6 -2
  287. package/dist/particles/navigation-link-list/navigation-link-list.js +18 -7
  288. package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -1
  289. package/dist/particles/order-details-back/order-details-back.d.ts +28 -0
  290. package/dist/particles/order-details-back/order-details-back.js +52 -0
  291. package/dist/particles/order-details-back/order-details-back.js.map +1 -0
  292. package/dist/particles/order-status-badge/order-status-badge.d.ts +19 -0
  293. package/dist/particles/order-status-badge/order-status-badge.js +50 -0
  294. package/dist/particles/order-status-badge/order-status-badge.js.map +1 -0
  295. package/dist/particles/payment-methods/payment-methods.d.ts +1 -1
  296. package/dist/particles/payment-methods/payment-methods.js +1 -1
  297. package/dist/particles/payment-methods/payment-methods.js.map +1 -1
  298. package/dist/particles/phone-field/phone-field.js +2 -2
  299. package/dist/particles/phone-field/phone-field.js.map +1 -1
  300. package/dist/particles/select/select.js +6 -6
  301. package/dist/particles/select/select.js.map +1 -1
  302. package/dist/particles/toast/toast.d.ts +21 -7
  303. package/dist/particles/toast/toast.js +76 -8
  304. package/dist/particles/toast/toast.js.map +1 -1
  305. package/dist/schema.graphql +1376 -126
  306. package/dist/sdk/actions/address-action-provider.d.ts +16 -0
  307. package/dist/sdk/actions/address-action-provider.js +20 -0
  308. package/dist/sdk/actions/address-action-provider.js.map +1 -0
  309. package/dist/sdk/actions/analytics-action-provider.js +1 -1
  310. package/dist/sdk/actions/index.d.ts +5 -1
  311. package/dist/sdk/actions/index.js +5 -1
  312. package/dist/sdk/actions/locale-action-provider.d.ts +16 -0
  313. package/dist/sdk/actions/locale-action-provider.js +20 -0
  314. package/dist/sdk/actions/locale-action-provider.js.map +1 -0
  315. package/dist/sdk/actions/order-action-provider.d.ts +12 -0
  316. package/dist/sdk/actions/order-action-provider.js +16 -0
  317. package/dist/sdk/actions/order-action-provider.js.map +1 -0
  318. package/dist/sdk/actions/saved-card-action-provider.d.ts +12 -0
  319. package/dist/sdk/actions/saved-card-action-provider.js +16 -0
  320. package/dist/sdk/actions/saved-card-action-provider.js.map +1 -0
  321. package/dist/sdk/actions/types.d.ts +10 -2
  322. package/dist/sdk/address/address-fields.js +38 -0
  323. package/dist/sdk/address/address-fields.js.map +1 -0
  324. package/dist/sdk/address/checkout-readiness.js +17 -0
  325. package/dist/sdk/address/checkout-readiness.js.map +1 -0
  326. package/dist/sdk/address/constants.js +60 -0
  327. package/dist/sdk/address/constants.js.map +1 -0
  328. package/dist/sdk/address/country-display.js +19 -0
  329. package/dist/sdk/address/country-display.js.map +1 -0
  330. package/dist/sdk/address/country-rules.js +30 -0
  331. package/dist/sdk/address/country-rules.js.map +1 -0
  332. package/dist/sdk/address/format-address.js +18 -0
  333. package/dist/sdk/address/format-address.js.map +1 -0
  334. package/dist/sdk/address/iso-countries.js +262 -0
  335. package/dist/sdk/address/iso-countries.js.map +1 -0
  336. package/dist/sdk/address/layouts.js +56 -0
  337. package/dist/sdk/address/layouts.js.map +1 -0
  338. package/dist/sdk/address/messages.js +97 -0
  339. package/dist/sdk/address/messages.js.map +1 -0
  340. package/dist/sdk/address/operations.d.ts +54 -0
  341. package/dist/sdk/address/operations.js +83 -0
  342. package/dist/sdk/address/operations.js.map +1 -0
  343. package/dist/sdk/address/postal-code-lookup-operations.js +23 -0
  344. package/dist/sdk/address/postal-code-lookup-operations.js.map +1 -0
  345. package/dist/sdk/address/postal-code.js +11 -0
  346. package/dist/sdk/address/postal-code.js.map +1 -0
  347. package/dist/sdk/address/schema.js +14 -0
  348. package/dist/sdk/address/schema.js.map +1 -0
  349. package/dist/sdk/address/server-fields.js +25 -0
  350. package/dist/sdk/address/server-fields.js.map +1 -0
  351. package/dist/sdk/address/switch-country.js +57 -0
  352. package/dist/sdk/address/switch-country.js.map +1 -0
  353. package/dist/sdk/address/types.d.ts +26 -0
  354. package/dist/sdk/address/use-address-actions.d.ts +29 -0
  355. package/dist/sdk/address/use-address-actions.js +247 -0
  356. package/dist/sdk/address/use-address-actions.js.map +1 -0
  357. package/dist/sdk/address/use-address-by-postal-code.js +57 -0
  358. package/dist/sdk/address/use-address-by-postal-code.js.map +1 -0
  359. package/dist/sdk/address/validate-address.js +62 -0
  360. package/dist/sdk/address/validate-address.js.map +1 -0
  361. package/dist/sdk/cache/storefront-cache.js +30 -4
  362. package/dist/sdk/cache/storefront-cache.js.map +1 -1
  363. package/dist/sdk/cart/operations.d.ts +2 -1
  364. package/dist/sdk/cart/operations.js +55 -1
  365. package/dist/sdk/cart/operations.js.map +1 -1
  366. package/dist/sdk/cart/optimistic.d.ts +30 -7
  367. package/dist/sdk/cart/optimistic.js +78 -41
  368. package/dist/sdk/cart/optimistic.js.map +1 -1
  369. package/dist/sdk/cart/use-cart-actions.d.ts +7 -0
  370. package/dist/sdk/cart/use-cart-actions.js +61 -15
  371. package/dist/sdk/cart/use-cart-actions.js.map +1 -1
  372. package/dist/sdk/cart/use-cart-sync-sales-channel.js +70 -0
  373. package/dist/sdk/cart/use-cart-sync-sales-channel.js.map +1 -0
  374. package/dist/sdk/client/fetch-page-data.d.ts +11 -0
  375. package/dist/sdk/client/fetch-page-data.js +12 -1
  376. package/dist/sdk/client/fetch-page-data.js.map +1 -1
  377. package/dist/sdk/content/create-content-runtime.js +1 -8
  378. package/dist/sdk/content/create-content-runtime.js.map +1 -1
  379. package/dist/sdk/data/failed-fields.js +23 -0
  380. package/dist/sdk/data/failed-fields.js.map +1 -0
  381. package/dist/sdk/data/index.js +2 -2
  382. package/dist/sdk/data/page-reactive-data-root.d.ts +45 -7
  383. package/dist/sdk/data/page-reactive-data-root.js +88 -12
  384. package/dist/sdk/data/page-reactive-data-root.js.map +1 -1
  385. package/dist/sdk/data/reactive-list-item-data-provider.js +2 -2
  386. package/dist/sdk/generated/fragment-types.js +2 -0
  387. package/dist/sdk/generated/fragment-types.js.map +1 -1
  388. package/dist/sdk/generated/gql.js +17 -11
  389. package/dist/sdk/generated/gql.js.map +1 -1
  390. package/dist/sdk/generated/graphql.d.ts +185 -46
  391. package/dist/sdk/generated/graphql.js +2587 -155
  392. package/dist/sdk/generated/graphql.js.map +1 -1
  393. package/dist/sdk/i18n/messages/en-US.js +157 -1
  394. package/dist/sdk/i18n/messages/en-US.json +157 -1
  395. package/dist/sdk/i18n/messages/en-US.json.d.ts +156 -0
  396. package/dist/sdk/i18n/messages/es-ES.js +157 -1
  397. package/dist/sdk/i18n/messages/es-ES.json +157 -1
  398. package/dist/sdk/i18n/messages/pt-BR.js +157 -1
  399. package/dist/sdk/i18n/messages/pt-BR.json +157 -1
  400. package/dist/sdk/i18n/provider.js +1 -1
  401. package/dist/sdk/i18n/provider.js.map +1 -1
  402. package/dist/sdk/locale/binding-switch-provider.d.ts +13 -0
  403. package/dist/sdk/locale/binding-switch-provider.js +20 -0
  404. package/dist/sdk/locale/binding-switch-provider.js.map +1 -0
  405. package/dist/sdk/locale/use-locale-actions.d.ts +16 -0
  406. package/dist/sdk/locale/use-locale-actions.js +70 -0
  407. package/dist/sdk/locale/use-locale-actions.js.map +1 -0
  408. package/dist/sdk/navigation/binding-switch.d.ts +39 -0
  409. package/dist/sdk/navigation/binding-switch.js +129 -0
  410. package/dist/sdk/navigation/binding-switch.js.map +1 -0
  411. package/dist/sdk/navigation/current-page.js +30 -0
  412. package/dist/sdk/navigation/current-page.js.map +1 -0
  413. package/dist/sdk/navigation/decode-route-params.d.ts +11 -0
  414. package/dist/sdk/navigation/decode-route-params.js +32 -0
  415. package/dist/sdk/navigation/decode-route-params.js.map +1 -0
  416. package/dist/sdk/navigation/not-found-log.d.ts +28 -0
  417. package/dist/sdk/navigation/not-found-log.js +133 -0
  418. package/dist/sdk/navigation/not-found-log.js.map +1 -0
  419. package/dist/sdk/navigation/path.js +25 -0
  420. package/dist/sdk/navigation/path.js.map +1 -0
  421. package/dist/sdk/navigation/redirect.d.ts +11 -0
  422. package/dist/sdk/navigation/redirect.js +22 -0
  423. package/dist/sdk/navigation/redirect.js.map +1 -0
  424. package/dist/sdk/navigation/report.js +70 -0
  425. package/dist/sdk/navigation/report.js.map +1 -0
  426. package/dist/sdk/navigation/resolve-storefront-href.d.ts +12 -0
  427. package/dist/sdk/navigation/resolve-storefront-href.js +214 -0
  428. package/dist/sdk/navigation/resolve-storefront-href.js.map +1 -0
  429. package/dist/sdk/navigation/route-identity-provider.d.ts +11 -0
  430. package/dist/sdk/navigation/route-identity-provider.js +20 -0
  431. package/dist/sdk/navigation/route-identity-provider.js.map +1 -0
  432. package/dist/sdk/navigation/route-map-provider.d.ts +19 -0
  433. package/dist/sdk/navigation/route-map-provider.js +29 -0
  434. package/dist/sdk/navigation/route-map-provider.js.map +1 -0
  435. package/dist/sdk/navigation/storefront-link.d.ts +16 -0
  436. package/dist/sdk/navigation/storefront-link.js +66 -0
  437. package/dist/sdk/navigation/storefront-link.js.map +1 -0
  438. package/dist/sdk/navigation/types.d.ts +45 -0
  439. package/dist/sdk/navigation/use-storefront-navigation.d.ts +26 -0
  440. package/dist/sdk/navigation/use-storefront-navigation.js +73 -0
  441. package/dist/sdk/navigation/use-storefront-navigation.js.map +1 -0
  442. package/dist/sdk/navigation/use-storefront-route.d.ts +26 -0
  443. package/dist/sdk/navigation/use-storefront-route.js +87 -0
  444. package/dist/sdk/navigation/use-storefront-route.js.map +1 -0
  445. package/dist/sdk/navigation/use-storefront-search-params.d.ts +11 -0
  446. package/dist/sdk/navigation/use-storefront-search-params.js +16 -0
  447. package/dist/sdk/navigation/use-storefront-search-params.js.map +1 -0
  448. package/dist/sdk/orders/completion-badge.d.ts +8 -0
  449. package/dist/sdk/orders/completion-badge.js +47 -0
  450. package/dist/sdk/orders/completion-badge.js.map +1 -0
  451. package/dist/sdk/orders/order-operations.d.ts +19 -0
  452. package/dist/sdk/orders/order-operations.js +21 -0
  453. package/dist/sdk/orders/order-operations.js.map +1 -0
  454. package/dist/sdk/orders/use-order-actions.d.ts +23 -0
  455. package/dist/sdk/orders/use-order-actions.js +62 -0
  456. package/dist/sdk/orders/use-order-actions.js.map +1 -0
  457. package/dist/sdk/payment/gateway-origin.js +26 -13
  458. package/dist/sdk/payment/gateway-origin.js.map +1 -1
  459. package/dist/sdk/payment/gateway.d.ts +14 -2
  460. package/dist/sdk/payment/gateway.js +32 -14
  461. package/dist/sdk/payment/gateway.js.map +1 -1
  462. package/dist/sdk/payment/operations.js +11 -0
  463. package/dist/sdk/payment/operations.js.map +1 -1
  464. package/dist/sdk/payment/submission-registry.d.ts +2 -1
  465. package/dist/sdk/payment/submission-registry.js +12 -8
  466. package/dist/sdk/payment/submission-registry.js.map +1 -1
  467. package/dist/sdk/payment/use-payment-actions.d.ts +5 -3
  468. package/dist/sdk/payment/use-payment-actions.js +5 -2
  469. package/dist/sdk/payment/use-payment-actions.js.map +1 -1
  470. package/dist/sdk/payment/use-place-order.d.ts +6 -3
  471. package/dist/sdk/payment/use-place-order.js +333 -143
  472. package/dist/sdk/payment/use-place-order.js.map +1 -1
  473. package/dist/sdk/saved-cards/operations.d.ts +16 -0
  474. package/dist/sdk/saved-cards/operations.js +41 -0
  475. package/dist/sdk/saved-cards/operations.js.map +1 -0
  476. package/dist/sdk/saved-cards/use-saved-card-actions.d.ts +26 -0
  477. package/dist/sdk/saved-cards/use-saved-card-actions.js +86 -0
  478. package/dist/sdk/saved-cards/use-saved-card-actions.js.map +1 -0
  479. package/dist/sdk/seo/page-alternates.d.ts +57 -0
  480. package/dist/sdk/seo/page-alternates.js +127 -0
  481. package/dist/sdk/seo/page-alternates.js.map +1 -0
  482. package/dist/sdk/shipping/shipping-operations.d.ts +1 -1
  483. package/dist/sdk/shipping/shipping-operations.js +13 -0
  484. package/dist/sdk/shipping/shipping-operations.js.map +1 -1
  485. package/dist/sdk/state/cart.d.ts +9 -2
  486. package/dist/sdk/state/cart.js +9 -2
  487. package/dist/sdk/state/cart.js.map +1 -1
  488. package/dist/utils/own-value.js +19 -0
  489. package/dist/utils/own-value.js.map +1 -0
  490. package/dist/utils/safe-href.d.ts +4 -4
  491. package/dist/utils/safe-href.js +31 -22
  492. package/dist/utils/safe-href.js.map +1 -1
  493. package/package.json +5 -1
  494. package/skills/storefront-asset/SKILL.md +111 -0
  495. package/skills/storefront-asset/references/api-side.md +153 -0
  496. package/skills/storefront-asset/references/findings.md +40 -0
  497. package/skills/storefront-asset/references/ui-side.md +94 -0
  498. package/src/styles/tailwind.css +28 -2
@@ -0,0 +1,57 @@
1
+ import { CatalogRouteAlternatesQuery } from "../generated/graphql.js";
2
+ //#region src/sdk/seo/page-alternates.d.ts
3
+ export type AlternateBinding = {
4
+ bindingId: string;
5
+ locale: string;
6
+ };
7
+ export type RouteVariant = NonNullable<CatalogRouteAlternatesQuery['catalogRoute']>['variants'][number];
8
+ /** Structurally assignable to Next.js `Metadata['alternates']`. */
9
+ export type PageAlternates = {
10
+ canonical: string;
11
+ /** BCP 47 tag or `x-default` -> absolute URL. */
12
+ languages?: Record<string, string>;
13
+ };
14
+ export type RouteParams = Readonly<Record<string, string | string[] | undefined>>;
15
+ export type BuildPageAlternatesOptions = {
16
+ bindingId: string;
17
+ defaultBindingId: string;
18
+ /** Every declared binding, in authoring order. */
19
+ bindings: readonly AlternateBinding[];
20
+ /** Decoded logical path of the request. */
21
+ selfPath: string;
22
+ /** Binding id -> decoded logical path, for the cluster members only. `null` means no cluster source. */
23
+ clusterPaths: Readonly<Record<string, string>> | null;
24
+ buildUrl: (bindingId: string, logicalPath: string) => string;
25
+ };
26
+ /**
27
+ * The only GraphQL text the alternates feature owns. `catalogClusterPaths` reads its result, and the
28
+ * package tests validate it against the Storefront API schema.
29
+ */
30
+ export declare const CATALOG_ROUTE_ALTERNATES_QUERY: import("@graphql-typed-document-node/core").TypedDocumentNode<CatalogRouteAlternatesQuery, {
31
+ path: string;
32
+ }>;
33
+ /**
34
+ * The canonical URL plus, when a reciprocal cluster exists, `languages`. A cluster needs two members
35
+ * and must include the rendered binding: search engines ignore a set that does not reference itself.
36
+ */
37
+ export declare function buildPageAlternates({ bindingId, defaultBindingId, bindings, selfPath, clusterPaths, buildUrl }: BuildPageAlternatesOptions): PageAlternates;
38
+ /**
39
+ * The logical path a route pattern names under these params, which arrive decoded
40
+ * (`decodeRouteParams`): `('/[slug]/p', { slug: 'café' })` -> `'/café/p'`. Catch-alls join with `/`;
41
+ * empty -> `'/'`.
42
+ * Empty, `.` and `..` values are dropped. It never decodes: a caller must decode first, or an
43
+ * encoded dot segment (`%2E%2E`) stays an inert literal segment.
44
+ */
45
+ export declare function routeLogicalPath(route: string, params: RouteParams): string;
46
+ /**
47
+ * Binding id -> variant path for the bindings whose locale a confirmed variant matches. Never
48
+ * rejects: a thrown loader, an `error`, a missing or `null` `catalogRoute`, or no matching variant
49
+ * all resolve to `null`, so a catalog lookup can never fail the page it describes. A thrown loader
50
+ * or an `error` is logged by code or error name only, never with the path or the upstream message.
51
+ */
52
+ export declare function catalogClusterPaths(bindings: readonly AlternateBinding[], load: () => Promise<{
53
+ data: unknown;
54
+ error?: unknown;
55
+ }>): Promise<Record<string, string> | null>;
56
+ //#endregion
57
+ //# sourceMappingURL=page-alternates.d.ts.map
@@ -0,0 +1,127 @@
1
+ import { graphql } from "../generated/gql.js";
2
+ import { loggableErrorName } from "../../utils/loggable-error-name.js";
3
+ import { CombinedGraphQLErrors } from "@apollo/client/errors";
4
+ //#region src/sdk/seo/page-alternates.ts
5
+ /**
6
+ * The only GraphQL text the alternates feature owns. `catalogClusterPaths` reads its result, and the
7
+ * package tests validate it against the Storefront API schema.
8
+ */
9
+ const CATALOG_ROUTE_ALTERNATES_QUERY = graphql(`
10
+ query CatalogRouteAlternates($path: String!) {
11
+ catalogRoute(input: { path: $path }) {
12
+ variants {
13
+ locale
14
+ path
15
+ }
16
+ }
17
+ }
18
+ `);
19
+ /** Encodes each segment and keeps `/` literal, so a decoded path is encoded exactly once. */
20
+ function encodePath(path) {
21
+ return path.split("/").map(encodeURIComponent).join("/");
22
+ }
23
+ /**
24
+ * One binding per locale: `hreflang` maps a tag to a single URL. The default binding represents a
25
+ * locale it declares; otherwise the first binding declaring it does.
26
+ */
27
+ function representatives(bindings, defaultBindingId) {
28
+ const byLocale = /* @__PURE__ */ new Map();
29
+ for (const binding of bindings) {
30
+ const key = binding.locale.toLowerCase();
31
+ if (!byLocale.get(key) || binding.bindingId === defaultBindingId) byLocale.set(key, binding);
32
+ }
33
+ return bindings.filter((binding) => byLocale.get(binding.locale.toLowerCase()) === binding);
34
+ }
35
+ /**
36
+ * The canonical URL plus, when a reciprocal cluster exists, `languages`. A cluster needs two members
37
+ * and must include the rendered binding: search engines ignore a set that does not reference itself.
38
+ */
39
+ function buildPageAlternates({ bindingId, defaultBindingId, bindings, selfPath, clusterPaths, buildUrl }) {
40
+ const url = (id, path) => buildUrl(id, encodePath(path));
41
+ const pathOf = (id) => clusterPaths && Object.hasOwn(clusterPaths, id) ? clusterPaths[id] : void 0;
42
+ const canonical = url(bindingId, pathOf(bindingId) ?? selfPath);
43
+ const members = representatives(bindings, defaultBindingId).flatMap((binding) => {
44
+ const path = pathOf(binding.bindingId);
45
+ return path === void 0 ? [] : [{
46
+ ...binding,
47
+ href: url(binding.bindingId, path)
48
+ }];
49
+ });
50
+ if (members.length < 2 || !members.some((member) => member.bindingId === bindingId)) return { canonical };
51
+ const languages = {};
52
+ for (const member of members) languages[member.locale] = member.href;
53
+ const defaultMember = members.find((member) => member.bindingId === defaultBindingId);
54
+ if (defaultMember) languages["x-default"] = defaultMember.href;
55
+ return {
56
+ canonical,
57
+ languages
58
+ };
59
+ }
60
+ /** `.` and `..` would make the URL a crawler resolves differ from the page that states it. */
61
+ function isPathSegment(segment) {
62
+ return segment !== "" && segment !== "." && segment !== "..";
63
+ }
64
+ /**
65
+ * The logical path a route pattern names under these params, which arrive decoded
66
+ * (`decodeRouteParams`): `('/[slug]/p', { slug: 'café' })` -> `'/café/p'`. Catch-alls join with `/`;
67
+ * empty -> `'/'`.
68
+ * Empty, `.` and `..` values are dropped. It never decodes: a caller must decode first, or an
69
+ * encoded dot segment (`%2E%2E`) stays an inert literal segment.
70
+ */
71
+ function routeLogicalPath(route, params) {
72
+ return `/${route.split("/").filter(Boolean).flatMap((segment) => {
73
+ const dynamic = /^\[{1,2}(?:\.\.\.)?([^\]]+)\]{1,2}$/.exec(segment);
74
+ if (!dynamic) return [segment];
75
+ return [params[dynamic[1]] ?? []].flat();
76
+ }).filter(isPathSegment).join("/")}`;
77
+ }
78
+ function readVariants(data) {
79
+ const variants = data?.catalogRoute?.variants;
80
+ if (!Array.isArray(variants)) return [];
81
+ return variants.filter((variant) => typeof variant?.locale === "string" && typeof variant?.path === "string");
82
+ }
83
+ /** Binding id -> confirmed variant path, matching BCP 47 tags case-insensitively and nothing looser. */
84
+ function variantPathsByBinding(bindings, variants) {
85
+ const paths = {};
86
+ for (const binding of bindings) {
87
+ const locale = binding.locale.toLowerCase();
88
+ const variant = variants.find((candidate) => candidate.locale.toLowerCase() === locale);
89
+ if (variant) paths[binding.bindingId] = variant.path;
90
+ }
91
+ return paths;
92
+ }
93
+ /**
94
+ * Why a lookup degraded, safe to log: the GraphQL error code, else the allow-listed error name. `null`
95
+ * for `BAD_USER_INPUT`, which a path `catalogRoute` cannot parse (a slug with a dot) always answers.
96
+ */
97
+ function degradedReason(error) {
98
+ if (!CombinedGraphQLErrors.is(error)) return loggableErrorName(error);
99
+ const codes = error.errors.map(({ extensions }) => extensions?.code);
100
+ if (codes.length > 0 && codes.every((candidate) => candidate === "BAD_USER_INPUT")) return null;
101
+ return codes.find((candidate) => typeof candidate === "string" && candidate !== "BAD_USER_INPUT") ?? "GRAPHQL_ERROR";
102
+ }
103
+ function warnDegraded(error) {
104
+ const reason = degradedReason(error);
105
+ if (reason) console.warn("[seo.catalogClusterPaths] catalogRoute lookup degraded to no cluster", reason);
106
+ return null;
107
+ }
108
+ /**
109
+ * Binding id -> variant path for the bindings whose locale a confirmed variant matches. Never
110
+ * rejects: a thrown loader, an `error`, a missing or `null` `catalogRoute`, or no matching variant
111
+ * all resolve to `null`, so a catalog lookup can never fail the page it describes. A thrown loader
112
+ * or an `error` is logged by code or error name only, never with the path or the upstream message.
113
+ */
114
+ async function catalogClusterPaths(bindings, load) {
115
+ try {
116
+ const { data, error } = await load();
117
+ if (error) return warnDegraded(error);
118
+ const paths = variantPathsByBinding(bindings, readVariants(data));
119
+ return Object.keys(paths).length > 0 ? paths : null;
120
+ } catch (error) {
121
+ return warnDegraded(error);
122
+ }
123
+ }
124
+ //#endregion
125
+ export { CATALOG_ROUTE_ALTERNATES_QUERY, buildPageAlternates, catalogClusterPaths, encodePath, routeLogicalPath };
126
+
127
+ //# sourceMappingURL=page-alternates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-alternates.js","names":[],"sources":["../../../src/sdk/seo/page-alternates.ts"],"sourcesContent":["import { CombinedGraphQLErrors } from '@apollo/client/errors';\nimport { loggableErrorName } from '../../utils/loggable-error-name.js';\nimport { graphql } from '../generated/gql.js';\nimport type { CatalogRouteAlternatesQuery } from '../generated/graphql.js';\n\nexport type AlternateBinding = { bindingId: string; locale: string };\n\nexport type RouteVariant = NonNullable<CatalogRouteAlternatesQuery['catalogRoute']>['variants'][number];\n\n/** Structurally assignable to Next.js `Metadata['alternates']`. */\nexport type PageAlternates = {\n canonical: string;\n /** BCP 47 tag or `x-default` -> absolute URL. */\n languages?: Record<string, string>;\n};\n\nexport type RouteParams = Readonly<Record<string, string | string[] | undefined>>;\n\nexport type BuildPageAlternatesOptions = {\n bindingId: string;\n defaultBindingId: string;\n /** Every declared binding, in authoring order. */\n bindings: readonly AlternateBinding[];\n /** Decoded logical path of the request. */\n selfPath: string;\n /** Binding id -> decoded logical path, for the cluster members only. `null` means no cluster source. */\n clusterPaths: Readonly<Record<string, string>> | null;\n buildUrl: (bindingId: string, logicalPath: string) => string;\n};\n\n/**\n * The only GraphQL text the alternates feature owns. `catalogClusterPaths` reads its result, and the\n * package tests validate it against the Storefront API schema.\n */\nexport const CATALOG_ROUTE_ALTERNATES_QUERY = graphql(`\n query CatalogRouteAlternates($path: String!) {\n catalogRoute(input: { path: $path }) {\n variants {\n locale\n path\n }\n }\n }\n`);\n\n/** Encodes each segment and keeps `/` literal, so a decoded path is encoded exactly once. */\nexport function encodePath(path: string): string {\n return path.split('/').map(encodeURIComponent).join('/');\n}\n\n/**\n * One binding per locale: `hreflang` maps a tag to a single URL. The default binding represents a\n * locale it declares; otherwise the first binding declaring it does.\n */\nfunction representatives(bindings: readonly AlternateBinding[], defaultBindingId: string): AlternateBinding[] {\n const byLocale = new Map<string, AlternateBinding>();\n for (const binding of bindings) {\n const key = binding.locale.toLowerCase();\n const current = byLocale.get(key);\n if (!current || binding.bindingId === defaultBindingId) byLocale.set(key, binding);\n }\n return bindings.filter((binding) => byLocale.get(binding.locale.toLowerCase()) === binding);\n}\n\n/**\n * The canonical URL plus, when a reciprocal cluster exists, `languages`. A cluster needs two members\n * and must include the rendered binding: search engines ignore a set that does not reference itself.\n */\nexport function buildPageAlternates({\n bindingId,\n defaultBindingId,\n bindings,\n selfPath,\n clusterPaths,\n buildUrl,\n}: BuildPageAlternatesOptions): PageAlternates {\n const url = (id: string, path: string) => buildUrl(id, encodePath(path));\n const pathOf = (id: string) => (clusterPaths && Object.hasOwn(clusterPaths, id) ? clusterPaths[id] : undefined);\n const canonical = url(bindingId, pathOf(bindingId) ?? selfPath);\n\n const members = representatives(bindings, defaultBindingId).flatMap((binding) => {\n const path = pathOf(binding.bindingId);\n return path === undefined ? [] : [{ ...binding, href: url(binding.bindingId, path) }];\n });\n if (members.length < 2 || !members.some((member) => member.bindingId === bindingId)) return { canonical };\n\n const languages: Record<string, string> = {};\n for (const member of members) languages[member.locale] = member.href;\n const defaultMember = members.find((member) => member.bindingId === defaultBindingId);\n if (defaultMember) languages['x-default'] = defaultMember.href;\n return { canonical, languages };\n}\n\n/** `.` and `..` would make the URL a crawler resolves differ from the page that states it. */\nfunction isPathSegment(segment: string): boolean {\n return segment !== '' && segment !== '.' && segment !== '..';\n}\n\n/**\n * The logical path a route pattern names under these params, which arrive decoded\n * (`decodeRouteParams`): `('/[slug]/p', { slug: 'café' })` -> `'/café/p'`. Catch-alls join with `/`;\n * empty -> `'/'`.\n * Empty, `.` and `..` values are dropped. It never decodes: a caller must decode first, or an\n * encoded dot segment (`%2E%2E`) stays an inert literal segment.\n */\nexport function routeLogicalPath(route: string, params: RouteParams): string {\n const segments = route\n .split('/')\n .filter(Boolean)\n .flatMap((segment) => {\n const dynamic = /^\\[{1,2}(?:\\.\\.\\.)?([^\\]]+)\\]{1,2}$/.exec(segment);\n if (!dynamic) return [segment];\n return [params[dynamic[1] as string] ?? []].flat();\n })\n .filter(isPathSegment);\n return `/${segments.join('/')}`;\n}\n\nfunction readVariants(data: unknown): RouteVariant[] {\n const variants = (data as { catalogRoute?: { variants?: unknown } | null } | null)?.catalogRoute?.variants;\n if (!Array.isArray(variants)) return [];\n return variants.filter(\n (variant): variant is RouteVariant => typeof variant?.locale === 'string' && typeof variant?.path === 'string',\n );\n}\n\n/** Binding id -> confirmed variant path, matching BCP 47 tags case-insensitively and nothing looser. */\nfunction variantPathsByBinding(\n bindings: readonly AlternateBinding[],\n variants: readonly RouteVariant[],\n): Record<string, string> {\n const paths: Record<string, string> = {};\n for (const binding of bindings) {\n const locale = binding.locale.toLowerCase();\n const variant = variants.find((candidate) => candidate.locale.toLowerCase() === locale);\n if (variant) paths[binding.bindingId] = variant.path;\n }\n return paths;\n}\n\n/**\n * Why a lookup degraded, safe to log: the GraphQL error code, else the allow-listed error name. `null`\n * for `BAD_USER_INPUT`, which a path `catalogRoute` cannot parse (a slug with a dot) always answers.\n */\nfunction degradedReason(error: unknown): string | null {\n if (!CombinedGraphQLErrors.is(error)) return loggableErrorName(error);\n const codes = error.errors.map(({ extensions }) => extensions?.code);\n if (codes.length > 0 && codes.every((candidate) => candidate === 'BAD_USER_INPUT')) return null;\n const code = codes.find(\n (candidate): candidate is string => typeof candidate === 'string' && candidate !== 'BAD_USER_INPUT',\n );\n return code ?? 'GRAPHQL_ERROR';\n}\n\nfunction warnDegraded(error: unknown): null {\n const reason = degradedReason(error);\n if (reason) console.warn('[seo.catalogClusterPaths] catalogRoute lookup degraded to no cluster', reason);\n return null;\n}\n\n/**\n * Binding id -> variant path for the bindings whose locale a confirmed variant matches. Never\n * rejects: a thrown loader, an `error`, a missing or `null` `catalogRoute`, or no matching variant\n * all resolve to `null`, so a catalog lookup can never fail the page it describes. A thrown loader\n * or an `error` is logged by code or error name only, never with the path or the upstream message.\n */\nexport async function catalogClusterPaths(\n bindings: readonly AlternateBinding[],\n load: () => Promise<{ data: unknown; error?: unknown }>,\n): Promise<Record<string, string> | null> {\n try {\n const { data, error } = await load();\n if (error) return warnDegraded(error);\n const paths = variantPathsByBinding(bindings, readVariants(data));\n return Object.keys(paths).length > 0 ? paths : null;\n } catch (error) {\n return warnDegraded(error);\n }\n}\n"],"mappings":";;;;;;;;AAkCA,MAAa,iCAAiC,QAAQ;;;;;;;;;CASrD;;AAGD,SAAgB,WAAW,MAAsB;CAC/C,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;AACzD;;;;;AAMA,SAAS,gBAAgB,UAAuC,kBAA8C;CAC5G,MAAM,2BAAW,IAAI,IAA8B;CACnD,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,MAAM,QAAQ,OAAO,YAAY;EAEvC,IAAI,CADY,SAAS,IAAI,GAClB,KAAK,QAAQ,cAAc,kBAAkB,SAAS,IAAI,KAAK,OAAO;CACnF;CACA,OAAO,SAAS,QAAQ,YAAY,SAAS,IAAI,QAAQ,OAAO,YAAY,CAAC,MAAM,OAAO;AAC5F;;;;;AAMA,SAAgB,oBAAoB,EAClC,WACA,kBACA,UACA,UACA,cACA,YAC6C;CAC7C,MAAM,OAAO,IAAY,SAAiB,SAAS,IAAI,WAAW,IAAI,CAAC;CACvE,MAAM,UAAU,OAAgB,gBAAgB,OAAO,OAAO,cAAc,EAAE,IAAI,aAAa,MAAM,KAAA;CACrG,MAAM,YAAY,IAAI,WAAW,OAAO,SAAS,KAAK,QAAQ;CAE9D,MAAM,UAAU,gBAAgB,UAAU,gBAAgB,CAAC,CAAC,SAAS,YAAY;EAC/E,MAAM,OAAO,OAAO,QAAQ,SAAS;EACrC,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC;GAAE,GAAG;GAAS,MAAM,IAAI,QAAQ,WAAW,IAAI;EAAE,CAAC;CACtF,CAAC;CACD,IAAI,QAAQ,SAAS,KAAK,CAAC,QAAQ,MAAM,WAAW,OAAO,cAAc,SAAS,GAAG,OAAO,EAAE,UAAU;CAExG,MAAM,YAAoC,CAAC;CAC3C,KAAK,MAAM,UAAU,SAAS,UAAU,OAAO,UAAU,OAAO;CAChE,MAAM,gBAAgB,QAAQ,MAAM,WAAW,OAAO,cAAc,gBAAgB;CACpF,IAAI,eAAe,UAAU,eAAe,cAAc;CAC1D,OAAO;EAAE;EAAW;CAAU;AAChC;;AAGA,SAAS,cAAc,SAA0B;CAC/C,OAAO,YAAY,MAAM,YAAY,OAAO,YAAY;AAC1D;;;;;;;;AASA,SAAgB,iBAAiB,OAAe,QAA6B;CAU3E,OAAO,IATU,MACd,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,SAAS,YAAY;EACpB,MAAM,UAAU,sCAAsC,KAAK,OAAO;EAClE,IAAI,CAAC,SAAS,OAAO,CAAC,OAAO;EAC7B,OAAO,CAAC,OAAO,QAAQ,OAAiB,CAAC,CAAC,CAAC,CAAC,KAAK;CACnD,CAAC,CAAC,CACD,OAAO,aACQ,CAAC,CAAC,KAAK,GAAG;AAC9B;AAEA,SAAS,aAAa,MAA+B;CACnD,MAAM,WAAY,MAAkE,cAAc;CAClG,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,CAAC;CACtC,OAAO,SAAS,QACb,YAAqC,OAAO,SAAS,WAAW,YAAY,OAAO,SAAS,SAAS,QACxG;AACF;;AAGA,SAAS,sBACP,UACA,UACwB;CACxB,MAAM,QAAgC,CAAC;CACvC,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,SAAS,QAAQ,OAAO,YAAY;EAC1C,MAAM,UAAU,SAAS,MAAM,cAAc,UAAU,OAAO,YAAY,MAAM,MAAM;EACtF,IAAI,SAAS,MAAM,QAAQ,aAAa,QAAQ;CAClD;CACA,OAAO;AACT;;;;;AAMA,SAAS,eAAe,OAA+B;CACrD,IAAI,CAAC,sBAAsB,GAAG,KAAK,GAAG,OAAO,kBAAkB,KAAK;CACpE,MAAM,QAAQ,MAAM,OAAO,KAAK,EAAE,iBAAiB,YAAY,IAAI;CACnE,IAAI,MAAM,SAAS,KAAK,MAAM,OAAO,cAAc,cAAc,gBAAgB,GAAG,OAAO;CAI3F,OAHa,MAAM,MAChB,cAAmC,OAAO,cAAc,YAAY,cAAc,gBAE3E,KAAK;AACjB;AAEA,SAAS,aAAa,OAAsB;CAC1C,MAAM,SAAS,eAAe,KAAK;CACnC,IAAI,QAAQ,QAAQ,KAAK,wEAAwE,MAAM;CACvG,OAAO;AACT;;;;;;;AAQA,eAAsB,oBACpB,UACA,MACwC;CACxC,IAAI;EACF,MAAM,EAAE,MAAM,UAAU,MAAM,KAAK;EACnC,IAAI,OAAO,OAAO,aAAa,KAAK;EACpC,MAAM,QAAQ,sBAAsB,UAAU,aAAa,IAAI,CAAC;EAChE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ;CACjD,SAAS,OAAO;EACd,OAAO,aAAa,KAAK;CAC3B;AACF"}
@@ -24,7 +24,7 @@ export type ShippingAddressUpdateErrorEntity = Readonly<{
24
24
  }>;
25
25
  export type ShippingAddressInput = Readonly<{
26
26
  savedAddressId?: string;
27
- recipientName: string;
27
+ recipientName?: string;
28
28
  postalCode: string;
29
29
  country: string;
30
30
  street?: string;
@@ -62,6 +62,19 @@ const SHIPPING_ADDRESS_UPDATE = gql`
62
62
  }
63
63
  cart {
64
64
  ...CartFragment
65
+ freeShippingProgress {
66
+ threshold {
67
+ __typename
68
+ amount
69
+ currencyCode
70
+ }
71
+ remaining {
72
+ __typename
73
+ amount
74
+ currencyCode
75
+ }
76
+ qualified
77
+ }
65
78
  }
66
79
  userErrors {
67
80
  code
@@ -1 +1 @@
1
- {"version":3,"file":"shipping-operations.js","names":[],"sources":["../../../src/sdk/shipping/shipping-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Shipping address mutation documents (docs/storefront-core/reference-free-particle-model.md § The cart write contract).\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive\n * read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see\n * `codegen.ts`): the `gql` tag alone is still plucked by `graphql-codegen`, which would duplicate\n * these hand-written types in `sdk/generated/`. The mutation stays hand-typed as a\n * `TypedDocumentNode` (Decision 3 in the spec). The payload projects the full refreshed `shipping`\n * and `cart` state, so the response write into the cache *is* the post-update refresh: `Shipping`'s\n * reactive read flips with no refetch and no imperative cache write.\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`\n * (`ShippingAddressUpdateError`); transport and top-level GraphQL failures are infrastructure,\n * mapped by the handlers in `use-shipping-actions.ts` to the one client-synthesized code,\n * `NETWORK_USER_ERROR`.\n */\n\n/** A typed address-update failure; NETWORK_USER_ERROR is the one client-synthesized code. */\nexport type ShippingAddressUpdateErrorEntity = Readonly<{ code: string; message: string }>;\n\n/**\n * The one client-synthesized error code, carried by the userError that `setAddress` *resolves*\n * (never throws) when the mutation fails at the transport/top-level-GraphQL layer. Consumers use\n * it to route the resolved synthetic failure to the generic upstream error state (Decision 5),\n * distinct from the domain `userErrors` codes that render inline.\n */\nexport const SHIPPING_NETWORK_ERROR_CODE = 'NETWORK_ERROR';\n\nexport type ShippingAddressInput = Readonly<{\n savedAddressId?: string;\n recipientName: string;\n postalCode: string;\n country: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n state?: string;\n}>;\n\n/** The full shippingAddressUpdate mutation payload. */\nexport type ShippingAddressUpdatePayloadEntity = Readonly<{\n __typename: 'ShippingAddressUpdatePayload';\n shipping: {\n __typename: 'Shipping';\n id: string;\n address: {\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n } | null;\n savedAddresses: ReadonlyArray<{\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n }>;\n options: ReadonlyArray<{\n __typename: 'ShippingOption';\n id: string;\n name: string;\n channel: string;\n shippingEstimate: { __typename: 'ShippingEstimate'; value: number; unit: string };\n price: { __typename: 'Money'; amount: number; currencyCode: string };\n listPrice: { __typename: 'Money'; amount: number; currencyCode: string };\n }>;\n selectedOptionId?: string | null;\n } | null;\n cart: CartEntity;\n userErrors: readonly ShippingAddressUpdateErrorEntity[];\n}>;\n\ntype ShippingAddressUpdateData = Readonly<{ shippingAddressUpdate: ShippingAddressUpdatePayloadEntity }>;\n\nexport const SHIPPING_ADDRESS_UPDATE: TypedDocumentNode<ShippingAddressUpdateData, { input: ShippingAddressInput }> =\n gql`\n mutation ShippingAddressUpdate($input: ShippingAddressUpdateInput!) {\n shippingAddressUpdate(input: $input) {\n shipping {\n __typename\n id\n address {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n savedAddresses {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n options {\n __typename\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n cart {\n ...CartFragment\n }\n userErrors {\n code\n message\n }\n }\n }\n ${CartFragment}\n`;\n"],"mappings":";;;;;;;;;AA8BA,MAAa,8BAA8B;AAgE3C,MAAa,0BACX,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6DD,aAAa"}
1
+ {"version":3,"file":"shipping-operations.js","names":[],"sources":["../../../src/sdk/shipping/shipping-operations.ts"],"sourcesContent":["import type { TypedDocumentNode } from '@apollo/client';\nimport { type CartEntity, CartFragment, type CartFreeShippingProgress } from '../cart/operations.js';\nimport { gql } from '../graphql-tag.js';\n\n/**\n * Shipping address mutation documents (docs/storefront-core/reference-free-particle-model.md § The cart write contract).\n *\n * Authored with the hand `gql` tag — the codegen `graphql()` factory is reserved for the reactive\n * read path (`operations.ts`) — and explicitly excluded from the codegen `documents` glob (see\n * `codegen.ts`): the `gql` tag alone is still plucked by `graphql-codegen`, which would duplicate\n * these hand-written types in `sdk/generated/`. The mutation stays hand-typed as a\n * `TypedDocumentNode` (Decision 3 in the spec). The payload projects the full refreshed `shipping`\n * and `cart` state, so the response write into the cache *is* the post-update refresh: `Shipping`'s\n * reactive read flips with no refetch and no imperative cache write.\n *\n * Failures follow ADR-00007's two-path contract: domain outcomes arrive as payload `userErrors`\n * (`ShippingAddressUpdateError`); transport and top-level GraphQL failures are infrastructure,\n * mapped by the handlers in `use-shipping-actions.ts` to the one client-synthesized code,\n * `NETWORK_USER_ERROR`.\n */\n\n/** A typed address-update failure; NETWORK_USER_ERROR is the one client-synthesized code. */\nexport type ShippingAddressUpdateErrorEntity = Readonly<{ code: string; message: string }>;\n\n/**\n * The one client-synthesized error code, carried by the userError that `setAddress` *resolves*\n * (never throws) when the mutation fails at the transport/top-level-GraphQL layer. Consumers use\n * it to route the resolved synthetic failure to the generic upstream error state (Decision 5),\n * distinct from the domain `userErrors` codes that render inline.\n */\nexport const SHIPPING_NETWORK_ERROR_CODE = 'NETWORK_ERROR';\n\nexport type ShippingAddressInput = Readonly<{\n savedAddressId?: string;\n recipientName?: string;\n postalCode: string;\n country: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n state?: string;\n}>;\n\n/** The full shippingAddressUpdate mutation payload. */\nexport type ShippingAddressUpdatePayloadEntity = Readonly<{\n __typename: 'ShippingAddressUpdatePayload';\n shipping: {\n __typename: 'Shipping';\n id: string;\n address: {\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n } | null;\n savedAddresses: ReadonlyArray<{\n __typename: 'Address';\n id?: string | null;\n recipientName?: string | null;\n postalCode?: string | null;\n country: string;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n }>;\n options: ReadonlyArray<{\n __typename: 'ShippingOption';\n id: string;\n name: string;\n channel: string;\n shippingEstimate: { __typename: 'ShippingEstimate'; value: number; unit: string };\n price: { __typename: 'Money'; amount: number; currencyCode: string };\n listPrice: { __typename: 'Money'; amount: number; currencyCode: string };\n }>;\n selectedOptionId?: string | null;\n } | null;\n cart: CartEntity & { freeShippingProgress: CartFreeShippingProgress | null };\n userErrors: readonly ShippingAddressUpdateErrorEntity[];\n}>;\n\ntype ShippingAddressUpdateData = Readonly<{ shippingAddressUpdate: ShippingAddressUpdatePayloadEntity }>;\n\nexport const SHIPPING_ADDRESS_UPDATE: TypedDocumentNode<ShippingAddressUpdateData, { input: ShippingAddressInput }> =\n gql`\n mutation ShippingAddressUpdate($input: ShippingAddressUpdateInput!) {\n shippingAddressUpdate(input: $input) {\n shipping {\n __typename\n id\n address {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n savedAddresses {\n __typename\n id\n recipientName\n postalCode\n country\n street\n number\n complement\n neighborhood\n city\n state\n }\n options {\n __typename\n id\n name\n channel\n shippingEstimate {\n value\n unit\n }\n price {\n amount\n currencyCode\n }\n listPrice {\n amount\n currencyCode\n }\n }\n selectedOptionId\n }\n cart {\n ...CartFragment\n freeShippingProgress {\n threshold {\n __typename\n amount\n currencyCode\n }\n remaining {\n __typename\n amount\n currencyCode\n }\n qualified\n }\n }\n userErrors {\n code\n message\n }\n }\n }\n ${CartFragment}\n`;\n"],"mappings":";;;;;;;;;AA8BA,MAAa,8BAA8B;AAgE3C,MAAa,0BACX,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA0ED,aAAa"}
@@ -2,8 +2,12 @@
2
2
  export declare const orderFormIdVar: import("@apollo/client").ReactiveVar<string | null>;
3
3
  /**
4
4
  * Latest `userErrors` from any cart write, surfaced context-free. The cart action hook publishes
5
- * here on every call (cleared synchronously at the start of the next call) and `CartError` reads it
5
+ * here on every call and `CartError` reads it
6
6
  * via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Stays in client state — never a query variable or request header.
7
+ *
8
+ * Lifetime: each item write (add, remove, quantity) clears this var as it starts; coupon writes and
9
+ * `validate` leave it alone. A CartRoot mount clears it too, never a re-render. The var is module-level,
10
+ * so without the mount clear an error from another page would show on the next one.
7
11
  */
8
12
  export declare const cartUserErrorsVar: import("@apollo/client").ReactiveVar<readonly Readonly<{
9
13
  code: string;
@@ -30,8 +34,11 @@ export declare const miniCartOpenVar: import("@apollo/client").ReactiveVar<boole
30
34
  * Latest `userErrors` from a coupon write (`applyCoupon` / `removeCoupon`), surfaced context-free.
31
35
  * A dedicated channel mirroring `cartUserErrorsVar` so coupon feedback sits next to the coupon form
32
36
  * and never collides with item-write errors (docs/storefront-core/reference-free-particle-model.md § The cart write contract). The coupon
33
- * actions publish here on every call (cleared at the start of the next call) and `CartCouponError`
37
+ * actions publish here on every call and `CartCouponError`
34
38
  * reads it via `useReactiveVar`. Stays in client state — never a query variable or request header.
39
+ *
40
+ * Lifetime: each coupon write (apply, remove) clears this var as it starts; item writes and `validate`
41
+ * leave it alone. A CartRoot mount clears it too, never a re-render.
35
42
  */
36
43
  export declare const cartCouponErrorsVar: import("@apollo/client").ReactiveVar<readonly Readonly<{
37
44
  code: string;
@@ -3,8 +3,12 @@ import { makeVar } from "@apollo/client";
3
3
  const orderFormIdVar = makeVar(null);
4
4
  /**
5
5
  * Latest `userErrors` from any cart write, surfaced context-free. The cart action hook publishes
6
- * here on every call (cleared synchronously at the start of the next call) and `CartError` reads it
6
+ * here on every call and `CartError` reads it
7
7
  * via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Stays in client state — never a query variable or request header.
8
+ *
9
+ * Lifetime: each item write (add, remove, quantity) clears this var as it starts; coupon writes and
10
+ * `validate` leave it alone. A CartRoot mount clears it too, never a re-render. The var is module-level,
11
+ * so without the mount clear an error from another page would show on the next one.
8
12
  */
9
13
  const cartUserErrorsVar = makeVar([]);
10
14
  /**
@@ -28,8 +32,11 @@ const miniCartOpenVar = makeVar(false);
28
32
  * Latest `userErrors` from a coupon write (`applyCoupon` / `removeCoupon`), surfaced context-free.
29
33
  * A dedicated channel mirroring `cartUserErrorsVar` so coupon feedback sits next to the coupon form
30
34
  * and never collides with item-write errors (docs/storefront-core/reference-free-particle-model.md § The cart write contract). The coupon
31
- * actions publish here on every call (cleared at the start of the next call) and `CartCouponError`
35
+ * actions publish here on every call and `CartCouponError`
32
36
  * reads it via `useReactiveVar`. Stays in client state — never a query variable or request header.
37
+ *
38
+ * Lifetime: each coupon write (apply, remove) clears this var as it starts; item writes and `validate`
39
+ * leave it alone. A CartRoot mount clears it too, never a re-render.
33
40
  */
34
41
  const cartCouponErrorsVar = makeVar([]);
35
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"cart.js","names":[],"sources":["../../../src/sdk/state/cart.ts"],"sourcesContent":["import { makeVar } from '@apollo/client';\nimport type { CartUserError } from '../cart/operations.js';\n\n// Session-scoped cart identifier (`Cart.id` from the cart query response). Client state only —\n// never sent as a query variable or request header; the x-order-form-id cookie carries cart\n// context on the transport. Starts null; hydrated when the cart entity arrives, which opens the\n// cart action ready gate. See docs/storefront-core/reference-cart.md § Cart context; docs/storefront-core/reference-free-particle-model.md § The cart write contract.\nexport const orderFormIdVar = makeVar<string | null>(null);\n\n/**\n * Latest `userErrors` from any cart write, surfaced context-free. The cart action hook publishes\n * here on every call (cleared synchronously at the start of the next call) and `CartError` reads it\n * via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Stays in client state — never a query variable or request header.\n */\nexport const cartUserErrorsVar = makeVar<readonly CartUserError[]>([]);\n\n/**\n * Monotonic add-success pulse. `addItem` increments it on each successful add (no userErrors); the\n * error and network-catch branches leave it untouched. `CartOpenOnAdd` and `CartRedirectOnAdd` key\n * a `useEffect` on it via `useReactiveVar`, so every successful add re-fires their behavior even when\n * the drawer is already open or was just closed — a boolean would not re-fire on an unchanged value\n * (docs/storefront-core/reference-free-particle-model.md § Read side — state). Client state only — never a query variable\n * or request header.\n */\nexport const cartLastAddVar = makeVar<number>(0);\n\n/**\n * The mini-cart's open state, surfaced context-free. `CartOpenOnAdd` reads it via `useReactiveVar`\n * to control the `DrawerRoot` and writes it back through `onOpenChange` so the header trigger and\n * manual close (Escape / backdrop / close button) stay in sync. The single source of truth for the\n * controlled drawer; `addItem` never writes it. Client state only — never a query variable or\n * request header.\n */\nexport const miniCartOpenVar = makeVar<boolean>(false);\n\n/**\n * Latest `userErrors` from a coupon write (`applyCoupon` / `removeCoupon`), surfaced context-free.\n * A dedicated channel mirroring `cartUserErrorsVar` so coupon feedback sits next to the coupon form\n * and never collides with item-write errors (docs/storefront-core/reference-free-particle-model.md § The cart write contract). The coupon\n * actions publish here on every call (cleared at the start of the next call) and `CartCouponError`\n * reads it via `useReactiveVar`. Stays in client state — never a query variable or request header.\n */\nexport const cartCouponErrorsVar = makeVar<readonly CartUserError[]>([]);\n\n/**\n * Count of cart writes currently in flight (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Every mutating\n * handler in the cart action namespace registers for the lifetime of its call, so `> 0` means a\n * write is outstanding. The stock-validation open call reads this to skip while a write is running —\n * that write's own response already carries current availability, so re-validating would be\n * redundant. `validate` itself is read-only upstream and never registers here. Client state only —\n * never a query variable or request header.\n */\nexport const cartWritesInFlightVar = makeVar<number>(0);\n\n/**\n * Epoch-ms timestamp of when the client last received current availability (`0` = never). Stamped on\n * a successful `validate` and on every successful cart write, because a write's response already\n * carries recomputed availability (docs/storefront-core/reference-cart.md § Validation). The\n * stock-validation open call compares `now - cartAvailabilityFreshAtVar()` against\n * `CART_VALIDATE_STALENESS_MS` and skips while inside the window, so reopening the overlay — or\n * opening it right after an add — does not re-validate. Client state only.\n */\nexport const cartAvailabilityFreshAtVar = makeVar<number>(0);\n\n/**\n * The staleness window for the stock-validation open call, in milliseconds. The single tuning knob:\n * the platform's rate limits under real traffic are not known yet, so this value is a starting point,\n * not a contract (docs/storefront-core/reference-cart.md § Validation). The pre-checkout call ignores it and always\n * runs.\n */\nexport const CART_VALIDATE_STALENESS_MS = 30_000;\n"],"mappings":";;AAOA,MAAa,iBAAiB,QAAuB,IAAI;;;;;;AAOzD,MAAa,oBAAoB,QAAkC,CAAC,CAAC;;;;;;;;;AAUrE,MAAa,iBAAiB,QAAgB,CAAC;;;;;;;;AAS/C,MAAa,kBAAkB,QAAiB,KAAK;;;;;;;;AASrD,MAAa,sBAAsB,QAAkC,CAAC,CAAC;;;;;;;;;AAUvE,MAAa,wBAAwB,QAAgB,CAAC;;;;;;;;;AAUtD,MAAa,6BAA6B,QAAgB,CAAC;;;;;;;AAQ3D,MAAa,6BAA6B"}
1
+ {"version":3,"file":"cart.js","names":[],"sources":["../../../src/sdk/state/cart.ts"],"sourcesContent":["import { makeVar } from '@apollo/client';\nimport type { CartUserError } from '../cart/operations.js';\n\n// Session-scoped cart identifier (`Cart.id` from the cart query response). Client state only —\n// never sent as a query variable or request header; the x-order-form-id cookie carries cart\n// context on the transport. Starts null; hydrated when the cart entity arrives, which opens the\n// cart action ready gate. See docs/storefront-core/reference-cart.md § Cart context; docs/storefront-core/reference-free-particle-model.md § The cart write contract.\nexport const orderFormIdVar = makeVar<string | null>(null);\n\n/**\n * Latest `userErrors` from any cart write, surfaced context-free. The cart action hook publishes\n * here on every call and `CartError` reads it\n * via `useReactiveVar`, decoupling error display from `CartRoot`'s data context (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Stays in client state — never a query variable or request header.\n *\n * Lifetime: each item write (add, remove, quantity) clears this var as it starts; coupon writes and\n * `validate` leave it alone. A CartRoot mount clears it too, never a re-render. The var is module-level,\n * so without the mount clear an error from another page would show on the next one.\n */\nexport const cartUserErrorsVar = makeVar<readonly CartUserError[]>([]);\n\n/**\n * Monotonic add-success pulse. `addItem` increments it on each successful add (no userErrors); the\n * error and network-catch branches leave it untouched. `CartOpenOnAdd` and `CartRedirectOnAdd` key\n * a `useEffect` on it via `useReactiveVar`, so every successful add re-fires their behavior even when\n * the drawer is already open or was just closed — a boolean would not re-fire on an unchanged value\n * (docs/storefront-core/reference-free-particle-model.md § Read side — state). Client state only — never a query variable\n * or request header.\n */\nexport const cartLastAddVar = makeVar<number>(0);\n\n/**\n * The mini-cart's open state, surfaced context-free. `CartOpenOnAdd` reads it via `useReactiveVar`\n * to control the `DrawerRoot` and writes it back through `onOpenChange` so the header trigger and\n * manual close (Escape / backdrop / close button) stay in sync. The single source of truth for the\n * controlled drawer; `addItem` never writes it. Client state only — never a query variable or\n * request header.\n */\nexport const miniCartOpenVar = makeVar<boolean>(false);\n\n/**\n * Latest `userErrors` from a coupon write (`applyCoupon` / `removeCoupon`), surfaced context-free.\n * A dedicated channel mirroring `cartUserErrorsVar` so coupon feedback sits next to the coupon form\n * and never collides with item-write errors (docs/storefront-core/reference-free-particle-model.md § The cart write contract). The coupon\n * actions publish here on every call and `CartCouponError`\n * reads it via `useReactiveVar`. Stays in client state — never a query variable or request header.\n *\n * Lifetime: each coupon write (apply, remove) clears this var as it starts; item writes and `validate`\n * leave it alone. A CartRoot mount clears it too, never a re-render.\n */\nexport const cartCouponErrorsVar = makeVar<readonly CartUserError[]>([]);\n\n/**\n * Count of cart writes currently in flight (docs/storefront-core/reference-free-particle-model.md § The cart write contract). Every mutating\n * handler in the cart action namespace registers for the lifetime of its call, so `> 0` means a\n * write is outstanding. The stock-validation open call reads this to skip while a write is running —\n * that write's own response already carries current availability, so re-validating would be\n * redundant. `validate` itself is read-only upstream and never registers here. Client state only —\n * never a query variable or request header.\n */\nexport const cartWritesInFlightVar = makeVar<number>(0);\n\n/**\n * Epoch-ms timestamp of when the client last received current availability (`0` = never). Stamped on\n * a successful `validate` and on every successful cart write, because a write's response already\n * carries recomputed availability (docs/storefront-core/reference-cart.md § Validation). The\n * stock-validation open call compares `now - cartAvailabilityFreshAtVar()` against\n * `CART_VALIDATE_STALENESS_MS` and skips while inside the window, so reopening the overlay — or\n * opening it right after an add — does not re-validate. Client state only.\n */\nexport const cartAvailabilityFreshAtVar = makeVar<number>(0);\n\n/**\n * The staleness window for the stock-validation open call, in milliseconds. The single tuning knob:\n * the platform's rate limits under real traffic are not known yet, so this value is a starting point,\n * not a contract (docs/storefront-core/reference-cart.md § Validation). The pre-checkout call ignores it and always\n * runs.\n */\nexport const CART_VALIDATE_STALENESS_MS = 30_000;\n"],"mappings":";;AAOA,MAAa,iBAAiB,QAAuB,IAAI;;;;;;;;;;AAWzD,MAAa,oBAAoB,QAAkC,CAAC,CAAC;;;;;;;;;AAUrE,MAAa,iBAAiB,QAAgB,CAAC;;;;;;;;AAS/C,MAAa,kBAAkB,QAAiB,KAAK;;;;;;;;;;;AAYrD,MAAa,sBAAsB,QAAkC,CAAC,CAAC;;;;;;;;;AAUvE,MAAa,wBAAwB,QAAgB,CAAC;;;;;;;;;AAUtD,MAAa,6BAA6B,QAAgB,CAAC;;;;;;;AAQ3D,MAAa,6BAA6B"}
@@ -0,0 +1,19 @@
1
+ //#region src/utils/own-value.ts
2
+ /**
3
+ * Own-property read. `Object.hasOwn`, not a bare index lookup or `key in source`: every plain object
4
+ * inherits from `Object.prototype`, so `source['constructor']` resolves to
5
+ * `Object.prototype.constructor` — a function, therefore never `undefined` — and `__proto__` to the
6
+ * prototype itself, and the absent-key branch of the caller would never be taken. Every keyed
7
+ * lookup here is fed an authored or user-typed key (an element id from `JSON.parse`, a card network
8
+ * or payment method name), so an inherited name must read as missing, never as a value.
9
+ *
10
+ * Lives in `utils/` because its callers span peer domains (`sdk/content`, `matter/card-entry`,
11
+ * `matter/payment`), none of which should import a lookup helper from another.
12
+ */
13
+ function ownValue(source, key) {
14
+ return Object.hasOwn(source, key) ? source[key] : void 0;
15
+ }
16
+ //#endregion
17
+ export { ownValue };
18
+
19
+ //# sourceMappingURL=own-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"own-value.js","names":[],"sources":["../../src/utils/own-value.ts"],"sourcesContent":["/**\n * Own-property read. `Object.hasOwn`, not a bare index lookup or `key in source`: every plain object\n * inherits from `Object.prototype`, so `source['constructor']` resolves to\n * `Object.prototype.constructor` — a function, therefore never `undefined` — and `__proto__` to the\n * prototype itself, and the absent-key branch of the caller would never be taken. Every keyed\n * lookup here is fed an authored or user-typed key (an element id from `JSON.parse`, a card network\n * or payment method name), so an inherited name must read as missing, never as a value.\n *\n * Lives in `utils/` because its callers span peer domains (`sdk/content`, `matter/card-entry`,\n * `matter/payment`), none of which should import a lookup helper from another.\n */\nexport function ownValue<T>(source: Record<string, T>, key: string): T | undefined {\n return Object.hasOwn(source, key) ? source[key] : undefined;\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,SAAY,QAA2B,KAA4B;CACjF,OAAO,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,OAAO,KAAA;AACpD"}
@@ -1,11 +1,11 @@
1
+ import { PageRef } from "../sdk/navigation/types.js";
1
2
  //#region src/utils/safe-href.d.ts
2
3
  /**
3
- * Builds the sign-in destination, carrying the current path so the shopper can be returned where they
4
+ * The sign-in page, carrying the current logical path so the shopper can be returned where they
4
5
  * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow
5
6
  * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of
6
- * travelling encoded, and so does a router reporting no path — `usePathname()`'s type is why this takes
7
- * a nullable one.
7
+ * travelling encoded, and so does a router reporting no path.
8
8
  */
9
- export declare function resolveSignInHref(pathname: string | null): string;
9
+ export declare function signInTarget(path: string | null): PageRef;
10
10
  //#endregion
11
11
  //# sourceMappingURL=safe-href.d.ts.map
@@ -49,9 +49,8 @@ function resolveSafeHref(raw) {
49
49
  reason: "forbidden-scheme"
50
50
  };
51
51
  }
52
- /** The storefront's own sign-in route, which forwards to the platform's login. A fixed convention,
53
- * never an authored value. */
54
- const SIGN_IN_ROUTE = "/login";
52
+ /** The storefront's own sign-in page, which forwards to the platform's login. Never an authored value. */
53
+ const SIGN_IN_PAGE = { standard: "sign-in" };
55
54
  /** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */
56
55
  const RETURN_URL_PARAM = "returnUrl";
57
56
  /**
@@ -61,7 +60,7 @@ const RETURN_URL_PARAM = "returnUrl";
61
60
  * unchanged, so a caller logging the reason still sees which spelling arrived.
62
61
  *
63
62
  * Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch
64
- * for a URL the shopper typed: the account button builds the destination through `resolveSignInHref`, and
63
+ * for a URL the shopper typed: the account button builds the destination through `signInTarget`, and
65
64
  * the sign-in route revalidates what arrives through `resolveReturnHref`.
66
65
  */
67
66
  function resolveSiteRelativeHref(raw) {
@@ -92,50 +91,60 @@ function resolveNavigableHref(raw) {
92
91
  * `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route
93
92
  * itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which
94
93
  * hands them to the platform a second time — a sign-in that never lands where the parameter promised.
94
+ *
95
+ * `signInPath` is the sign-in page's logical path, since a return is one; `null` when the store has no
96
+ * sign-in page, and then no return is the route.
95
97
  */
96
- function resolveReturnHref(raw) {
98
+ function resolveReturnHref(raw, signInPath) {
97
99
  const destination = resolveSiteRelativeHref(raw);
98
100
  if (!destination.safe) return destination;
99
- return isSignInRoute(destination.href) ? {
101
+ return isSignInRoute(destination.href, signInPath) ? {
100
102
  safe: false,
101
103
  reason: "sign-in-route"
102
104
  } : destination;
103
105
  }
104
- /** Whether a site-relative value names the storefront's own sign-in route, in any of its spellings. */
105
- function isSignInRoute(href) {
106
- return pathOf(href) === SIGN_IN_ROUTE;
106
+ /**
107
+ * Whether a site-relative value names the sign-in page at `signInPath`, in any of its spellings. `null`
108
+ * is a store without a sign-in page, where nothing is the route.
109
+ */
110
+ function isSignInRoute(href, signInPath) {
111
+ return signInPath !== null && pathOf(href) === pathOf(signInPath);
107
112
  }
108
113
  /**
109
114
  * `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in
110
- * route is refused. Sending `/login` to `/login` reloads the same document, which mounts the same
115
+ * route is refused. Sending the route to itself reloads the same document, which mounts the same
111
116
  * handover again — a loop the shopper never gets past, and the mirror of the refusal
112
117
  * `resolveReturnHref` already makes on the way back.
113
118
  *
114
119
  * Only the site-relative spelling is decidable here, being same-origin by construction. An absolute
115
120
  * address needs the document's own origin to compare against, which this module does not have and a
116
121
  * prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin
117
- * login page whose path happens to be `/login` is a different page and is left alone.
122
+ * login page whose path happens to be the route's is a different page and is left alone.
123
+ *
124
+ * `signInPath` is the sign-in page's public path, since the address is a document URL.
118
125
  */
119
- function resolveLoginAddressHref(raw) {
126
+ function resolveLoginAddressHref(raw, signInPath) {
120
127
  const address = resolveNavigableHref(raw);
121
128
  if (!address.safe || !address.href.startsWith("/")) return address;
122
- return isSignInRoute(address.href) ? {
129
+ return isSignInRoute(address.href, signInPath) ? {
123
130
  safe: false,
124
131
  reason: "sign-in-route"
125
132
  } : address;
126
133
  }
127
134
  /**
128
- * Builds the sign-in destination, carrying the current path so the shopper can be returned where they
135
+ * The sign-in page, carrying the current logical path so the shopper can be returned where they
129
136
  * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow
130
137
  * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of
131
- * travelling encoded, and so does a router reporting no path — `usePathname()`'s type is why this takes
132
- * a nullable one.
138
+ * travelling encoded, and so does a router reporting no path.
133
139
  */
134
- function resolveSignInHref(pathname) {
135
- if (!pathname) return SIGN_IN_ROUTE;
136
- const destination = resolveSiteRelativeHref(pathname);
137
- if (!destination.safe) return SIGN_IN_ROUTE;
138
- return `${SIGN_IN_ROUTE}?${RETURN_URL_PARAM}=${encodeURIComponent(destination.href)}`;
140
+ function signInTarget(path) {
141
+ if (!path) return SIGN_IN_PAGE;
142
+ const destination = resolveSiteRelativeHref(path);
143
+ if (!destination.safe) return SIGN_IN_PAGE;
144
+ return {
145
+ standard: "sign-in",
146
+ query: { [RETURN_URL_PARAM]: destination.href }
147
+ };
139
148
  }
140
149
  /** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a
141
150
  * real host; nothing is navigated to it and only `pathname` is read back. */
@@ -164,6 +173,6 @@ function hasStrippableCharacter(value) {
164
173
  return false;
165
174
  }
166
175
  //#endregion
167
- export { RETURN_URL_PARAM, isSignInRoute, resolveLoginAddressHref, resolveNavigableHref, resolveReturnHref, resolveSafeHref, resolveSignInHref, resolveSiteRelativeHref };
176
+ export { RETURN_URL_PARAM, SIGN_IN_PAGE, isSignInRoute, resolveLoginAddressHref, resolveNavigableHref, resolveReturnHref, resolveSafeHref, resolveSiteRelativeHref, signInTarget };
168
177
 
169
178
  //# sourceMappingURL=safe-href.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-href.js","names":[],"sources":["../../src/utils/safe-href.ts"],"sourcesContent":["export type SafeHrefRejection =\n | 'blank'\n | 'malformed'\n | 'protocol-relative'\n | 'forbidden-scheme'\n | 'absolute'\n | 'sign-in-route';\n\nexport type SafeHrefResult = { safe: true; href: string } | { safe: false; reason: SafeHrefRejection };\n\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/**\n * The only gate on a CMS-authored destination: `http:`, `https:`, `mailto:`, `tel:`, and paths\n * starting with a single `/`. The runtime slice does not enforce a model's `pattern`, and the sukima\n * preflight that does never sees content published after a deploy, so an authored `javascript:` value\n * can reach the component intact and this is what stands between it and an `href`.\n *\n * Rejects rather than sanitizes: a destination that comes back safe is character-for-character the\n * trimmed authored value, so no value is ever silently rewritten into a different working one.\n */\nexport function resolveSafeHref(raw: string): SafeHrefResult {\n const href = raw.trim();\n if (href.length === 0) {\n return { safe: false, reason: 'blank' };\n }\n // Browsers strip ASCII tabs and newlines from a URL before parsing it, so `java<TAB>script:alert(1)`\n // executes. Refusing the whole value is the only defense that does not depend on stripping the same\n // characters in the same order the parser does.\n if (hasStrippableCharacter(href)) {\n return { safe: false, reason: 'malformed' };\n }\n // A URL parser reads `\\` as `/` under a special scheme, so `/\\evil.example` resolves against the\n // store's origin as an authority rather than a path. Any pair of leading slashes is an off-site\n // jump however it is spelled, and only `//` looks like one.\n if (/^[/\\\\]{2}/.test(href)) {\n return { safe: false, reason: 'protocol-relative' };\n }\n if (href.startsWith('/')) {\n return { safe: true, href };\n }\n\n let protocol: string;\n try {\n protocol = new URL(href).protocol;\n } catch {\n return { safe: false, reason: 'malformed' };\n }\n // `new URL` lowercases the protocol, so `JavaScript:` and `javascript:` are the same rejection.\n return ALLOWED_PROTOCOLS.has(protocol) ? { safe: true, href } : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/** The storefront's own sign-in route, which forwards to the platform's login. A fixed convention,\n * never an authored value. */\nconst SIGN_IN_ROUTE = '/login';\n\n/** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */\nexport const RETURN_URL_PARAM = 'returnUrl';\n\n/**\n * `resolveSafeHref` narrowed to the site-relative subset: the destinations a shopper may be sent back to\n * across the auth hop. The allowlist admits absolute http(s) values, which are legitimate for an authored\n * link but are exactly what would turn the hop into an open redirect. Every other rejection travels out\n * unchanged, so a caller logging the reason still sees which spelling arrived.\n *\n * Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch\n * for a URL the shopper typed: the account button builds the destination through `resolveSignInHref`, and\n * the sign-in route revalidates what arrives through `resolveReturnHref`.\n */\nexport function resolveSiteRelativeHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return destination.href.startsWith('/') ? destination : { safe: false, reason: 'absolute' };\n}\n\n/** The subset of the allowlist that resolves to a page a document can be handed over to. */\nconst NAVIGABLE_PROTOCOLS = new Set(['http:', 'https:']);\n\n/**\n * `resolveSafeHref` narrowed to the destinations that resolve to a page: site-relative, or absolute\n * `http(s)`. `mailto:` and `tel:` are legitimate for an authored link and refused here, since handing a\n * document over to one leaves the shopper in a mail client instead of a login.\n */\nexport function resolveNavigableHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe || destination.href.startsWith('/')) {\n return destination;\n }\n // The allowlist already parsed this value, so the protocol is readable without a second guard.\n const { protocol } = new URL(destination.href);\n return NAVIGABLE_PROTOCOLS.has(protocol) ? destination : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/**\n * `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route\n * itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which\n * hands them to the platform a second time — a sign-in that never lands where the parameter promised.\n */\nexport function resolveReturnHref(raw: string): SafeHrefResult {\n const destination = resolveSiteRelativeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return isSignInRoute(destination.href) ? { safe: false, reason: 'sign-in-route' } : destination;\n}\n\n/** Whether a site-relative value names the storefront's own sign-in route, in any of its spellings. */\nexport function isSignInRoute(href: string): boolean {\n return pathOf(href) === SIGN_IN_ROUTE;\n}\n\n/**\n * `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in\n * route is refused. Sending `/login` to `/login` reloads the same document, which mounts the same\n * handover again — a loop the shopper never gets past, and the mirror of the refusal\n * `resolveReturnHref` already makes on the way back.\n *\n * Only the site-relative spelling is decidable here, being same-origin by construction. An absolute\n * address needs the document's own origin to compare against, which this module does not have and a\n * prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin\n * login page whose path happens to be `/login` is a different page and is left alone.\n */\nexport function resolveLoginAddressHref(raw: string): SafeHrefResult {\n const address = resolveNavigableHref(raw);\n if (!address.safe || !address.href.startsWith('/')) {\n return address;\n }\n return isSignInRoute(address.href) ? { safe: false, reason: 'sign-in-route' } : address;\n}\n\n/**\n * Builds the sign-in destination, carrying the current path so the shopper can be returned where they\n * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow\n * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of\n * travelling encoded, and so does a router reporting no path — `usePathname()`'s type is why this takes\n * a nullable one.\n */\nexport function resolveSignInHref(pathname: string | null): string {\n if (!pathname) {\n return SIGN_IN_ROUTE;\n }\n const destination = resolveSiteRelativeHref(pathname);\n if (!destination.safe) {\n return SIGN_IN_ROUTE;\n }\n return `${SIGN_IN_ROUTE}?${RETURN_URL_PARAM}=${encodeURIComponent(destination.href)}`;\n}\n\n/** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a\n * real host; nothing is navigated to it and only `pathname` is read back. */\nconst PATH_COMPARISON_BASE = 'https://store.invalid';\n\n/**\n * The path of a site-relative value, without its query or fragment and without a trailing slash, so a\n * route comparison reads the route rather than one of its spellings. `/loginhelp` is a different path\n * and stays one.\n *\n * Parsed rather than sliced, because `/account/../login`, `/account\\..\\login` and `/account/%2e%2e/login`\n * are all spellings a URL parser resolves to `/login`. A slice compares them literally and admits them,\n * and the value then reaches a receiver that does resolve them — which puts the shopper back on the\n * trampoline the refusal exists to prevent. Only the comparison is normalized: the caller returns the\n * value as it arrived, so the promise that nothing is silently rewritten still holds.\n */\nfunction pathOf(href: string): string {\n const { pathname } = new URL(href, PATH_COMPARISON_BASE);\n return pathname.replace(/\\/+$/, '') || '/';\n}\n\n/** Any C0 control or space anywhere in the value — the set a URL parser removes or trims. */\nfunction hasStrippableCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";AAUA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC;;;;;;;;;;AAWxE,SAAgB,gBAAgB,KAA6B;CAC3D,MAAM,OAAO,IAAI,KAAK;CACtB,IAAI,KAAK,WAAW,GAClB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAQ;CAKxC,IAAI,uBAAuB,IAAI,GAC7B,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAY;CAK5C,IAAI,YAAY,KAAK,IAAI,GACvB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAoB;CAEpD,IAAI,KAAK,WAAW,GAAG,GACrB,OAAO;EAAE,MAAM;EAAM;CAAK;CAG5B,IAAI;CACJ,IAAI;EACF,WAAW,IAAI,IAAI,IAAI,CAAC,CAAC;CAC3B,QAAQ;EACN,OAAO;GAAE,MAAM;GAAO,QAAQ;EAAY;CAC5C;CAEA,OAAO,kBAAkB,IAAI,QAAQ,IAAI;EAAE,MAAM;EAAM;CAAK,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAmB;AAC5G;;;AAIA,MAAM,gBAAgB;;AAGtB,MAAa,mBAAmB;;;;;;;;;;;AAYhC,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,YAAY,KAAK,WAAW,GAAG,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAW;AAC5F;;AAGA,MAAM,sCAAsB,IAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;;;;;;AAOvD,SAAgB,qBAAqB,KAA6B;CAChE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,QAAQ,YAAY,KAAK,WAAW,GAAG,GACtD,OAAO;CAGT,MAAM,EAAE,aAAa,IAAI,IAAI,YAAY,IAAI;CAC7C,OAAO,oBAAoB,IAAI,QAAQ,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAmB;AACrG;;;;;;AAOA,SAAgB,kBAAkB,KAA6B;CAC7D,MAAM,cAAc,wBAAwB,GAAG;CAC/C,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,cAAc,YAAY,IAAI,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AACtF;;AAGA,SAAgB,cAAc,MAAuB;CACnD,OAAO,OAAO,IAAI,MAAM;AAC1B;;;;;;;;;;;;AAaA,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,KAAK,WAAW,GAAG,GAC/C,OAAO;CAET,OAAO,cAAc,QAAQ,IAAI,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAClF;;;;;;;;AASA,SAAgB,kBAAkB,UAAiC;CACjE,IAAI,CAAC,UACH,OAAO;CAET,MAAM,cAAc,wBAAwB,QAAQ;CACpD,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,GAAG,cAAc,GAAG,iBAAiB,GAAG,mBAAmB,YAAY,IAAI;AACpF;;;AAIA,MAAM,uBAAuB;;;;;;;;;;;;AAa7B,SAAS,OAAO,MAAsB;CACpC,MAAM,EAAE,aAAa,IAAI,IAAI,MAAM,oBAAoB;CACvD,OAAO,SAAS,QAAQ,QAAQ,EAAE,KAAK;AACzC;;AAGA,SAAS,uBAAuB,OAAwB;CACtD,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,OAAO,UAAU,YAAY,CAAC,KAAK;EACzC,IAAI,QAAQ,MAAQ,SAAS,KAC3B,OAAO;CAEX;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"safe-href.js","names":[],"sources":["../../src/utils/safe-href.ts"],"sourcesContent":["import type { PageRef } from '../sdk/navigation/types.js';\n\nexport type SafeHrefRejection =\n | 'blank'\n | 'malformed'\n | 'protocol-relative'\n | 'forbidden-scheme'\n | 'absolute'\n | 'sign-in-route';\n\nexport type SafeHrefResult = { safe: true; href: string } | { safe: false; reason: SafeHrefRejection };\n\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\n\n/**\n * The only gate on a CMS-authored destination: `http:`, `https:`, `mailto:`, `tel:`, and paths\n * starting with a single `/`. The runtime slice does not enforce a model's `pattern`, and the sukima\n * preflight that does never sees content published after a deploy, so an authored `javascript:` value\n * can reach the component intact and this is what stands between it and an `href`.\n *\n * Rejects rather than sanitizes: a destination that comes back safe is character-for-character the\n * trimmed authored value, so no value is ever silently rewritten into a different working one.\n */\nexport function resolveSafeHref(raw: string): SafeHrefResult {\n const href = raw.trim();\n if (href.length === 0) {\n return { safe: false, reason: 'blank' };\n }\n // Browsers strip ASCII tabs and newlines from a URL before parsing it, so `java<TAB>script:alert(1)`\n // executes. Refusing the whole value is the only defense that does not depend on stripping the same\n // characters in the same order the parser does.\n if (hasStrippableCharacter(href)) {\n return { safe: false, reason: 'malformed' };\n }\n // A URL parser reads `\\` as `/` under a special scheme, so `/\\evil.example` resolves against the\n // store's origin as an authority rather than a path. Any pair of leading slashes is an off-site\n // jump however it is spelled, and only `//` looks like one.\n if (/^[/\\\\]{2}/.test(href)) {\n return { safe: false, reason: 'protocol-relative' };\n }\n if (href.startsWith('/')) {\n return { safe: true, href };\n }\n\n let protocol: string;\n try {\n protocol = new URL(href).protocol;\n } catch {\n return { safe: false, reason: 'malformed' };\n }\n // `new URL` lowercases the protocol, so `JavaScript:` and `javascript:` are the same rejection.\n return ALLOWED_PROTOCOLS.has(protocol) ? { safe: true, href } : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/** The storefront's own sign-in page, which forwards to the platform's login. Never an authored value. */\nexport const SIGN_IN_PAGE: PageRef = { standard: 'sign-in' };\n\n/** The parameter carrying the shopper's way back, read by the sign-in route and the platform's login. */\nexport const RETURN_URL_PARAM = 'returnUrl';\n\n/**\n * `resolveSafeHref` narrowed to the site-relative subset: the destinations a shopper may be sent back to\n * across the auth hop. The allowlist admits absolute http(s) values, which are legitimate for an authored\n * link but are exactly what would turn the hop into an open redirect. Every other rejection travels out\n * unchanged, so a caller logging the reason still sees which spelling arrived.\n *\n * Both ends of the flow narrow through here rather than only the sender, because the sender cannot vouch\n * for a URL the shopper typed: the account button builds the destination through `signInTarget`, and\n * the sign-in route revalidates what arrives through `resolveReturnHref`.\n */\nexport function resolveSiteRelativeHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return destination.href.startsWith('/') ? destination : { safe: false, reason: 'absolute' };\n}\n\n/** The subset of the allowlist that resolves to a page a document can be handed over to. */\nconst NAVIGABLE_PROTOCOLS = new Set(['http:', 'https:']);\n\n/**\n * `resolveSafeHref` narrowed to the destinations that resolve to a page: site-relative, or absolute\n * `http(s)`. `mailto:` and `tel:` are legitimate for an authored link and refused here, since handing a\n * document over to one leaves the shopper in a mail client instead of a login.\n */\nexport function resolveNavigableHref(raw: string): SafeHrefResult {\n const destination = resolveSafeHref(raw);\n if (!destination.safe || destination.href.startsWith('/')) {\n return destination;\n }\n // The allowlist already parsed this value, so the protocol is readable without a second guard.\n const { protocol } = new URL(destination.href);\n return NAVIGABLE_PROTOCOLS.has(protocol) ? destination : { safe: false, reason: 'forbidden-scheme' };\n}\n\n/**\n * `resolveSiteRelativeHref` narrowed further, for a return arriving at the sign-in route: the route\n * itself is refused. Admitting it sends a shopper who just authenticated back to the trampoline, which\n * hands them to the platform a second time — a sign-in that never lands where the parameter promised.\n *\n * `signInPath` is the sign-in page's logical path, since a return is one; `null` when the store has no\n * sign-in page, and then no return is the route.\n */\nexport function resolveReturnHref(raw: string, signInPath: string | null): SafeHrefResult {\n const destination = resolveSiteRelativeHref(raw);\n if (!destination.safe) {\n return destination;\n }\n return isSignInRoute(destination.href, signInPath) ? { safe: false, reason: 'sign-in-route' } : destination;\n}\n\n/**\n * Whether a site-relative value names the sign-in page at `signInPath`, in any of its spellings. `null`\n * is a store without a sign-in page, where nothing is the route.\n */\nexport function isSignInRoute(href: string, signInPath: string | null): boolean {\n return signInPath !== null && pathOf(href) === pathOf(signInPath);\n}\n\n/**\n * `resolveNavigableHref` narrowed for the address a handover targets: the storefront's own sign-in\n * route is refused. Sending the route to itself reloads the same document, which mounts the same\n * handover again — a loop the shopper never gets past, and the mirror of the refusal\n * `resolveReturnHref` already makes on the way back.\n *\n * Only the site-relative spelling is decidable here, being same-origin by construction. An absolute\n * address needs the document's own origin to compare against, which this module does not have and a\n * prerender does not either, so `isSignInRoute` is exported for the caller that does. A cross-origin\n * login page whose path happens to be the route's is a different page and is left alone.\n *\n * `signInPath` is the sign-in page's public path, since the address is a document URL.\n */\nexport function resolveLoginAddressHref(raw: string, signInPath: string | null): SafeHrefResult {\n const address = resolveNavigableHref(raw);\n if (!address.safe || !address.href.startsWith('/')) {\n return address;\n }\n return isSignInRoute(address.href, signInPath) ? { safe: false, reason: 'sign-in-route' } : address;\n}\n\n/**\n * The sign-in page, carrying the current logical path so the shopper can be returned where they\n * started. The sender's half only: nothing stops a hand-crafted link, so the sign-in route is to narrow\n * the parameter again on arrival. A path the narrowing refuses drops the parameter instead of\n * travelling encoded, and so does a router reporting no path.\n */\nexport function signInTarget(path: string | null): PageRef {\n if (!path) {\n return SIGN_IN_PAGE;\n }\n const destination = resolveSiteRelativeHref(path);\n if (!destination.safe) {\n return SIGN_IN_PAGE;\n }\n return { standard: 'sign-in', query: { [RETURN_URL_PARAM]: destination.href } };\n}\n\n/** Opaque base for resolving a site-relative value to a path. Reserved by RFC 6761, so it never names a\n * real host; nothing is navigated to it and only `pathname` is read back. */\nconst PATH_COMPARISON_BASE = 'https://store.invalid';\n\n/**\n * The path of a site-relative value, without its query or fragment and without a trailing slash, so a\n * route comparison reads the route rather than one of its spellings. `/loginhelp` is a different path\n * and stays one.\n *\n * Parsed rather than sliced, because `/account/../login`, `/account\\..\\login` and `/account/%2e%2e/login`\n * are all spellings a URL parser resolves to `/login`. A slice compares them literally and admits them,\n * and the value then reaches a receiver that does resolve them — which puts the shopper back on the\n * trampoline the refusal exists to prevent. Only the comparison is normalized: the caller returns the\n * value as it arrived, so the promise that nothing is silently rewritten still holds.\n */\nfunction pathOf(href: string): string {\n const { pathname } = new URL(href, PATH_COMPARISON_BASE);\n return pathname.replace(/\\/+$/, '') || '/';\n}\n\n/** Any C0 control or space anywhere in the value — the set a URL parser removes or trims. */\nfunction hasStrippableCharacter(value: string): boolean {\n for (const character of value) {\n const code = character.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";AAYA,MAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC;;;;;;;;;;AAWxE,SAAgB,gBAAgB,KAA6B;CAC3D,MAAM,OAAO,IAAI,KAAK;CACtB,IAAI,KAAK,WAAW,GAClB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAQ;CAKxC,IAAI,uBAAuB,IAAI,GAC7B,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAY;CAK5C,IAAI,YAAY,KAAK,IAAI,GACvB,OAAO;EAAE,MAAM;EAAO,QAAQ;CAAoB;CAEpD,IAAI,KAAK,WAAW,GAAG,GACrB,OAAO;EAAE,MAAM;EAAM;CAAK;CAG5B,IAAI;CACJ,IAAI;EACF,WAAW,IAAI,IAAI,IAAI,CAAC,CAAC;CAC3B,QAAQ;EACN,OAAO;GAAE,MAAM;GAAO,QAAQ;EAAY;CAC5C;CAEA,OAAO,kBAAkB,IAAI,QAAQ,IAAI;EAAE,MAAM;EAAM;CAAK,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAmB;AAC5G;;AAGA,MAAa,eAAwB,EAAE,UAAU,UAAU;;AAG3D,MAAa,mBAAmB;;;;;;;;;;;AAYhC,SAAgB,wBAAwB,KAA6B;CACnE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,YAAY,KAAK,WAAW,GAAG,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAW;AAC5F;;AAGA,MAAM,sCAAsB,IAAI,IAAI,CAAC,SAAS,QAAQ,CAAC;;;;;;AAOvD,SAAgB,qBAAqB,KAA6B;CAChE,MAAM,cAAc,gBAAgB,GAAG;CACvC,IAAI,CAAC,YAAY,QAAQ,YAAY,KAAK,WAAW,GAAG,GACtD,OAAO;CAGT,MAAM,EAAE,aAAa,IAAI,IAAI,YAAY,IAAI;CAC7C,OAAO,oBAAoB,IAAI,QAAQ,IAAI,cAAc;EAAE,MAAM;EAAO,QAAQ;CAAmB;AACrG;;;;;;;;;AAUA,SAAgB,kBAAkB,KAAa,YAA2C;CACxF,MAAM,cAAc,wBAAwB,GAAG;CAC/C,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO,cAAc,YAAY,MAAM,UAAU,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAClG;;;;;AAMA,SAAgB,cAAc,MAAc,YAAoC;CAC9E,OAAO,eAAe,QAAQ,OAAO,IAAI,MAAM,OAAO,UAAU;AAClE;;;;;;;;;;;;;;AAeA,SAAgB,wBAAwB,KAAa,YAA2C;CAC9F,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,KAAK,WAAW,GAAG,GAC/C,OAAO;CAET,OAAO,cAAc,QAAQ,MAAM,UAAU,IAAI;EAAE,MAAM;EAAO,QAAQ;CAAgB,IAAI;AAC9F;;;;;;;AAQA,SAAgB,aAAa,MAA8B;CACzD,IAAI,CAAC,MACH,OAAO;CAET,MAAM,cAAc,wBAAwB,IAAI;CAChD,IAAI,CAAC,YAAY,MACf,OAAO;CAET,OAAO;EAAE,UAAU;EAAW,OAAO,GAAG,mBAAmB,YAAY,KAAK;CAAE;AAChF;;;AAIA,MAAM,uBAAuB;;;;;;;;;;;;AAa7B,SAAS,OAAO,MAAsB;CACpC,MAAM,EAAE,aAAa,IAAI,IAAI,MAAM,oBAAoB;CACvD,OAAO,SAAS,QAAQ,QAAQ,EAAE,KAAK;AACzC;;AAGA,SAAS,uBAAuB,OAAwB;CACtD,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,OAAO,UAAU,YAAY,CAAC,KAAK;EACzC,IAAI,QAAQ,MAAQ,SAAS,KAC3B,OAAO;CAEX;CACA,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore",
3
- "version": "0.0.7",
3
+ "version": "0.0.10",
4
4
  "description": "FastStore AI Native component library built on Base UI with AI-editable styles",
5
5
  "license": "MIT",
6
6
  "homepage": "https://developers.vtex.com/docs/guides/faststore",
@@ -50,12 +50,16 @@
50
50
  },
51
51
  "files": [
52
52
  "dist",
53
+ "skills",
53
54
  "src/styles/tailwind.css",
54
55
  "CHANGELOG.md"
55
56
  ],
56
57
  "dependencies": {
57
58
  "@base-ui/react": "^1.3.0",
58
59
  "@graphql-typed-document-node/core": "^3.2.0",
60
+ "@vtex/country-forms": "1.14.0",
61
+ "@vtex/faststore-catalog": "0.0.10",
62
+ "esbuild": "~0.27.3",
59
63
  "graphql": "^16.13.1",
60
64
  "react-hook-form": "^7.85.0",
61
65
  "react-intl": "^10.1.22",