@vtex/faststore 0.0.1

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 (538) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +95 -0
  4. package/dist/actions.json +334 -0
  5. package/dist/catalog.json +6615 -0
  6. package/dist/client.d.ts +17 -0
  7. package/dist/client.js +8 -0
  8. package/dist/components.d.ts +87 -0
  9. package/dist/components.js +87 -0
  10. package/dist/content-types.json +684 -0
  11. package/dist/core/dist/actions/mock-action.d.ts +24 -0
  12. package/dist/core/dist/actions/mock-action.js +28 -0
  13. package/dist/core/dist/actions/mock-action.js.map +1 -0
  14. package/dist/core/dist/actions/registry.d.ts +24 -0
  15. package/dist/core/dist/actions/registry.js +28 -0
  16. package/dist/core/dist/actions/registry.js.map +1 -0
  17. package/dist/core/dist/define-component.d.ts +100 -0
  18. package/dist/core/dist/define-component.js +8 -0
  19. package/dist/core/dist/define-component.js.map +1 -0
  20. package/dist/core/dist/define-content-type.d.ts +95 -0
  21. package/dist/core/dist/define-content-type.js +283 -0
  22. package/dist/core/dist/define-content-type.js.map +1 -0
  23. package/dist/core/dist/index.d.ts +7 -0
  24. package/dist/core/dist/index.js +5 -0
  25. package/dist/core/dist/schema/generated/schema.d.ts +28 -0
  26. package/dist/core/dist/types.d.ts +1 -0
  27. package/dist/docs/access-code-field.md +100 -0
  28. package/dist/docs/access-code-sign-in.md +174 -0
  29. package/dist/docs/account-entry-point.md +155 -0
  30. package/dist/docs/address-summary.md +50 -0
  31. package/dist/docs/buy-button.md +162 -0
  32. package/dist/docs/carousel.md +105 -0
  33. package/dist/docs/cart-item.md +162 -0
  34. package/dist/docs/cart-totalizer.md +197 -0
  35. package/dist/docs/cart.md +495 -0
  36. package/dist/docs/client-preferences.md +184 -0
  37. package/dist/docs/client-profile-form.md +192 -0
  38. package/dist/docs/client-profile.md +117 -0
  39. package/dist/docs/container.md +97 -0
  40. package/dist/docs/document-field.md +97 -0
  41. package/dist/docs/email-field.md +93 -0
  42. package/dist/docs/email-identification.md +102 -0
  43. package/dist/docs/footer-copyright.md +112 -0
  44. package/dist/docs/footer-link-group.md +162 -0
  45. package/dist/docs/footer-root.md +145 -0
  46. package/dist/docs/footer-social.md +151 -0
  47. package/dist/docs/free-shipping-progress.md +87 -0
  48. package/dist/docs/gallery.md +84 -0
  49. package/dist/docs/header-root.md +150 -0
  50. package/dist/docs/identity-edit.md +88 -0
  51. package/dist/docs/identity-summary.md +106 -0
  52. package/dist/docs/incentives.md +151 -0
  53. package/dist/docs/logo.md +135 -0
  54. package/dist/docs/meter.md +67 -0
  55. package/dist/docs/navigation-link-list.md +171 -0
  56. package/dist/docs/navigation-link.md +163 -0
  57. package/dist/docs/navigation-menu.md +264 -0
  58. package/dist/docs/payment-methods.md +139 -0
  59. package/dist/docs/phone-field.md +106 -0
  60. package/dist/docs/postal-code-field.md +126 -0
  61. package/dist/docs/pricing.md +499 -0
  62. package/dist/docs/product-gallery.md +409 -0
  63. package/dist/docs/product-information.md +295 -0
  64. package/dist/docs/product-list.md +170 -0
  65. package/dist/docs/product-quantity.md +88 -0
  66. package/dist/docs/product-shelf.md +141 -0
  67. package/dist/docs/promotion.md +109 -0
  68. package/dist/docs/region.md +225 -0
  69. package/dist/docs/session.md +123 -0
  70. package/dist/docs/shipping-address.md +390 -0
  71. package/dist/docs/shipping-simulator.md +147 -0
  72. package/dist/docs/sign-in-form.md +117 -0
  73. package/dist/docs/tabs.md +176 -0
  74. package/dist/docs/toast.md +124 -0
  75. package/dist/docs/variant-selector.md +450 -0
  76. package/dist/graphql/define-subgraph.d.ts +12 -0
  77. package/dist/graphql/define-subgraph.js +15 -0
  78. package/dist/graphql/define-subgraph.js.map +1 -0
  79. package/dist/graphql/gql.d.ts +10 -0
  80. package/dist/graphql/gql.js +16 -0
  81. package/dist/graphql/gql.js.map +1 -0
  82. package/dist/graphql/types.d.ts +88 -0
  83. package/dist/graphql.d.ts +4 -0
  84. package/dist/graphql.js +3 -0
  85. package/dist/index.d.ts +19 -0
  86. package/dist/index.js +5 -0
  87. package/dist/internal/client.d.ts +24 -0
  88. package/dist/internal/client.js +23 -0
  89. package/dist/internal/content.d.ts +2 -0
  90. package/dist/internal/content.js +2 -0
  91. package/dist/internal/server.d.ts +7 -0
  92. package/dist/internal/server.js +6 -0
  93. package/dist/matter/access-code-sign-in/access-code-sign-in.d.ts +111 -0
  94. package/dist/matter/access-code-sign-in/access-code-sign-in.js +387 -0
  95. package/dist/matter/access-code-sign-in/access-code-sign-in.js.map +1 -0
  96. package/dist/matter/account-entry-point/account-entry-point.d.ts +64 -0
  97. package/dist/matter/account-entry-point/account-entry-point.js +151 -0
  98. package/dist/matter/account-entry-point/account-entry-point.js.map +1 -0
  99. package/dist/matter/breadcrumb/breadcrumb.d.ts +40 -0
  100. package/dist/matter/breadcrumb/breadcrumb.js +155 -0
  101. package/dist/matter/breadcrumb/breadcrumb.js.map +1 -0
  102. package/dist/matter/buy-button/buy-button.d.ts +95 -0
  103. package/dist/matter/buy-button/buy-button.js +259 -0
  104. package/dist/matter/buy-button/buy-button.js.map +1 -0
  105. package/dist/matter/cart/cart-namespace.d.ts +48 -0
  106. package/dist/matter/cart/cart-namespace.js +50 -0
  107. package/dist/matter/cart/cart-namespace.js.map +1 -0
  108. package/dist/matter/cart/cart.d.ts +312 -0
  109. package/dist/matter/cart/cart.js +1034 -0
  110. package/dist/matter/cart/cart.js.map +1 -0
  111. package/dist/matter/cart-item/cart-item.d.ts +103 -0
  112. package/dist/matter/cart-item/cart-item.js +672 -0
  113. package/dist/matter/cart-item/cart-item.js.map +1 -0
  114. package/dist/matter/cart-item-compositions/cart-item-compositions.d.ts +49 -0
  115. package/dist/matter/cart-item-compositions/cart-item-compositions.js +165 -0
  116. package/dist/matter/cart-item-compositions/cart-item-compositions.js.map +1 -0
  117. package/dist/matter/cart-item-customizations/cart-item-customizations.d.ts +28 -0
  118. package/dist/matter/cart-item-customizations/cart-item-customizations.js +73 -0
  119. package/dist/matter/cart-item-customizations/cart-item-customizations.js.map +1 -0
  120. package/dist/matter/cart-item-discounts/cart-item-discounts.d.ts +33 -0
  121. package/dist/matter/cart-item-discounts/cart-item-discounts.js +70 -0
  122. package/dist/matter/cart-item-discounts/cart-item-discounts.js.map +1 -0
  123. package/dist/matter/cart-item-seller-info/cart-item-seller-info.d.ts +24 -0
  124. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js +54 -0
  125. package/dist/matter/cart-item-seller-info/cart-item-seller-info.js.map +1 -0
  126. package/dist/matter/cart-item-variations/cart-item-variations.d.ts +27 -0
  127. package/dist/matter/cart-item-variations/cart-item-variations.js +69 -0
  128. package/dist/matter/cart-item-variations/cart-item-variations.js.map +1 -0
  129. package/dist/matter/cart-totalizer/cart-totalizer.d.ts +78 -0
  130. package/dist/matter/cart-totalizer/cart-totalizer.js +220 -0
  131. package/dist/matter/cart-totalizer/cart-totalizer.js.map +1 -0
  132. package/dist/matter/client-preferences/client-preferences.d.ts +50 -0
  133. package/dist/matter/client-preferences/client-preferences.js +206 -0
  134. package/dist/matter/client-preferences/client-preferences.js.map +1 -0
  135. package/dist/matter/client-profile/client-profile.d.ts +59 -0
  136. package/dist/matter/client-profile/client-profile.js +185 -0
  137. package/dist/matter/client-profile/client-profile.js.map +1 -0
  138. package/dist/matter/client-profile-form/client-profile-form.d.ts +126 -0
  139. package/dist/matter/client-profile-form/client-profile-form.js +660 -0
  140. package/dist/matter/client-profile-form/client-profile-form.js.map +1 -0
  141. package/dist/matter/delivery-options/delivery-options-accordion.d.ts +30 -0
  142. package/dist/matter/delivery-options/delivery-options-accordion.js +189 -0
  143. package/dist/matter/delivery-options/delivery-options-accordion.js.map +1 -0
  144. package/dist/matter/delivery-options/delivery-options-controller.d.ts +49 -0
  145. package/dist/matter/delivery-options/delivery-options-controller.js +203 -0
  146. package/dist/matter/delivery-options/delivery-options-controller.js.map +1 -0
  147. package/dist/matter/delivery-options/delivery-options.d.ts +31 -0
  148. package/dist/matter/delivery-options/delivery-options.js +103 -0
  149. package/dist/matter/delivery-options/delivery-options.js.map +1 -0
  150. package/dist/matter/delivery-options/use-delivery-option-selection.d.ts +9 -0
  151. package/dist/matter/delivery-options/use-delivery-option-selection.js +76 -0
  152. package/dist/matter/delivery-options/use-delivery-option-selection.js.map +1 -0
  153. package/dist/matter/email-identification/email-identification.d.ts +37 -0
  154. package/dist/matter/email-identification/email-identification.js +111 -0
  155. package/dist/matter/email-identification/email-identification.js.map +1 -0
  156. package/dist/matter/free-shipping-progress/free-shipping-progress.d.ts +44 -0
  157. package/dist/matter/free-shipping-progress/free-shipping-progress.js +170 -0
  158. package/dist/matter/free-shipping-progress/free-shipping-progress.js.map +1 -0
  159. package/dist/matter/identity-edit/identity-edit.d.ts +52 -0
  160. package/dist/matter/identity-edit/identity-edit.js +148 -0
  161. package/dist/matter/identity-edit/identity-edit.js.map +1 -0
  162. package/dist/matter/identity-summary/identity-summary.d.ts +128 -0
  163. package/dist/matter/identity-summary/identity-summary.js +344 -0
  164. package/dist/matter/identity-summary/identity-summary.js.map +1 -0
  165. package/dist/matter/pricing/pricing.d.ts +162 -0
  166. package/dist/matter/pricing/pricing.js +793 -0
  167. package/dist/matter/pricing/pricing.js.map +1 -0
  168. package/dist/matter/product-gallery/product-gallery.d.ts +23 -0
  169. package/dist/matter/product-gallery/product-gallery.js +188 -0
  170. package/dist/matter/product-gallery/product-gallery.js.map +1 -0
  171. package/dist/matter/product-information/product-information.d.ts +61 -0
  172. package/dist/matter/product-information/product-information.js +355 -0
  173. package/dist/matter/product-information/product-information.js.map +1 -0
  174. package/dist/matter/product-list/product-list.d.ts +86 -0
  175. package/dist/matter/product-list/product-list.js +342 -0
  176. package/dist/matter/product-list/product-list.js.map +1 -0
  177. package/dist/matter/product-quantity/product-quantity.d.ts +50 -0
  178. package/dist/matter/product-quantity/product-quantity.js +111 -0
  179. package/dist/matter/product-quantity/product-quantity.js.map +1 -0
  180. package/dist/matter/product-shelf/product-shelf.d.ts +125 -0
  181. package/dist/matter/product-shelf/product-shelf.js +376 -0
  182. package/dist/matter/product-shelf/product-shelf.js.map +1 -0
  183. package/dist/matter/region/region.d.ts +211 -0
  184. package/dist/matter/region/region.js +579 -0
  185. package/dist/matter/region/region.js.map +1 -0
  186. package/dist/matter/session/session.d.ts +58 -0
  187. package/dist/matter/session/session.js +112 -0
  188. package/dist/matter/session/session.js.map +1 -0
  189. package/dist/matter/shipping-address/country-descriptors.js +101 -0
  190. package/dist/matter/shipping-address/country-descriptors.js.map +1 -0
  191. package/dist/matter/shipping-address/shipping-address.d.ts +284 -0
  192. package/dist/matter/shipping-address/shipping-address.js +1036 -0
  193. package/dist/matter/shipping-address/shipping-address.js.map +1 -0
  194. package/dist/matter/shipping-simulator/shipping-simulator.d.ts +143 -0
  195. package/dist/matter/shipping-simulator/shipping-simulator.js +644 -0
  196. package/dist/matter/shipping-simulator/shipping-simulator.js.map +1 -0
  197. package/dist/matter/sign-in-form/sign-in-form.d.ts +79 -0
  198. package/dist/matter/sign-in-form/sign-in-form.js +226 -0
  199. package/dist/matter/sign-in-form/sign-in-form.js.map +1 -0
  200. package/dist/matter/variant-selector/variant-selector.d.ts +183 -0
  201. package/dist/matter/variant-selector/variant-selector.js +840 -0
  202. package/dist/matter/variant-selector/variant-selector.js.map +1 -0
  203. package/dist/message-locales.json +7 -0
  204. package/dist/particles/access-code-field/access-code-field.d.ts +33 -0
  205. package/dist/particles/access-code-field/access-code-field.js +95 -0
  206. package/dist/particles/access-code-field/access-code-field.js.map +1 -0
  207. package/dist/particles/accordion/accordion.d.ts +45 -0
  208. package/dist/particles/accordion/accordion.js +156 -0
  209. package/dist/particles/accordion/accordion.js.map +1 -0
  210. package/dist/particles/address-summary/address-summary.d.ts +50 -0
  211. package/dist/particles/address-summary/address-summary.js +129 -0
  212. package/dist/particles/address-summary/address-summary.js.map +1 -0
  213. package/dist/particles/badge/badge.d.ts +10 -0
  214. package/dist/particles/badge/badge.js +27 -0
  215. package/dist/particles/badge/badge.js.map +1 -0
  216. package/dist/particles/button/button.d.ts +18 -0
  217. package/dist/particles/button/button.js +37 -0
  218. package/dist/particles/button/button.js.map +1 -0
  219. package/dist/particles/carousel/carousel.d.ts +60 -0
  220. package/dist/particles/carousel/carousel.js +335 -0
  221. package/dist/particles/carousel/carousel.js.map +1 -0
  222. package/dist/particles/checkbox/checkbox.d.ts +40 -0
  223. package/dist/particles/checkbox/checkbox.js +82 -0
  224. package/dist/particles/checkbox/checkbox.js.map +1 -0
  225. package/dist/particles/container/container.d.ts +20 -0
  226. package/dist/particles/container/container.js +36 -0
  227. package/dist/particles/container/container.js.map +1 -0
  228. package/dist/particles/dialog/dialog.d.ts +54 -0
  229. package/dist/particles/dialog/dialog.js +192 -0
  230. package/dist/particles/dialog/dialog.js.map +1 -0
  231. package/dist/particles/document-field/document-field.d.ts +61 -0
  232. package/dist/particles/document-field/document-field.js +146 -0
  233. package/dist/particles/document-field/document-field.js.map +1 -0
  234. package/dist/particles/drawer/drawer.d.ts +52 -0
  235. package/dist/particles/drawer/drawer.js +183 -0
  236. package/dist/particles/drawer/drawer.js.map +1 -0
  237. package/dist/particles/email-field/email-field.d.ts +37 -0
  238. package/dist/particles/email-field/email-field.js +106 -0
  239. package/dist/particles/email-field/email-field.js.map +1 -0
  240. package/dist/particles/field/field.d.ts +50 -0
  241. package/dist/particles/field/field.js +133 -0
  242. package/dist/particles/field/field.js.map +1 -0
  243. package/dist/particles/fieldset/fieldset.d.ts +16 -0
  244. package/dist/particles/fieldset/fieldset.js +52 -0
  245. package/dist/particles/fieldset/fieldset.js.map +1 -0
  246. package/dist/particles/footer-copyright/footer-copyright.d.ts +32 -0
  247. package/dist/particles/footer-copyright/footer-copyright.js +50 -0
  248. package/dist/particles/footer-copyright/footer-copyright.js.map +1 -0
  249. package/dist/particles/footer-link-group/footer-link-group.d.ts +66 -0
  250. package/dist/particles/footer-link-group/footer-link-group.js +154 -0
  251. package/dist/particles/footer-link-group/footer-link-group.js.map +1 -0
  252. package/dist/particles/footer-root/footer-root.d.ts +21 -0
  253. package/dist/particles/footer-root/footer-root.js +38 -0
  254. package/dist/particles/footer-root/footer-root.js.map +1 -0
  255. package/dist/particles/footer-social/footer-social.d.ts +79 -0
  256. package/dist/particles/footer-social/footer-social.js +176 -0
  257. package/dist/particles/footer-social/footer-social.js.map +1 -0
  258. package/dist/particles/gallery/gallery.d.ts +181 -0
  259. package/dist/particles/gallery/gallery.js +920 -0
  260. package/dist/particles/gallery/gallery.js.map +1 -0
  261. package/dist/particles/header-root/header-root.d.ts +21 -0
  262. package/dist/particles/header-root/header-root.js +38 -0
  263. package/dist/particles/header-root/header-root.js.map +1 -0
  264. package/dist/particles/icon/icon.d.ts +22 -0
  265. package/dist/particles/icon/icon.js +48 -0
  266. package/dist/particles/icon/icon.js.map +1 -0
  267. package/dist/particles/image/image.d.ts +13 -0
  268. package/dist/particles/image/image.js +59 -0
  269. package/dist/particles/image/image.js.map +1 -0
  270. package/dist/particles/incentives/incentives.d.ts +85 -0
  271. package/dist/particles/incentives/incentives.js +200 -0
  272. package/dist/particles/incentives/incentives.js.map +1 -0
  273. package/dist/particles/input/input.d.ts +9 -0
  274. package/dist/particles/input/input.js +28 -0
  275. package/dist/particles/input/input.js.map +1 -0
  276. package/dist/particles/logo/logo.d.ts +55 -0
  277. package/dist/particles/logo/logo.js +96 -0
  278. package/dist/particles/logo/logo.js.map +1 -0
  279. package/dist/particles/menu/menu.d.ts +103 -0
  280. package/dist/particles/menu/menu.js +409 -0
  281. package/dist/particles/menu/menu.js.map +1 -0
  282. package/dist/particles/menubar/menubar.d.ts +18 -0
  283. package/dist/particles/menubar/menubar.js +42 -0
  284. package/dist/particles/menubar/menubar.js.map +1 -0
  285. package/dist/particles/meter/meter.d.ts +36 -0
  286. package/dist/particles/meter/meter.js +132 -0
  287. package/dist/particles/meter/meter.js.map +1 -0
  288. package/dist/particles/navigation-link/navigation-link.d.ts +43 -0
  289. package/dist/particles/navigation-link/navigation-link.js +82 -0
  290. package/dist/particles/navigation-link/navigation-link.js.map +1 -0
  291. package/dist/particles/navigation-link-list/navigation-link-list.d.ts +59 -0
  292. package/dist/particles/navigation-link-list/navigation-link-list.js +103 -0
  293. package/dist/particles/navigation-link-list/navigation-link-list.js.map +1 -0
  294. package/dist/particles/navigation-menu/navigation-menu.d.ts +78 -0
  295. package/dist/particles/navigation-menu/navigation-menu.js +295 -0
  296. package/dist/particles/navigation-menu/navigation-menu.js.map +1 -0
  297. package/dist/particles/number-field/number-field.d.ts +46 -0
  298. package/dist/particles/number-field/number-field.js +169 -0
  299. package/dist/particles/number-field/number-field.js.map +1 -0
  300. package/dist/particles/password-field/password-field.d.ts +31 -0
  301. package/dist/particles/password-field/password-field.js +109 -0
  302. package/dist/particles/password-field/password-field.js.map +1 -0
  303. package/dist/particles/payment-methods/payment-methods.d.ts +72 -0
  304. package/dist/particles/payment-methods/payment-methods.js +151 -0
  305. package/dist/particles/payment-methods/payment-methods.js.map +1 -0
  306. package/dist/particles/phone-field/phone-field.d.ts +67 -0
  307. package/dist/particles/phone-field/phone-field.js +250 -0
  308. package/dist/particles/phone-field/phone-field.js.map +1 -0
  309. package/dist/particles/popover/popover.d.ts +68 -0
  310. package/dist/particles/popover/popover.js +284 -0
  311. package/dist/particles/popover/popover.js.map +1 -0
  312. package/dist/particles/postal-code-field/postal-code-field.d.ts +75 -0
  313. package/dist/particles/postal-code-field/postal-code-field.js +169 -0
  314. package/dist/particles/postal-code-field/postal-code-field.js.map +1 -0
  315. package/dist/particles/promotion/promotion.d.ts +46 -0
  316. package/dist/particles/promotion/promotion.js +78 -0
  317. package/dist/particles/promotion/promotion.js.map +1 -0
  318. package/dist/particles/quantity-selector/quantity-selector.d.ts +30 -0
  319. package/dist/particles/quantity-selector/quantity-selector.js +116 -0
  320. package/dist/particles/quantity-selector/quantity-selector.js.map +1 -0
  321. package/dist/particles/radio/radio.d.ts +36 -0
  322. package/dist/particles/radio/radio.js +76 -0
  323. package/dist/particles/radio/radio.js.map +1 -0
  324. package/dist/particles/scroll-area/scroll-area.d.ts +36 -0
  325. package/dist/particles/scroll-area/scroll-area.js +145 -0
  326. package/dist/particles/scroll-area/scroll-area.js.map +1 -0
  327. package/dist/particles/select/select.d.ts +125 -0
  328. package/dist/particles/select/select.js +478 -0
  329. package/dist/particles/select/select.js.map +1 -0
  330. package/dist/particles/separator/separator.d.ts +12 -0
  331. package/dist/particles/separator/separator.js +33 -0
  332. package/dist/particles/separator/separator.js.map +1 -0
  333. package/dist/particles/shared/input-mask.d.ts +5 -0
  334. package/dist/particles/shared/input-mask.js +58 -0
  335. package/dist/particles/shared/input-mask.js.map +1 -0
  336. package/dist/particles/spinner/spinner.d.ts +13 -0
  337. package/dist/particles/spinner/spinner.js +31 -0
  338. package/dist/particles/spinner/spinner.js.map +1 -0
  339. package/dist/particles/switch/switch.d.ts +27 -0
  340. package/dist/particles/switch/switch.js +59 -0
  341. package/dist/particles/switch/switch.js.map +1 -0
  342. package/dist/particles/tabs/tabs.d.ts +45 -0
  343. package/dist/particles/tabs/tabs.js +164 -0
  344. package/dist/particles/tabs/tabs.js.map +1 -0
  345. package/dist/particles/text/text.d.ts +24 -0
  346. package/dist/particles/text/text.js +40 -0
  347. package/dist/particles/text/text.js.map +1 -0
  348. package/dist/particles/toast/toast.d.ts +83 -0
  349. package/dist/particles/toast/toast.js +194 -0
  350. package/dist/particles/toast/toast.js.map +1 -0
  351. package/dist/particles/toggle/toggle.d.ts +26 -0
  352. package/dist/particles/toggle/toggle.js +61 -0
  353. package/dist/particles/toggle/toggle.js.map +1 -0
  354. package/dist/particles/tooltip/tooltip.d.ts +61 -0
  355. package/dist/particles/tooltip/tooltip.js +240 -0
  356. package/dist/particles/tooltip/tooltip.js.map +1 -0
  357. package/dist/schema.graphql +2953 -0
  358. package/dist/sdk/actions/cart-action-provider.d.ts +19 -0
  359. package/dist/sdk/actions/cart-action-provider.js +23 -0
  360. package/dist/sdk/actions/cart-action-provider.js.map +1 -0
  361. package/dist/sdk/actions/identity-action-provider.d.ts +15 -0
  362. package/dist/sdk/actions/identity-action-provider.js +19 -0
  363. package/dist/sdk/actions/identity-action-provider.js.map +1 -0
  364. package/dist/sdk/actions/index.d.ts +7 -0
  365. package/dist/sdk/actions/index.js +6 -0
  366. package/dist/sdk/actions/inject-actions.d.ts +14 -0
  367. package/dist/sdk/actions/inject-actions.js +36 -0
  368. package/dist/sdk/actions/inject-actions.js.map +1 -0
  369. package/dist/sdk/actions/region-action-provider.d.ts +15 -0
  370. package/dist/sdk/actions/region-action-provider.js +19 -0
  371. package/dist/sdk/actions/region-action-provider.js.map +1 -0
  372. package/dist/sdk/actions/session-action-provider.d.ts +15 -0
  373. package/dist/sdk/actions/session-action-provider.js +19 -0
  374. package/dist/sdk/actions/session-action-provider.js.map +1 -0
  375. package/dist/sdk/actions/shipping-action-provider.d.ts +15 -0
  376. package/dist/sdk/actions/shipping-action-provider.js +19 -0
  377. package/dist/sdk/actions/shipping-action-provider.js.map +1 -0
  378. package/dist/sdk/actions/types.d.ts +21 -0
  379. package/dist/sdk/cache/storefront-cache.js +35 -0
  380. package/dist/sdk/cache/storefront-cache.js.map +1 -0
  381. package/dist/sdk/cart/operations.d.ts +31 -0
  382. package/dist/sdk/cart/operations.js +215 -0
  383. package/dist/sdk/cart/operations.js.map +1 -0
  384. package/dist/sdk/cart/optimistic.d.ts +24 -0
  385. package/dist/sdk/cart/optimistic.js +164 -0
  386. package/dist/sdk/cart/optimistic.js.map +1 -0
  387. package/dist/sdk/cart/use-cart-actions.d.ts +56 -0
  388. package/dist/sdk/cart/use-cart-actions.js +348 -0
  389. package/dist/sdk/cart/use-cart-actions.js.map +1 -0
  390. package/dist/sdk/cart/use-cart-validate-on-open.js +50 -0
  391. package/dist/sdk/cart/use-cart-validate-on-open.js.map +1 -0
  392. package/dist/sdk/cart/write-gate.js +54 -0
  393. package/dist/sdk/cart/write-gate.js.map +1 -0
  394. package/dist/sdk/client/assert-api-url.js +20 -0
  395. package/dist/sdk/client/assert-api-url.js.map +1 -0
  396. package/dist/sdk/client/create-client.d.ts +23 -0
  397. package/dist/sdk/client/create-client.js +46 -0
  398. package/dist/sdk/client/create-client.js.map +1 -0
  399. package/dist/sdk/client/fetch-page-data.d.ts +39 -0
  400. package/dist/sdk/client/fetch-page-data.js +33 -0
  401. package/dist/sdk/client/fetch-page-data.js.map +1 -0
  402. package/dist/sdk/client/register-preload-query.d.ts +24 -0
  403. package/dist/sdk/client/register-preload-query.js +33 -0
  404. package/dist/sdk/client/register-preload-query.js.map +1 -0
  405. package/dist/sdk/content/create-content-runtime.d.ts +68 -0
  406. package/dist/sdk/content/create-content-runtime.js +503 -0
  407. package/dist/sdk/content/create-content-runtime.js.map +1 -0
  408. package/dist/sdk/context/headers.d.ts +15 -0
  409. package/dist/sdk/context/headers.js +21 -0
  410. package/dist/sdk/context/headers.js.map +1 -0
  411. package/dist/sdk/context/storefront-context.d.ts +11 -0
  412. package/dist/sdk/context/storefront-context.js +29 -0
  413. package/dist/sdk/context/storefront-context.js.map +1 -0
  414. package/dist/sdk/data/data-override-context.d.ts +12 -0
  415. package/dist/sdk/data/data-override-context.js +19 -0
  416. package/dist/sdk/data/data-override-context.js.map +1 -0
  417. package/dist/sdk/data/entity-subscriber.js +28 -0
  418. package/dist/sdk/data/entity-subscriber.js.map +1 -0
  419. package/dist/sdk/data/hot-data-provider.d.ts +19 -0
  420. package/dist/sdk/data/hot-data-provider.js +33 -0
  421. package/dist/sdk/data/hot-data-provider.js.map +1 -0
  422. package/dist/sdk/data/index.d.ts +8 -0
  423. package/dist/sdk/data/index.js +8 -0
  424. package/dist/sdk/data/list-item-ref-context.d.ts +20 -0
  425. package/dist/sdk/data/list-item-ref-context.js +11 -0
  426. package/dist/sdk/data/list-item-ref-context.js.map +1 -0
  427. package/dist/sdk/data/multiple-reactive-data-provider.d.ts +32 -0
  428. package/dist/sdk/data/multiple-reactive-data-provider.js +20 -0
  429. package/dist/sdk/data/multiple-reactive-data-provider.js.map +1 -0
  430. package/dist/sdk/data/page-reactive-data-root.d.ts +53 -0
  431. package/dist/sdk/data/page-reactive-data-root.js +153 -0
  432. package/dist/sdk/data/page-reactive-data-root.js.map +1 -0
  433. package/dist/sdk/data/reactive-data-provider.d.ts +25 -0
  434. package/dist/sdk/data/reactive-data-provider.js +24 -0
  435. package/dist/sdk/data/reactive-data-provider.js.map +1 -0
  436. package/dist/sdk/data/reactive-list-item-data-provider.d.ts +26 -0
  437. package/dist/sdk/data/reactive-list-item-data-provider.js +42 -0
  438. package/dist/sdk/data/reactive-list-item-data-provider.js.map +1 -0
  439. package/dist/sdk/data/use-reactive-entity.js +40 -0
  440. package/dist/sdk/data/use-reactive-entity.js.map +1 -0
  441. package/dist/sdk/format/client.d.ts +12 -0
  442. package/dist/sdk/format/client.js +20 -0
  443. package/dist/sdk/format/client.js.map +1 -0
  444. package/dist/sdk/format/formatters.d.ts +32 -0
  445. package/dist/sdk/format/formatters.js +45 -0
  446. package/dist/sdk/format/formatters.js.map +1 -0
  447. package/dist/sdk/generated/fragment-types.js +23 -0
  448. package/dist/sdk/generated/fragment-types.js.map +1 -0
  449. package/dist/sdk/generated/gql.js +51 -0
  450. package/dist/sdk/generated/gql.js.map +1 -0
  451. package/dist/sdk/generated/graphql.d.ts +622 -0
  452. package/dist/sdk/generated/graphql.js +11917 -0
  453. package/dist/sdk/generated/graphql.js.map +1 -0
  454. package/dist/sdk/graphql-tag.d.ts +10 -0
  455. package/dist/sdk/graphql-tag.js +21 -0
  456. package/dist/sdk/graphql-tag.js.map +1 -0
  457. package/dist/sdk/i18n/client.d.ts +4 -0
  458. package/dist/sdk/i18n/client.js +4 -0
  459. package/dist/sdk/i18n/locales.d.ts +8 -0
  460. package/dist/sdk/i18n/locales.js +57 -0
  461. package/dist/sdk/i18n/locales.js.map +1 -0
  462. package/dist/sdk/i18n/messages/en-US.js +24 -0
  463. package/dist/sdk/i18n/messages/en-US.js.map +1 -0
  464. package/dist/sdk/i18n/messages/en-US.json +19 -0
  465. package/dist/sdk/i18n/messages/en-US.json.d.ts +23 -0
  466. package/dist/sdk/i18n/messages/es-ES.js +24 -0
  467. package/dist/sdk/i18n/messages/es-ES.js.map +1 -0
  468. package/dist/sdk/i18n/messages/es-ES.json +19 -0
  469. package/dist/sdk/i18n/messages/pt-BR.js +24 -0
  470. package/dist/sdk/i18n/messages/pt-BR.js.map +1 -0
  471. package/dist/sdk/i18n/messages/pt-BR.json +19 -0
  472. package/dist/sdk/i18n/provider.d.ts +1 -0
  473. package/dist/sdk/i18n/provider.js +30 -0
  474. package/dist/sdk/i18n/provider.js.map +1 -0
  475. package/dist/sdk/i18n/server.d.ts +28 -0
  476. package/dist/sdk/i18n/server.js +59 -0
  477. package/dist/sdk/i18n/server.js.map +1 -0
  478. package/dist/sdk/identity/operations.d.ts +34 -0
  479. package/dist/sdk/identity/operations.js +78 -0
  480. package/dist/sdk/identity/operations.js.map +1 -0
  481. package/dist/sdk/identity/use-identity-actions.d.ts +62 -0
  482. package/dist/sdk/identity/use-identity-actions.js +180 -0
  483. package/dist/sdk/identity/use-identity-actions.js.map +1 -0
  484. package/dist/sdk/provider/index.d.ts +2 -0
  485. package/dist/sdk/provider/index.js +2 -0
  486. package/dist/sdk/provider/storefront-provider.d.ts +32 -0
  487. package/dist/sdk/provider/storefront-provider.js +111 -0
  488. package/dist/sdk/provider/storefront-provider.js.map +1 -0
  489. package/dist/sdk/region/operations.d.ts +6 -0
  490. package/dist/sdk/region/region-operations.d.ts +30 -0
  491. package/dist/sdk/region/region-operations.js +23 -0
  492. package/dist/sdk/region/region-operations.js.map +1 -0
  493. package/dist/sdk/region/use-region-actions.d.ts +23 -0
  494. package/dist/sdk/region/use-region-actions.js +66 -0
  495. package/dist/sdk/region/use-region-actions.js.map +1 -0
  496. package/dist/sdk/seller.js +11 -0
  497. package/dist/sdk/seller.js.map +1 -0
  498. package/dist/sdk/session/auth-operations.d.ts +47 -0
  499. package/dist/sdk/session/auth-operations.js +79 -0
  500. package/dist/sdk/session/auth-operations.js.map +1 -0
  501. package/dist/sdk/session/operations.d.ts +6 -0
  502. package/dist/sdk/session/use-session-actions.d.ts +27 -0
  503. package/dist/sdk/session/use-session-actions.js +126 -0
  504. package/dist/sdk/session/use-session-actions.js.map +1 -0
  505. package/dist/sdk/shipping/cart-operations.d.ts +3 -0
  506. package/dist/sdk/shipping/cart-operations.js +33 -0
  507. package/dist/sdk/shipping/cart-operations.js.map +1 -0
  508. package/dist/sdk/shipping/operations.d.ts +3 -0
  509. package/dist/sdk/shipping/operations.js +33 -0
  510. package/dist/sdk/shipping/operations.js.map +1 -0
  511. package/dist/sdk/shipping/option-select-operations.d.ts +24 -0
  512. package/dist/sdk/shipping/option-select-operations.js +45 -0
  513. package/dist/sdk/shipping/option-select-operations.js.map +1 -0
  514. package/dist/sdk/shipping/request-timeout.js +41 -0
  515. package/dist/sdk/shipping/request-timeout.js.map +1 -0
  516. package/dist/sdk/shipping/shipping-operations.d.ts +38 -0
  517. package/dist/sdk/shipping/shipping-operations.js +77 -0
  518. package/dist/sdk/shipping/shipping-operations.js.map +1 -0
  519. package/dist/sdk/shipping/use-cart-shipping-simulation.d.ts +7 -0
  520. package/dist/sdk/shipping/use-cart-shipping-simulation.js +72 -0
  521. package/dist/sdk/shipping/use-cart-shipping-simulation.js.map +1 -0
  522. package/dist/sdk/shipping/use-shipping-actions.d.ts +27 -0
  523. package/dist/sdk/shipping/use-shipping-actions.js +113 -0
  524. package/dist/sdk/shipping/use-shipping-actions.js.map +1 -0
  525. package/dist/sdk/shipping/use-shipping-simulation.d.ts +7 -0
  526. package/dist/sdk/shipping/use-shipping-simulation.js +72 -0
  527. package/dist/sdk/shipping/use-shipping-simulation.js.map +1 -0
  528. package/dist/sdk/state/cart.d.ts +42 -0
  529. package/dist/sdk/state/cart.js +64 -0
  530. package/dist/sdk/state/cart.js.map +1 -0
  531. package/dist/sdk/state/index.js +3 -0
  532. package/dist/sdk/state/variant-selector.d.ts +17 -0
  533. package/dist/sdk/state/variant-selector.js +14 -0
  534. package/dist/sdk/state/variant-selector.js.map +1 -0
  535. package/dist/utils/safe-href.js +63 -0
  536. package/dist/utils/safe-href.js.map +1 -0
  537. package/package.json +84 -0
  538. package/src/styles/tailwind.css +32 -0
@@ -0,0 +1,503 @@
1
+ import { cache } from "react";
2
+ import { createHmac, timingSafeEqual } from "node:crypto";
3
+ import { cookies, draftMode } from "next/headers";
4
+ import { connection } from "next/server";
5
+ //#region src/sdk/content/create-content-runtime.tsx
6
+ const ENTRY_REQUEST_TIMEOUT_MS = 5e3;
7
+ /**
8
+ * Retention ceilings for the last-good store, both estimated rather than measured: no production
9
+ * store exists yet to size a real composite against, and the example schemas in this repo are demo
10
+ * content, not authored pages, so neither is evidence of real scale.
11
+ *
12
+ * `MAX_RETAINED_BLOB_BYTES` bounds one entry. Ordinary editorial text (a title, a body, an image URL,
13
+ * an alt text) stays in the hundreds of bytes to a few kilobytes per element regardless of how many
14
+ * elements a page composes — even the largest composed layout in this repo (103 elements) does not
15
+ * read as megabytes if every element stays plain text. The realistic way to exceed this is a single
16
+ * field holding embedded binary — a base64 image pasted into a text field instead of uploaded through
17
+ * the media widget — which is exactly the shape this guards against, independent of element count.
18
+ *
19
+ * `MAX_RETAINED_TOTAL_BYTES` bounds the whole store, and is the one that actually matters: the
20
+ * per-blob cap alone does not bound total memory, because it multiplies by key count, and key count is
21
+ * not small — a large store's pages and layouts, times its locales, is plausibly a few hundred keys.
22
+ * A few hundred keys at a few megabytes each already exceeds a typical serverless heap (512 MB–1 GB)
23
+ * on the per-blob cap alone; ~64 MB is a small slice of that heap while still holding many ordinary
24
+ * pages at once.
25
+ *
26
+ * Both numbers count serialized JSON text (`blobByteLength`), not retained heap: a parsed object
27
+ * typically costs more than its JSON text — V8 pays per-property and per-string object overhead that
28
+ * the text itself does not — so the real footprint at either ceiling is larger than the number on the
29
+ * tin, plausibly by a small multiple. Both ceilings still leave headroom against a 512 MB–1 GB heap at
30
+ * that multiple; sizing them as retained heap instead would need a runtime memory measurement this
31
+ * module has no cheap way to take.
32
+ *
33
+ * Both numbers are round and generous on purpose, not derived. `content.retention.skipped` below is
34
+ * the real calibration path: once a production store exists, its log volume says whether either
35
+ * ceiling needs to move.
36
+ */
37
+ const MAX_RETAINED_BLOB_BYTES = 1e6;
38
+ const MAX_RETAINED_TOTAL_BYTES = 64e6;
39
+ /** Server-only preview credential, supplied at deployment time; never reaches the browser. */
40
+ const PREVIEW_TOKEN_ENV = "CONTENT_PLATFORM_PREVIEW_TOKEN";
41
+ /** Shared broker secret used to verify the signed preview context cookie. */
42
+ const PREVIEW_SECRET_ENV = "CONTENT_PREVIEW_SECRET";
43
+ /** The signed preview context cookie the Draft Mode route sets. */
44
+ const PREVIEW_COOKIE = "__fs_content_preview";
45
+ /**
46
+ * Creates the one server-side content read surface for a store: a `React.cache`-deduped
47
+ * `readContentSlices` the generated page or layout awaits once at the top, and the
48
+ * `ContentEntryBoundary` the compiler wraps around each content-backed element. One read per scope
49
+ * yields every element's `$content` value keyed by `element.id`, so a page issues at most two Data
50
+ * Plane reads (its own entry plus its layout's) regardless of content-backed component count. Draft
51
+ * Mode switches the same read to Control Plane's preview endpoint through a server-only credential.
52
+ */
53
+ function createContentRuntime(config) {
54
+ const lastGood = /* @__PURE__ */ new Map();
55
+ let retainedBytes = 0;
56
+ /**
57
+ * Whether a successful read's blob replaces what `key` already holds, weighed against both
58
+ * ceilings. Skipping never deletes: whatever `key` held before, if anything, is left exactly as it
59
+ * was — only the update is declined, so a rare oversized read cannot erase a smaller last-good value
60
+ * that a future failure could still use.
61
+ */
62
+ function retainBlob(key, blob, fields) {
63
+ const size = blobByteLength(blob);
64
+ if (size > MAX_RETAINED_BLOB_BYTES) {
65
+ logEvent("warn", "content.retention.skipped", {
66
+ ...fields,
67
+ bytes: size,
68
+ reason: "blob-too-large"
69
+ });
70
+ return;
71
+ }
72
+ const existing = lastGood.get(key);
73
+ const existingSize = existing ? blobByteLength(existing) : 0;
74
+ if (retainedBytes - existingSize + size > MAX_RETAINED_TOTAL_BYTES) {
75
+ logEvent("warn", "content.retention.skipped", {
76
+ ...fields,
77
+ bytes: size,
78
+ reason: "total-cap-reached"
79
+ });
80
+ return;
81
+ }
82
+ lastGood.set(key, blob);
83
+ retainedBytes += size - existingSize;
84
+ }
85
+ /**
86
+ * The published read plus the fallback that covers it. The upstream is always called and the store
87
+ * is read only in the `catch`, which is what makes this a fallback and not a cache: a publish is
88
+ * visible on the very next request. A success ordinarily overwrites the entry (see `retainBlob` for
89
+ * the two cases where it does not), a `not-found` leaves it alone so unpublishing still unpublishes,
90
+ * and nothing is ever removed or expired by age.
91
+ *
92
+ * Failure is structural — whatever leaves `readPublishedEntry` as a throw — rather than a status
93
+ * table, so a 403 or a 429 serves the stored blob, and a failure mode added there later is covered
94
+ * without touching this.
95
+ */
96
+ async function readPublished(contentTypeId, entryId, locale) {
97
+ const key = `${contentTypeId}\u0000${entryId}\u0000${locale}`;
98
+ try {
99
+ const result = await readPublishedEntry(config.account, config.storeId, locale, contentTypeId, entryId);
100
+ if (result.status === "found") retainBlob(key, result.blob, {
101
+ contentTypeId,
102
+ entryId,
103
+ locale
104
+ });
105
+ return { result };
106
+ } catch (error) {
107
+ const reason = transientReason(error);
108
+ const stored = lastGood.get(key);
109
+ if (stored === void 0) return { result: {
110
+ status: "unavailable",
111
+ reason
112
+ } };
113
+ return {
114
+ result: {
115
+ status: "found",
116
+ blob: stored
117
+ },
118
+ staleReason: reason
119
+ };
120
+ }
121
+ }
122
+ const read = cache(async (contentTypeId, entryId, locale) => {
123
+ await connection();
124
+ const { isEnabled: draft } = await draftMode();
125
+ let result;
126
+ let staleReason;
127
+ if (draft) result = await readPreviewEntry(config, contentTypeId, entryId, locale);
128
+ else ({result, staleReason} = await readPublished(contentTypeId, entryId, locale));
129
+ const stale = staleReason !== void 0;
130
+ const { level, event } = stale ? STALE_READ_EVENT : READ_EVENTS[result.status];
131
+ const reason = staleReason ?? (result.status === "unavailable" || result.status === "invalid" ? result.reason : void 0);
132
+ if (!(!stale && result.status === "found" && process.env.NODE_ENV === "production")) logEvent(level, event, {
133
+ contentTypeId,
134
+ entryId,
135
+ locale,
136
+ source: draft ? "control-plane" : "data-plane",
137
+ ...reason === void 0 ? {} : { reason }
138
+ });
139
+ return result;
140
+ });
141
+ /**
142
+ * The scope's one read, awaited before render: the composite entry, sliced into one `$content`
143
+ * value per content-backed element. The values reach the components as literal props, so they are
144
+ * part of the server render by construction — a `cloneElement` from a client-side provider lands
145
+ * only on hydration, which is what made server HTML and client DOM disagree.
146
+ *
147
+ * The public shape takes one object, so a call site cannot silently swap two same-typed positional
148
+ * arguments; `React.cache` keys on the positional ones underneath.
149
+ */
150
+ async function readContentSlices({ contentTypeId, entryId, locale, elements }) {
151
+ const result = await read(contentTypeId, entryId, locale);
152
+ if (result.status !== "found") return emptySlices();
153
+ const slices = emptySlices();
154
+ const requested = Object.entries(elements);
155
+ const omissions = [];
156
+ for (const [elementId, modelId] of requested) {
157
+ const slice = sliceContent(result.blob, elementId, ownValue(config.contentTypes, modelId));
158
+ if (slice.status === "omitted") {
159
+ omissions.push({
160
+ elementId,
161
+ modelId,
162
+ reason: slice.reason
163
+ });
164
+ continue;
165
+ }
166
+ slices[elementId] = slice.content;
167
+ }
168
+ if (omissions.length > 0) logEvent("warn", "content.elements.omitted", {
169
+ contentTypeId,
170
+ entryId,
171
+ locale,
172
+ omitted: omissions.length,
173
+ total: requested.length,
174
+ omissions
175
+ });
176
+ return slices;
177
+ }
178
+ return {
179
+ readContentSlices,
180
+ ContentEntryBoundary
181
+ };
182
+ }
183
+ /**
184
+ * The slice map, with no prototype. An element id is a schema string, so `__proto__` is a name the
185
+ * map can be asked for; on a plain object the lookup would inherit `Object.prototype` and a boundary
186
+ * would render an element whose `$content` is that object rather than omitting it. The failure path
187
+ * returns this too — an entry that 404s must answer `undefined` for every key, including that one.
188
+ */
189
+ function emptySlices() {
190
+ return Object.create(null);
191
+ }
192
+ /**
193
+ * Renders its element only when that element's slice is present — the omission rule the content RFC
194
+ * states. It no longer delivers the value (the page passes `$content` as a literal prop), so it
195
+ * clones nothing and what wraps it no longer decides whether content arrives.
196
+ *
197
+ * Module scope, not a closure over `createContentRuntime`: it reads nothing from the runtime's
198
+ * configuration, so every store shares one component identity.
199
+ */
200
+ function ContentEntryBoundary({ value, children }) {
201
+ return value === void 0 ? null : children;
202
+ }
203
+ /**
204
+ * The published read: one composite entry from the Data Plane, live on every request. A definitive
205
+ * 404 resolves a `not-found` sentinel; a transient failure (network, timeout, 5xx, malformed body)
206
+ * throws, and `readPublished` decides between the stored blob and an omit.
207
+ *
208
+ * Nothing caches it. This read sat under `'use cache'` until Cache Components was removed for a
209
+ * platform that does not stream, and the five-minute `cacheLife` and 24-hour `expire` went with it —
210
+ * a transient failure used to throw inside the cache and Next kept serving the last-good entry for
211
+ * up to a day. What replaced that is the last-good store, which is a fallback and not a cache: it
212
+ * never shortens or skips this read, so the happy path is unchanged and a publish lands on the very
213
+ * next request. The page cache, the two cache tags this read emitted and the tag-based revalidation
214
+ * route they fed are still gone, and still owed by whatever restores caching.
215
+ */
216
+ async function readPublishedEntry(account, storeId, locale, contentTypeId, entryId) {
217
+ const url = buildDataPlaneUrl(account, storeId, locale, contentTypeId, entryId);
218
+ const response = await fetch(url, { signal: AbortSignal.timeout(ENTRY_REQUEST_TIMEOUT_MS) });
219
+ if (response.status === 404) return { status: "not-found" };
220
+ if (!response.ok) throw new Error(`content upstream status ${response.status}`);
221
+ let payload;
222
+ try {
223
+ payload = await response.json();
224
+ } catch {
225
+ throw new Error("content response is not JSON");
226
+ }
227
+ if (!isRecord(payload)) throw new Error("content response is not an object");
228
+ return {
229
+ status: "found",
230
+ blob: payload
231
+ };
232
+ }
233
+ /**
234
+ * The Draft Mode read: the same composite entry resolved through Control Plane's preview endpoint
235
+ * with a server-only credential, bypassing all caches. The branch comes from a SIGNED preview
236
+ * context cookie whose HMAC is re-verified here against the broker secret — a tampered cookie fails
237
+ * closed, so a valid session cannot read an unauthorized branch's drafts. The credential never
238
+ * enters browser code, logs, URLs, or props. Uncached, so its sentinels are never persisted.
239
+ */
240
+ async function readPreviewEntry(config, contentTypeId, entryId, locale) {
241
+ const token = process.env[PREVIEW_TOKEN_ENV];
242
+ if (!token) return {
243
+ status: "unavailable",
244
+ reason: "preview credential unavailable"
245
+ };
246
+ const secret = process.env[PREVIEW_SECRET_ENV];
247
+ if (!secret) return {
248
+ status: "unavailable",
249
+ reason: "preview secret unavailable"
250
+ };
251
+ const raw = (await cookies()).get(PREVIEW_COOKIE)?.value;
252
+ const claims = raw ? verifyPreviewContext(raw, secret) : null;
253
+ if (!claims || claims.account !== config.account || claims.storeId !== config.storeId || !claims.branch) return {
254
+ status: "unavailable",
255
+ reason: "invalid preview context"
256
+ };
257
+ const { account, storeId } = config;
258
+ return fetchPreview(`https://${account}.vtexcommercestable.com.br/api/content-platform/manage/${[
259
+ account,
260
+ storeId,
261
+ contentTypeId,
262
+ "entries",
263
+ "preview",
264
+ entryId
265
+ ].map(encodeURIComponent).join("/")}?branchId=${encodeURIComponent(claims.branch)}&locale=${encodeURIComponent(locale)}`, token);
266
+ }
267
+ async function fetchPreview(url, token) {
268
+ let response;
269
+ try {
270
+ response = await fetch(url, {
271
+ cache: "no-store",
272
+ headers: { Authorization: `Bearer ${token}` },
273
+ signal: AbortSignal.timeout(ENTRY_REQUEST_TIMEOUT_MS)
274
+ });
275
+ } catch (error) {
276
+ return {
277
+ status: "unavailable",
278
+ reason: isTimeoutError(error) ? "timeout" : "network error"
279
+ };
280
+ }
281
+ if (response.status === 404) return { status: "not-found" };
282
+ if (!response.ok) return {
283
+ status: "unavailable",
284
+ reason: `upstream status ${response.status}`
285
+ };
286
+ let payload;
287
+ try {
288
+ payload = await response.json();
289
+ } catch {
290
+ return {
291
+ status: "invalid",
292
+ reason: "response body is not JSON"
293
+ };
294
+ }
295
+ if (!isRecord(payload)) return {
296
+ status: "invalid",
297
+ reason: "response body is not an object"
298
+ };
299
+ return {
300
+ status: "found",
301
+ blob: payload
302
+ };
303
+ }
304
+ /**
305
+ * Verifies a signed preview context cookie (`base64url(claims).base64url(hmac)`) against the broker
306
+ * secret with a constant-time comparison, returning the claims only when the signature holds and the
307
+ * token has not expired — a captured cookie fails closed once past `exp`.
308
+ */
309
+ function verifyPreviewContext(raw, secret) {
310
+ const [body, signature] = raw.split(".");
311
+ if (!body || !signature) return null;
312
+ const expected = createHmac("sha256", secret).update(body).digest("base64url");
313
+ const given = Buffer.from(signature, "utf8");
314
+ const want = Buffer.from(expected, "utf8");
315
+ if (given.length !== want.length || !timingSafeEqual(given, want)) return null;
316
+ try {
317
+ const claims = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
318
+ if (typeof claims.branch !== "string" || !Number.isFinite(claims.exp) || Date.now() >= claims.exp) return null;
319
+ return claims;
320
+ } catch {
321
+ return null;
322
+ }
323
+ }
324
+ function buildDataPlaneUrl(account, storeId, locale, contentTypeId, entryId) {
325
+ return `https://${account}.vtexcommercestable.com.br/api/content-platform/data/${[
326
+ account,
327
+ storeId,
328
+ contentTypeId,
329
+ "entries",
330
+ entryId
331
+ ].map(encodeURIComponent).join("/")}?locale=${encodeURIComponent(locale)}`;
332
+ }
333
+ /**
334
+ * Slices one element's value out of the composite blob by its `element.id` and validates it against
335
+ * that element's per-component model. Omits only this component on a missing key, a non-object
336
+ * value, an unknown model, or a shape violation — keyword constraints are the preflight's job.
337
+ * Failing closed on an unknown model keeps an unvalidated blob from reaching `$content` (which would
338
+ * crash the route as a React child).
339
+ */
340
+ function sliceContent(blob, elementId, model) {
341
+ const raw = ownValue(blob, elementId);
342
+ if (!isRecord(raw)) return {
343
+ status: "omitted",
344
+ reason: "missing or non-object value"
345
+ };
346
+ if (!model) return {
347
+ status: "omitted",
348
+ reason: "unknown model"
349
+ };
350
+ const content = projectObject(model.schema.properties, raw);
351
+ const violation = findShapeViolation(model, content);
352
+ if (violation !== null) return {
353
+ status: "omitted",
354
+ reason: violation
355
+ };
356
+ return {
357
+ status: "sliced",
358
+ content
359
+ };
360
+ }
361
+ /**
362
+ * Keeps declared keys only, at every level the vocabulary admits, so the injected value matches the
363
+ * `ContentValue` type the component was compiled against. A value of the wrong shape passes through
364
+ * untouched for the validator below to reject.
365
+ */
366
+ function projectObject(properties, raw) {
367
+ const projected = {};
368
+ for (const [key, property] of Object.entries(properties)) {
369
+ const value = ownValue(raw, key);
370
+ if (value === void 0) continue;
371
+ if (property.type === "array") projected[key] = Array.isArray(value) ? value.map((member) => isRecord(member) ? projectObject(property.items.properties, member) : member) : value;
372
+ else if (property.type === "object") projected[key] = isRecord(value) ? projectObject(property.properties, value) : value;
373
+ else projected[key] = value;
374
+ }
375
+ return projected;
376
+ }
377
+ /** Shape-level validation only (required presence, primitive type, enum membership), at every level. */
378
+ function findShapeViolation(model, content) {
379
+ return findObjectViolation("", model.schema, content);
380
+ }
381
+ function findObjectViolation(path, shape, value) {
382
+ for (const key of shape.required ?? []) if (ownValue(value, key) === void 0) return `missing required property "${joinPath(path, key)}"`;
383
+ for (const [key, property] of Object.entries(shape.properties)) {
384
+ const member = ownValue(value, key);
385
+ if (member === void 0) continue;
386
+ const violation = findPropertyViolation(joinPath(path, key), property, member);
387
+ if (violation !== null) return violation;
388
+ }
389
+ return null;
390
+ }
391
+ function findPropertyViolation(path, property, value) {
392
+ if (property.type === "array") {
393
+ if (!Array.isArray(value)) return `property "${path}" does not match type "array"`;
394
+ for (const [index, member] of value.entries()) {
395
+ const itemPath = `${path}[${index}]`;
396
+ if (!isRecord(member)) return `property "${itemPath}" does not match type "object"`;
397
+ const violation = findObjectViolation(itemPath, property.items, member);
398
+ if (violation !== null) return violation;
399
+ }
400
+ return null;
401
+ }
402
+ if (property.type === "object") {
403
+ if (!isRecord(value)) return `property "${path}" does not match type "object"`;
404
+ return findObjectViolation(path, property, value);
405
+ }
406
+ if (!matchesScalarType(property.type, value)) return `property "${path}" does not match type "${property.type}"`;
407
+ if (property.enum && !property.enum.includes(value)) return `property "${path}" is not an allowed enum value`;
408
+ return null;
409
+ }
410
+ function joinPath(path, key) {
411
+ return path.length === 0 ? key : `${path}.${key}`;
412
+ }
413
+ function matchesScalarType(type, value) {
414
+ switch (type) {
415
+ case "string": return typeof value === "string";
416
+ case "boolean": return typeof value === "boolean";
417
+ case "number": return typeof value === "number" && Number.isFinite(value);
418
+ case "integer": return typeof value === "number" && Number.isInteger(value);
419
+ }
420
+ }
421
+ /**
422
+ * Severity as a function of the read's status, and nothing else: `unavailable` means the runtime
423
+ * could not read, which is the on-call signal; `not-found` and `invalid` mean the content is broken
424
+ * while the runtime works. `source` is a payload field, so a preview read that cannot resolve is a
425
+ * failure like any other. `invalid` is reachable from the preview branch only — the published path
426
+ * throws on a bad body, which is why the store covers that case.
427
+ */
428
+ const READ_EVENTS = {
429
+ found: {
430
+ level: "info",
431
+ event: "content.read.ok"
432
+ },
433
+ "not-found": {
434
+ level: "warn",
435
+ event: "content.read.missing"
436
+ },
437
+ invalid: {
438
+ level: "warn",
439
+ event: "content.read.invalid"
440
+ },
441
+ unavailable: {
442
+ level: "error",
443
+ event: "content.read.failed"
444
+ }
445
+ };
446
+ /**
447
+ * The one line the status does not decide: the read failed and the stored blob covered it. `warn`
448
+ * because the page rendered, which keeps `error` meaning exactly "the shopper is seeing holes". A
449
+ * covered outage never escalates on its own, so alerting on one means filtering this event name.
450
+ */
451
+ const STALE_READ_EVENT = {
452
+ level: "warn",
453
+ event: "content.read.stale"
454
+ };
455
+ /**
456
+ * The runtime's one log line: a constant message plus a payload whose `event` is the sole event
457
+ * discriminator, so rewording prose cannot break a consumer. Nothing here ever carries a content
458
+ * value, a preview token, or the broker secret.
459
+ *
460
+ * `entryId` is high-cardinality and stays log-only. Feeding these events to a metrics pipeline —
461
+ * which no part of this runtime has today — means dropping or hashing it at that boundary; the six
462
+ * event names are the bounded dimension set such a pipeline would inherit.
463
+ */
464
+ function logEvent(level, event, fields) {
465
+ console[level]("[content-runtime]", {
466
+ ...fields,
467
+ event
468
+ });
469
+ }
470
+ function transientReason(error) {
471
+ if (isTimeoutError(error)) return "timeout";
472
+ return error instanceof Error ? error.message : "network error";
473
+ }
474
+ /**
475
+ * The exact UTF-8 byte count of the serialized blob, not the JS string's UTF-16 code-unit count
476
+ * (`.length`). Non-ASCII text — accented Latin, common in Portuguese-language content, at 2 bytes per
477
+ * code unit, or CJK at 3 — makes those two numbers diverge, and a check against `.length` would let a
478
+ * blob past both ceilings while genuinely over them in bytes.
479
+ */
480
+ function blobByteLength(blob) {
481
+ return Buffer.byteLength(JSON.stringify(blob), "utf8");
482
+ }
483
+ function isRecord(value) {
484
+ return typeof value === "object" && value !== null && !Array.isArray(value);
485
+ }
486
+ /**
487
+ * Own-property read. Every object keyed by an authored id here comes from `JSON.parse` or a plain
488
+ * literal, so it carries `Object.prototype`: a key named `__proto__` or `constructor` would resolve
489
+ * to something inherited instead of to `undefined`, and the absent-key branch would never be taken.
490
+ */
491
+ function ownValue(source, key) {
492
+ return Object.hasOwn(source, key) ? source[key] : void 0;
493
+ }
494
+ /** Property check instead of `instanceof`: `AbortSignal.timeout` rejects with a `DOMException`. */
495
+ function isTimeoutError(error) {
496
+ if (typeof error !== "object" || error === null) return false;
497
+ const { name } = error;
498
+ return name === "TimeoutError" || name === "AbortError";
499
+ }
500
+ //#endregion
501
+ export { createContentRuntime };
502
+
503
+ //# sourceMappingURL=create-content-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-content-runtime.js","names":[],"sources":["../../../src/sdk/content/create-content-runtime.tsx"],"sourcesContent":["import { createHmac, timingSafeEqual } from 'node:crypto';\nimport type { ContentPropertySchema, ContentTypeDefinition } from '@vtex/fs-core';\nimport { cookies, draftMode } from 'next/headers';\nimport { connection } from 'next/server';\nimport { cache, type FC, type ReactNode } from 'react';\n\nexport type ContentRuntimeConfig = {\n account: string;\n storeId: string;\n /** Canonical per-component models, verbatim from the aggregated content catalog, keyed by id. */\n contentTypes: Record<string, ContentTypeDefinition>;\n};\n\n/** The coordinates of one composite read. `locale` arrives per call, so one build serves many. */\nexport type ReadContentSlicesArgs = {\n contentTypeId: string;\n entryId: string;\n locale: string;\n /** `element.id → per-component model id` for every content-backed element in the scope. */\n elements: Record<string, string>;\n};\n\n/**\n * The scope's slices, keyed by `element.id`. A key is absent when its element must be omitted — a\n * missing key, a shape violation, or a whole-entry failure.\n *\n * The value type is unchecked on purpose: the generated page forwards it to a component whose\n * `$content` is `ContentValue<that component's model>`, a type that exists only in the component\n * package, and an index signature cannot satisfy a model's required properties. Stated once here\n * rather than cast at every emitted prop; the read below validates every value against its model.\n */\nexport type ContentSlices = {\n // biome-ignore lint/suspicious/noExplicitAny: the model's type lives in the component package, not here.\n [elementId: string]: any;\n};\n\nexport type ContentEntryBoundaryProps = {\n /** This element's slice, read at the top of the scope. `undefined` omits the component. */\n value: unknown;\n children: ReactNode;\n};\n\nexport type ContentRuntime = {\n readContentSlices: (args: ReadContentSlicesArgs) => Promise<ContentSlices>;\n ContentEntryBoundary: FC<ContentEntryBoundaryProps>;\n};\n\n/** The signed preview context the Draft Mode route stores; re-verified here before use. */\ntype PreviewClaims = {\n account: string;\n storeId: string;\n branch: string;\n /** Millisecond epoch the token was minted / expires; a captured cookie stops working past `exp`. */\n iat: number;\n exp: number;\n};\n\n/**\n * Internal result taxonomy: a read either finds a validated composite blob or fails for a definite,\n * loggable reason. A transient upstream failure resolves `found` from the last-good store below when\n * that store holds the entry, and degrades to `unavailable` — omitting the affected components —\n * only when it does not.\n */\nexport type ContentEntryResult =\n | { status: 'found'; blob: Record<string, unknown> }\n | { status: 'not-found' }\n | { status: 'unavailable'; reason: string }\n | { status: 'invalid'; reason: string };\n\n/**\n * One published read's outcome. `staleReason` is present only when the fresh read failed and the\n * store covered it, and the result is then an ordinary `found`: no consumer has a fifth renderable\n * status to learn, and only the log line tells a served blob from a fresh one.\n */\ntype PublishedRead = { result: ContentEntryResult; staleReason?: string };\n\nconst ENTRY_REQUEST_TIMEOUT_MS = 5000;\n\n/**\n * Retention ceilings for the last-good store, both estimated rather than measured: no production\n * store exists yet to size a real composite against, and the example schemas in this repo are demo\n * content, not authored pages, so neither is evidence of real scale.\n *\n * `MAX_RETAINED_BLOB_BYTES` bounds one entry. Ordinary editorial text (a title, a body, an image URL,\n * an alt text) stays in the hundreds of bytes to a few kilobytes per element regardless of how many\n * elements a page composes — even the largest composed layout in this repo (103 elements) does not\n * read as megabytes if every element stays plain text. The realistic way to exceed this is a single\n * field holding embedded binary — a base64 image pasted into a text field instead of uploaded through\n * the media widget — which is exactly the shape this guards against, independent of element count.\n *\n * `MAX_RETAINED_TOTAL_BYTES` bounds the whole store, and is the one that actually matters: the\n * per-blob cap alone does not bound total memory, because it multiplies by key count, and key count is\n * not small — a large store's pages and layouts, times its locales, is plausibly a few hundred keys.\n * A few hundred keys at a few megabytes each already exceeds a typical serverless heap (512 MB–1 GB)\n * on the per-blob cap alone; ~64 MB is a small slice of that heap while still holding many ordinary\n * pages at once.\n *\n * Both numbers count serialized JSON text (`blobByteLength`), not retained heap: a parsed object\n * typically costs more than its JSON text — V8 pays per-property and per-string object overhead that\n * the text itself does not — so the real footprint at either ceiling is larger than the number on the\n * tin, plausibly by a small multiple. Both ceilings still leave headroom against a 512 MB–1 GB heap at\n * that multiple; sizing them as retained heap instead would need a runtime memory measurement this\n * module has no cheap way to take.\n *\n * Both numbers are round and generous on purpose, not derived. `content.retention.skipped` below is\n * the real calibration path: once a production store exists, its log volume says whether either\n * ceiling needs to move.\n */\nconst MAX_RETAINED_BLOB_BYTES = 1_000_000;\nconst MAX_RETAINED_TOTAL_BYTES = 64_000_000;\n\n/** Server-only preview credential, supplied at deployment time; never reaches the browser. */\nconst PREVIEW_TOKEN_ENV = 'CONTENT_PLATFORM_PREVIEW_TOKEN';\n/** Shared broker secret used to verify the signed preview context cookie. */\nconst PREVIEW_SECRET_ENV = 'CONTENT_PREVIEW_SECRET';\n/** The signed preview context cookie the Draft Mode route sets. */\nconst PREVIEW_COOKIE = '__fs_content_preview';\n\n/**\n * Creates the one server-side content read surface for a store: a `React.cache`-deduped\n * `readContentSlices` the generated page or layout awaits once at the top, and the\n * `ContentEntryBoundary` the compiler wraps around each content-backed element. One read per scope\n * yields every element's `$content` value keyed by `element.id`, so a page issues at most two Data\n * Plane reads (its own entry plus its layout's) regardless of content-backed component count. Draft\n * Mode switches the same read to Control Plane's preview endpoint through a server-only credential.\n */\nexport function createContentRuntime(config: ContentRuntimeConfig): ContentRuntime {\n // The blob of the most recent successful published read, per entry, so a failing Data Plane\n // renders the last content that worked instead of holes. Not `React.cache`, whose lifetime is the\n // request and so shorter than the failure it has to cover, and not module scope, which every\n // runtime in the process would share — two of them on the same coordinates would then serve each\n // other's content. The generated consumer holds the runtime in a module-scope `const`, so the\n // closure lives as long as the process either way.\n //\n // `contentTypeId` and `entryId` are compiler-emitted literals for the life of the deployment (a\n // dynamic route gets one entry, not one per slug), so today's key domain is small: pages plus\n // layouts, times locales. That is an invariant of the generated caller, not of this function —\n // nothing here stops a future one from passing a request-derived value instead, and the moment it\n // does, this map grows with traffic rather than with the store's page count.\n const lastGood = new Map<string, Record<string, unknown>>();\n let retainedBytes = 0;\n\n /**\n * Whether a successful read's blob replaces what `key` already holds, weighed against both\n * ceilings. Skipping never deletes: whatever `key` held before, if anything, is left exactly as it\n * was — only the update is declined, so a rare oversized read cannot erase a smaller last-good value\n * that a future failure could still use.\n */\n function retainBlob(\n key: string,\n blob: Record<string, unknown>,\n fields: { contentTypeId: string; entryId: string; locale: string },\n ): void {\n const size = blobByteLength(blob);\n if (size > MAX_RETAINED_BLOB_BYTES) {\n logEvent('warn', 'content.retention.skipped', { ...fields, bytes: size, reason: 'blob-too-large' });\n return;\n }\n const existing = lastGood.get(key);\n const existingSize = existing ? blobByteLength(existing) : 0;\n if (retainedBytes - existingSize + size > MAX_RETAINED_TOTAL_BYTES) {\n logEvent('warn', 'content.retention.skipped', { ...fields, bytes: size, reason: 'total-cap-reached' });\n return;\n }\n lastGood.set(key, blob);\n retainedBytes += size - existingSize;\n }\n\n /**\n * The published read plus the fallback that covers it. The upstream is always called and the store\n * is read only in the `catch`, which is what makes this a fallback and not a cache: a publish is\n * visible on the very next request. A success ordinarily overwrites the entry (see `retainBlob` for\n * the two cases where it does not), a `not-found` leaves it alone so unpublishing still unpublishes,\n * and nothing is ever removed or expired by age.\n *\n * Failure is structural — whatever leaves `readPublishedEntry` as a throw — rather than a status\n * table, so a 403 or a 429 serves the stored blob, and a failure mode added there later is covered\n * without touching this.\n */\n async function readPublished(contentTypeId: string, entryId: string, locale: string): Promise<PublishedRead> {\n // NUL appears in no content-type id, entry id, or BCP-47 tag, so two distinct triples cannot\n // collide. Keyed on the same three values the memoisation below uses, so the two layers never\n // disagree about what \"the same read\" is.\n const key = `${contentTypeId}\\u0000${entryId}\\u0000${locale}`;\n try {\n const result = await readPublishedEntry(config.account, config.storeId, locale, contentTypeId, entryId);\n if (result.status === 'found') {\n retainBlob(key, result.blob, { contentTypeId, entryId, locale });\n }\n return { result };\n } catch (error) {\n const reason = transientReason(error);\n const stored = lastGood.get(key);\n // Nothing stored: omit the affected components while the rest of the route renders.\n if (stored === undefined) return { result: { status: 'unavailable', reason } };\n return { result: { status: 'found', blob: stored }, staleReason: reason };\n }\n }\n\n // React.cache collapses same-entry awaits within one request: N boundaries reading the same\n // composite entry share one upstream read and one read-log line. That is per-request memoisation\n // only — nothing is reused across requests — so it is `readPublished` above, not this, that\n // carries a value across the failure it covers. Either way a read never throws a route error.\n const read = cache(async (contentTypeId: string, entryId: string, locale: string): Promise<ContentEntryResult> => {\n // Content is read per request, never at build time. Nothing else on a content-only page is\n // request-dependent — `draftMode()` prerenders as disabled and an uncached `fetch` does not bail\n // out on its own — so without this the entry is captured by a static prerender and the store\n // stops tracking the CMS until its next deploy. `'use cache'` used to hold the route open with a\n // five-minute revalidate; removing it for a platform that does not stream took that with it.\n // Outside the fallback's try, which lives in `readPublished`, so the bail-out it throws during\n // static generation is never swallowed as a transient failure.\n await connection();\n const { isEnabled: draft } = await draftMode();\n let result: ContentEntryResult;\n let staleReason: string | undefined;\n if (draft) {\n // The preview branch neither reads the store nor writes it: an unpublished blob must not\n // outlive the request that asked for it, and a draft must never cover a published failure.\n result = await readPreviewEntry(config, contentTypeId, entryId, locale);\n } else {\n ({ result, staleReason } = await readPublished(contentTypeId, entryId, locale));\n }\n // A served blob is `found`, so the status alone would report it as a success.\n const stale = staleReason !== undefined;\n const { level, event } = stale ? STALE_READ_EVENT : READ_EVENTS[result.status];\n const reason =\n staleReason ?? (result.status === 'unavailable' || result.status === 'invalid' ? result.reason : undefined);\n // The success line is the cheapest evidence of the ≤2-reads-per-page guarantee, and its only\n // cost is production volume: nothing caches this read, so it would emit once or twice per page\n // view and bury the rare failure line. Suppressed there, kept everywhere the count is checked —\n // and the gate covers a genuine success only, so a covered outage stays audible in production.\n const suppressed = !stale && result.status === 'found' && process.env.NODE_ENV === 'production';\n if (!suppressed) {\n logEvent(level, event, {\n contentTypeId,\n entryId,\n locale,\n source: draft ? 'control-plane' : 'data-plane',\n ...(reason === undefined ? {} : { reason }),\n });\n }\n return result;\n });\n\n /**\n * The scope's one read, awaited before render: the composite entry, sliced into one `$content`\n * value per content-backed element. The values reach the components as literal props, so they are\n * part of the server render by construction — a `cloneElement` from a client-side provider lands\n * only on hydration, which is what made server HTML and client DOM disagree.\n *\n * The public shape takes one object, so a call site cannot silently swap two same-typed positional\n * arguments; `React.cache` keys on the positional ones underneath.\n */\n async function readContentSlices({\n contentTypeId,\n entryId,\n locale,\n elements,\n }: ReadContentSlicesArgs): Promise<ContentSlices> {\n const result = await read(contentTypeId, entryId, locale);\n if (result.status !== 'found') {\n // A whole-entry failure (404, invalid, or an upstream failure with nothing stored for the\n // entry) omits every component sharing it: no key is present, so every boundary renders\n // nothing. A failure the last-good store covered never arrives here — it arrives as `found`.\n return emptySlices();\n }\n const slices = emptySlices();\n const requested = Object.entries(elements);\n const omissions: ElementOmission[] = [];\n for (const [elementId, modelId] of requested) {\n const slice = sliceContent(result.blob, elementId, ownValue(config.contentTypes, modelId));\n if (slice.status === 'omitted') {\n // A missing or invalid key within an otherwise-valid entry omits only this one component.\n omissions.push({ elementId, modelId, reason: slice.reason });\n continue;\n }\n slices[elementId] = slice.content;\n }\n if (omissions.length > 0) {\n // One line per call rather than one per element: the operational fact is the ratio, and\n // `omitted === total` is what tells a blank scope from a partial one. The level says only that\n // the page rendered, so it stays `warn` at every ratio.\n logEvent('warn', 'content.elements.omitted', {\n contentTypeId,\n entryId,\n locale,\n omitted: omissions.length,\n total: requested.length,\n omissions,\n });\n }\n return slices;\n }\n\n return { readContentSlices, ContentEntryBoundary };\n}\n\n/**\n * The slice map, with no prototype. An element id is a schema string, so `__proto__` is a name the\n * map can be asked for; on a plain object the lookup would inherit `Object.prototype` and a boundary\n * would render an element whose `$content` is that object rather than omitting it. The failure path\n * returns this too — an entry that 404s must answer `undefined` for every key, including that one.\n */\nfunction emptySlices(): ContentSlices {\n return Object.create(null) as ContentSlices;\n}\n\n/**\n * Renders its element only when that element's slice is present — the omission rule the content RFC\n * states. It no longer delivers the value (the page passes `$content` as a literal prop), so it\n * clones nothing and what wraps it no longer decides whether content arrives.\n *\n * Module scope, not a closure over `createContentRuntime`: it reads nothing from the runtime's\n * configuration, so every store shares one component identity.\n */\nfunction ContentEntryBoundary({ value, children }: ContentEntryBoundaryProps): ReactNode {\n return value === undefined ? null : children;\n}\n\n/**\n * The published read: one composite entry from the Data Plane, live on every request. A definitive\n * 404 resolves a `not-found` sentinel; a transient failure (network, timeout, 5xx, malformed body)\n * throws, and `readPublished` decides between the stored blob and an omit.\n *\n * Nothing caches it. This read sat under `'use cache'` until Cache Components was removed for a\n * platform that does not stream, and the five-minute `cacheLife` and 24-hour `expire` went with it —\n * a transient failure used to throw inside the cache and Next kept serving the last-good entry for\n * up to a day. What replaced that is the last-good store, which is a fallback and not a cache: it\n * never shortens or skips this read, so the happy path is unchanged and a publish lands on the very\n * next request. The page cache, the two cache tags this read emitted and the tag-based revalidation\n * route they fed are still gone, and still owed by whatever restores caching.\n */\nasync function readPublishedEntry(\n account: string,\n storeId: string,\n locale: string,\n contentTypeId: string,\n entryId: string,\n): Promise<ContentEntryResult> {\n const url = buildDataPlaneUrl(account, storeId, locale, contentTypeId, entryId);\n const response = await fetch(url, { signal: AbortSignal.timeout(ENTRY_REQUEST_TIMEOUT_MS) });\n\n if (response.status === 404) return { status: 'not-found' };\n if (!response.ok) throw new Error(`content upstream status ${response.status}`);\n\n let payload: unknown;\n try {\n payload = await response.json();\n } catch {\n throw new Error('content response is not JSON');\n }\n if (!isRecord(payload)) throw new Error('content response is not an object');\n\n return { status: 'found', blob: payload };\n}\n\n/**\n * The Draft Mode read: the same composite entry resolved through Control Plane's preview endpoint\n * with a server-only credential, bypassing all caches. The branch comes from a SIGNED preview\n * context cookie whose HMAC is re-verified here against the broker secret — a tampered cookie fails\n * closed, so a valid session cannot read an unauthorized branch's drafts. The credential never\n * enters browser code, logs, URLs, or props. Uncached, so its sentinels are never persisted.\n */\nasync function readPreviewEntry(\n config: ContentRuntimeConfig,\n contentTypeId: string,\n entryId: string,\n locale: string,\n): Promise<ContentEntryResult> {\n const token = process.env[PREVIEW_TOKEN_ENV];\n if (!token) return { status: 'unavailable', reason: 'preview credential unavailable' };\n const secret = process.env[PREVIEW_SECRET_ENV];\n if (!secret) return { status: 'unavailable', reason: 'preview secret unavailable' };\n\n const store = await cookies();\n const raw = store.get(PREVIEW_COOKIE)?.value;\n const claims = raw ? verifyPreviewContext(raw, secret) : null;\n if (!claims || claims.account !== config.account || claims.storeId !== config.storeId || !claims.branch) {\n return { status: 'unavailable', reason: 'invalid preview context' };\n }\n\n const { account, storeId } = config;\n const path = [account, storeId, contentTypeId, 'entries', 'preview', entryId].map(encodeURIComponent).join('/');\n const url = `https://${account}.vtexcommercestable.com.br/api/content-platform/manage/${path}?branchId=${encodeURIComponent(claims.branch)}&locale=${encodeURIComponent(locale)}`;\n return fetchPreview(url, token);\n}\n\nasync function fetchPreview(url: string, token: string): Promise<ContentEntryResult> {\n let response: Response;\n try {\n response = await fetch(url, {\n cache: 'no-store',\n headers: { Authorization: `Bearer ${token}` },\n signal: AbortSignal.timeout(ENTRY_REQUEST_TIMEOUT_MS),\n });\n } catch (error) {\n return { status: 'unavailable', reason: isTimeoutError(error) ? 'timeout' : 'network error' };\n }\n if (response.status === 404) return { status: 'not-found' };\n if (!response.ok) return { status: 'unavailable', reason: `upstream status ${response.status}` };\n let payload: unknown;\n try {\n payload = await response.json();\n } catch {\n return { status: 'invalid', reason: 'response body is not JSON' };\n }\n if (!isRecord(payload)) return { status: 'invalid', reason: 'response body is not an object' };\n return { status: 'found', blob: payload };\n}\n\n/**\n * Verifies a signed preview context cookie (`base64url(claims).base64url(hmac)`) against the broker\n * secret with a constant-time comparison, returning the claims only when the signature holds and the\n * token has not expired — a captured cookie fails closed once past `exp`.\n */\nfunction verifyPreviewContext(raw: string, secret: string): PreviewClaims | null {\n const [body, signature] = raw.split('.');\n if (!body || !signature) return null;\n const expected = createHmac('sha256', secret).update(body).digest('base64url');\n const given = Buffer.from(signature, 'utf8');\n const want = Buffer.from(expected, 'utf8');\n if (given.length !== want.length || !timingSafeEqual(given, want)) return null;\n try {\n const claims = JSON.parse(Buffer.from(body, 'base64url').toString('utf8')) as PreviewClaims;\n if (typeof claims.branch !== 'string' || !Number.isFinite(claims.exp) || Date.now() >= claims.exp) {\n return null;\n }\n return claims;\n } catch {\n return null;\n }\n}\n\nfunction buildDataPlaneUrl(\n account: string,\n storeId: string,\n locale: string,\n contentTypeId: string,\n entryId: string,\n): string {\n const path = [account, storeId, contentTypeId, 'entries', entryId].map(encodeURIComponent).join('/');\n return `https://${account}.vtexcommercestable.com.br/api/content-platform/data/${path}?locale=${encodeURIComponent(locale)}`;\n}\n\ntype ContentSliceResult =\n | { status: 'sliced'; content: Record<string, unknown> }\n | { status: 'omitted'; reason: string };\n\n/**\n * Slices one element's value out of the composite blob by its `element.id` and validates it against\n * that element's per-component model. Omits only this component on a missing key, a non-object\n * value, an unknown model, or a shape violation — keyword constraints are the preflight's job.\n * Failing closed on an unknown model keeps an unvalidated blob from reaching `$content` (which would\n * crash the route as a React child).\n */\nfunction sliceContent(\n blob: Record<string, unknown>,\n elementId: string,\n model: ContentTypeDefinition | undefined,\n): ContentSliceResult {\n const raw = ownValue(blob, elementId);\n if (!isRecord(raw)) return { status: 'omitted', reason: 'missing or non-object value' };\n if (!model) return { status: 'omitted', reason: 'unknown model' };\n\n const content = projectObject(model.schema.properties, raw);\n const violation = findShapeViolation(model, content);\n if (violation !== null) return { status: 'omitted', reason: violation };\n return { status: 'sliced', content };\n}\n\n/** A closed object shape, at the root or one level down. */\ntype ClosedObjectShape = {\n required?: readonly string[];\n properties: Record<string, ContentPropertySchema>;\n};\n\n/**\n * Keeps declared keys only, at every level the vocabulary admits, so the injected value matches the\n * `ContentValue` type the component was compiled against. A value of the wrong shape passes through\n * untouched for the validator below to reject.\n */\nfunction projectObject(\n properties: Record<string, ContentPropertySchema>,\n raw: Record<string, unknown>,\n): Record<string, unknown> {\n const projected: Record<string, unknown> = {};\n for (const [key, property] of Object.entries(properties)) {\n const value = ownValue(raw, key);\n if (value === undefined) continue;\n if (property.type === 'array') {\n projected[key] = Array.isArray(value)\n ? value.map((member) => (isRecord(member) ? projectObject(property.items.properties, member) : member))\n : value;\n } else if (property.type === 'object') {\n projected[key] = isRecord(value) ? projectObject(property.properties, value) : value;\n } else {\n projected[key] = value;\n }\n }\n return projected;\n}\n\n/** Shape-level validation only (required presence, primitive type, enum membership), at every level. */\nfunction findShapeViolation(model: ContentTypeDefinition, content: Record<string, unknown>): string | null {\n return findObjectViolation('', model.schema, content);\n}\n\nfunction findObjectViolation(path: string, shape: ClosedObjectShape, value: Record<string, unknown>): string | null {\n for (const key of shape.required ?? []) {\n if (ownValue(value, key) === undefined) return `missing required property \"${joinPath(path, key)}\"`;\n }\n for (const [key, property] of Object.entries(shape.properties)) {\n const member = ownValue(value, key);\n if (member === undefined) continue;\n const violation = findPropertyViolation(joinPath(path, key), property, member);\n if (violation !== null) return violation;\n }\n return null;\n}\n\nfunction findPropertyViolation(path: string, property: ContentPropertySchema, value: unknown): string | null {\n if (property.type === 'array') {\n if (!Array.isArray(value)) return `property \"${path}\" does not match type \"array\"`;\n for (const [index, member] of value.entries()) {\n const itemPath = `${path}[${index}]`;\n if (!isRecord(member)) return `property \"${itemPath}\" does not match type \"object\"`;\n const violation = findObjectViolation(itemPath, property.items, member);\n if (violation !== null) return violation;\n }\n // minItems and maxItems are author-time bounds; the read path does not enforce them.\n return null;\n }\n if (property.type === 'object') {\n if (!isRecord(value)) return `property \"${path}\" does not match type \"object\"`;\n return findObjectViolation(path, property, value);\n }\n if (!matchesScalarType(property.type, value)) return `property \"${path}\" does not match type \"${property.type}\"`;\n if (property.enum && !property.enum.includes(value as string | number)) {\n return `property \"${path}\" is not an allowed enum value`;\n }\n return null;\n}\n\nfunction joinPath(path: string, key: string): string {\n return path.length === 0 ? key : `${path}.${key}`;\n}\n\nfunction matchesScalarType(type: 'string' | 'number' | 'integer' | 'boolean', value: unknown): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'boolean':\n return typeof value === 'boolean';\n case 'number':\n return typeof value === 'number' && Number.isFinite(value);\n case 'integer':\n return typeof value === 'number' && Number.isInteger(value);\n }\n}\n\ntype LogLevel = 'error' | 'warn' | 'info';\n\n/** The closed vocabulary a log consumer discriminates on. Nothing else is ever emitted. */\ntype ContentEvent =\n | 'content.read.ok'\n | 'content.read.stale'\n | 'content.read.missing'\n | 'content.read.invalid'\n | 'content.read.failed'\n | 'content.elements.omitted'\n | 'content.retention.skipped';\n\n/** One omitted element, as the aggregate line reports it. `reason` is a path, never a value. */\ntype ElementOmission = { elementId: string; modelId: string; reason: string };\n\n/**\n * Severity as a function of the read's status, and nothing else: `unavailable` means the runtime\n * could not read, which is the on-call signal; `not-found` and `invalid` mean the content is broken\n * while the runtime works. `source` is a payload field, so a preview read that cannot resolve is a\n * failure like any other. `invalid` is reachable from the preview branch only — the published path\n * throws on a bad body, which is why the store covers that case.\n */\nconst READ_EVENTS: Record<ContentEntryResult['status'], { level: LogLevel; event: ContentEvent }> = {\n found: { level: 'info', event: 'content.read.ok' },\n 'not-found': { level: 'warn', event: 'content.read.missing' },\n invalid: { level: 'warn', event: 'content.read.invalid' },\n unavailable: { level: 'error', event: 'content.read.failed' },\n};\n\n/**\n * The one line the status does not decide: the read failed and the stored blob covered it. `warn`\n * because the page rendered, which keeps `error` meaning exactly \"the shopper is seeing holes\". A\n * covered outage never escalates on its own, so alerting on one means filtering this event name.\n */\nconst STALE_READ_EVENT: { level: LogLevel; event: ContentEvent } = { level: 'warn', event: 'content.read.stale' };\n\n/**\n * The runtime's one log line: a constant message plus a payload whose `event` is the sole event\n * discriminator, so rewording prose cannot break a consumer. Nothing here ever carries a content\n * value, a preview token, or the broker secret.\n *\n * `entryId` is high-cardinality and stays log-only. Feeding these events to a metrics pipeline —\n * which no part of this runtime has today — means dropping or hashing it at that boundary; the six\n * event names are the bounded dimension set such a pipeline would inherit.\n */\nfunction logEvent(level: LogLevel, event: ContentEvent, fields: Record<string, unknown>): void {\n // `event` spreads last so a `fields` key of the same name cannot displace the discriminator every\n // consumer keys on. `fields` is a `Record<string, unknown>`, so nothing in the types would object.\n console[level]('[content-runtime]', { ...fields, event });\n}\n\nfunction transientReason(error: unknown): string {\n if (isTimeoutError(error)) return 'timeout';\n return error instanceof Error ? error.message : 'network error';\n}\n\n/**\n * The exact UTF-8 byte count of the serialized blob, not the JS string's UTF-16 code-unit count\n * (`.length`). Non-ASCII text — accented Latin, common in Portuguese-language content, at 2 bytes per\n * code unit, or CJK at 3 — makes those two numbers diverge, and a check against `.length` would let a\n * blob past both ceilings while genuinely over them in bytes.\n */\nfunction blobByteLength(blob: Record<string, unknown>): number {\n return Buffer.byteLength(JSON.stringify(blob), 'utf8');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Own-property read. Every object keyed by an authored id here comes from `JSON.parse` or a plain\n * literal, so it carries `Object.prototype`: a key named `__proto__` or `constructor` would resolve\n * to something inherited instead of to `undefined`, and the absent-key branch would never be taken.\n */\nfunction ownValue<T>(source: Record<string, T>, key: string): T | undefined {\n return Object.hasOwn(source, key) ? source[key] : undefined;\n}\n\n/** Property check instead of `instanceof`: `AbortSignal.timeout` rejects with a `DOMException`. */\nfunction isTimeoutError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) return false;\n const { name } = error as { name?: unknown };\n return name === 'TimeoutError' || name === 'AbortError';\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { StorefrontContext } from "../../core/dist/schema/generated/schema.js";
2
+ import "../../core/dist/index.js";
3
+ //#region src/sdk/context/headers.d.ts
4
+ /**
5
+ * The context headers every commerce operation carries, in the RFC's spelling. The `x-faststore-`
6
+ * prefix marks them as storefront-declared: API Core correlates on them, it does not trust them.
7
+ *
8
+ * One builder for all three request paths — the browser Apollo provider, `createClient`, and
9
+ * `registerPreloadQuery` — so a server-rendered request and its client-side follow-up can never
10
+ * disagree about the context they were made for. These win over explicit `headers` on merge: a
11
+ * caller must not be able to claim a context the app did not render.
12
+ */
13
+ export declare function buildStorefrontContextHeaders(context: StorefrontContext): Record<string, string>;
14
+ //#endregion
15
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1,21 @@
1
+ //#region src/sdk/context/headers.ts
2
+ /**
3
+ * The context headers every commerce operation carries, in the RFC's spelling. The `x-faststore-`
4
+ * prefix marks them as storefront-declared: API Core correlates on them, it does not trust them.
5
+ *
6
+ * One builder for all three request paths — the browser Apollo provider, `createClient`, and
7
+ * `registerPreloadQuery` — so a server-rendered request and its client-side follow-up can never
8
+ * disagree about the context they were made for. These win over explicit `headers` on merge: a
9
+ * caller must not be able to claim a context the app did not render.
10
+ */
11
+ function buildStorefrontContextHeaders(context) {
12
+ return {
13
+ "x-faststore-binding": context.bindingId,
14
+ "x-faststore-locale": context.locale,
15
+ "x-faststore-sales-channel": context.salesChannel
16
+ };
17
+ }
18
+ //#endregion
19
+ export { buildStorefrontContextHeaders };
20
+
21
+ //# sourceMappingURL=headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.js","names":[],"sources":["../../../src/sdk/context/headers.ts"],"sourcesContent":["import type { StorefrontContext } from '@vtex/fs-core';\n\n/**\n * The context headers every commerce operation carries, in the RFC's spelling. The `x-faststore-`\n * prefix marks them as storefront-declared: API Core correlates on them, it does not trust them.\n *\n * One builder for all three request paths — the browser Apollo provider, `createClient`, and\n * `registerPreloadQuery` — so a server-rendered request and its client-side follow-up can never\n * disagree about the context they were made for. These win over explicit `headers` on merge: a\n * caller must not be able to claim a context the app did not render.\n */\nexport function buildStorefrontContextHeaders(context: StorefrontContext): Record<string, string> {\n return {\n 'x-faststore-binding': context.bindingId,\n 'x-faststore-locale': context.locale,\n 'x-faststore-sales-channel': context.salesChannel,\n };\n}\n"],"mappings":";;;;;;;;;;AAWA,SAAgB,8BAA8B,SAAoD;CAChG,OAAO;EACL,uBAAuB,QAAQ;EAC/B,sBAAsB,QAAQ;EAC9B,6BAA6B,QAAQ;CACvC;AACF"}
@@ -0,0 +1,11 @@
1
+ import { StorefrontContext } from "../../core/dist/schema/generated/schema.js";
2
+ import "../../core/dist/index.js";
3
+ import { ReactNode } from "react";
4
+ //#region src/sdk/context/storefront-context.d.ts
5
+ /**
6
+ * The active storefront context: locale, currency, sales channel, country, timezone, and text
7
+ * direction. Throws outside a `StorefrontProvider` that received a `context`.
8
+ */
9
+ export declare function useStorefrontContext(): StorefrontContext;
10
+ //#endregion
11
+ //# sourceMappingURL=storefront-context.d.ts.map