@salla.sa/twilight-theme-engine 1.0.148 → 1.0.150

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 (263) hide show
  1. package/dist/{AddToCartForm-WY5QEHJ4.js → AddToCartForm-P5Q4P763.js} +3 -3
  2. package/dist/{AddToCartForm-WY5QEHJ4.js.map → AddToCartForm-P5Q4P763.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-E2WXK6HD.js → BlogAuthorPage-Z3R6AETN.js} +27 -27
  4. package/dist/{BlogAuthorPage-E2WXK6HD.js.map → BlogAuthorPage-Z3R6AETN.js.map} +1 -1
  5. package/dist/{BlogCategoryPage-B2JEB33A.js → BlogCategoryPage-7VROFBGI.js} +27 -27
  6. package/dist/{BlogCategoryPage-B2JEB33A.js.map → BlogCategoryPage-7VROFBGI.js.map} +1 -1
  7. package/dist/{BlogPage-CSNI6SS5.js → BlogPage-Q2NN4WTB.js} +25 -25
  8. package/dist/{BlogPage-CSNI6SS5.js.map → BlogPage-Q2NN4WTB.js.map} +1 -1
  9. package/dist/{BlogSinglePage-5ZY5EB6H.js → BlogSinglePage-ZPCSNBIX.js} +25 -25
  10. package/dist/{BlogSinglePage-5ZY5EB6H.js.map → BlogSinglePage-ZPCSNBIX.js.map} +1 -1
  11. package/dist/{BlogTagPage-QFS7AKNK.js → BlogTagPage-IGG2VEMR.js} +27 -27
  12. package/dist/{BlogTagPage-QFS7AKNK.js.map → BlogTagPage-IGG2VEMR.js.map} +1 -1
  13. package/dist/{BrandsPage-QBA2WQHF.js → BrandsPage-ZAJT6RGM.js} +26 -26
  14. package/dist/{BrandsPage-QBA2WQHF.js.map → BrandsPage-ZAJT6RGM.js.map} +1 -1
  15. package/dist/{Breadcrumb-CH35WQ6M.js → Breadcrumb-KE4EWH7L.js} +25 -25
  16. package/dist/{Breadcrumb-CH35WQ6M.js.map → Breadcrumb-KE4EWH7L.js.map} +1 -1
  17. package/dist/{CartItem-NBM3KRUH.js → CartItem-RMCXCGHT.js} +25 -25
  18. package/dist/{CartItem-NBM3KRUH.js.map → CartItem-RMCXCGHT.js.map} +1 -1
  19. package/dist/{CartSummary-OD2IJTTA.js → CartSummary-NLEAHKWF.js} +25 -25
  20. package/dist/{CartSummary-OD2IJTTA.js.map → CartSummary-NLEAHKWF.js.map} +1 -1
  21. package/dist/{Copyright-7EC2FQUB.js → Copyright-EIBPTE3B.js} +3 -3
  22. package/dist/{Copyright-7EC2FQUB.js.map → Copyright-EIBPTE3B.js.map} +1 -1
  23. package/dist/{CustomerLayout-7GEOMQ3Z.js → CustomerLayout-POGWFN6R.js} +25 -25
  24. package/dist/{CustomerLayout-7GEOMQ3Z.js.map → CustomerLayout-POGWFN6R.js.map} +1 -1
  25. package/dist/{Footer-JTQIMWSF.js → Footer-LGIUINGS.js} +4 -4
  26. package/dist/{Footer-JTQIMWSF.js.map → Footer-LGIUINGS.js.map} +1 -1
  27. package/dist/{Header-4ZW5UVTX.js → Header-4TGYO6E4.js} +11 -11
  28. package/dist/{Header-4ZW5UVTX.js.map → Header-4TGYO6E4.js.map} +1 -1
  29. package/dist/{LatestProducts-VHN2P5TE.js → LatestProducts-YYKQNL5N.js} +27 -27
  30. package/dist/{LatestProducts-VHN2P5TE.js.map → LatestProducts-YYKQNL5N.js.map} +1 -1
  31. package/dist/{LoyaltyPage-PVK7FBFE.js → LoyaltyPage-MROFMZXV.js} +25 -25
  32. package/dist/{LoyaltyPage-PVK7FBFE.js.map → LoyaltyPage-MROFMZXV.js.map} +1 -1
  33. package/dist/{LoyaltyPointsPage-WYCO453U.js → LoyaltyPointsPage-DVHJOAKP.js} +8 -8
  34. package/dist/{LoyaltyPointsPage-WYCO453U.js.map → LoyaltyPointsPage-DVHJOAKP.js.map} +1 -1
  35. package/dist/{MainMenu-Y2PAFESM.js → MainMenu-GQO5KOTU.js} +7 -7
  36. package/dist/{MainMenu-Y2PAFESM.js.map → MainMenu-GQO5KOTU.js.map} +1 -1
  37. package/dist/{MasterLayout-EBLVT53G.js → MasterLayout-ZJBJ7EHM.js} +25 -25
  38. package/dist/{MasterLayout-EBLVT53G.js.map → MasterLayout-ZJBJ7EHM.js.map} +1 -1
  39. package/dist/{MobileMenu-YIL4MEWX.js → MobileMenu-TZSFYHPW.js} +26 -26
  40. package/dist/{MobileMenu-YIL4MEWX.js.map → MobileMenu-TZSFYHPW.js.map} +1 -1
  41. package/dist/{NotificationsPage-K2CJOV2N.js → NotificationsPage-BX6OSIDY.js} +25 -25
  42. package/dist/{NotificationsPage-K2CJOV2N.js.map → NotificationsPage-BX6OSIDY.js.map} +1 -1
  43. package/dist/{OrderSinglePage-T7S7KXJ3.js → OrderSinglePage-3RQ5TJDB.js} +26 -26
  44. package/dist/{OrderSinglePage-T7S7KXJ3.js.map → OrderSinglePage-3RQ5TJDB.js.map} +1 -1
  45. package/dist/{OrdersPage-WAW3NS2E.js → OrdersPage-S4ECYNGI.js} +25 -25
  46. package/dist/{OrdersPage-WAW3NS2E.js.map → OrdersPage-S4ECYNGI.js.map} +1 -1
  47. package/dist/{PageSingle-L5EBQGWS.js → PageSingle-BZGDC4VE.js} +6 -6
  48. package/dist/{PageSingle-L5EBQGWS.js.map → PageSingle-BZGDC4VE.js.map} +1 -1
  49. package/dist/{ProductDetails-4E46ZCMQ.js → ProductDetails-ZPRWPSVK.js} +7 -7
  50. package/dist/{ProductDetails-4E46ZCMQ.js.map → ProductDetails-ZPRWPSVK.js.map} +1 -1
  51. package/dist/{ProfilePage-KN7BWYFZ.js → ProfilePage-SKAS6LFQ.js} +25 -25
  52. package/dist/{ProfilePage-KN7BWYFZ.js.map → ProfilePage-SKAS6LFQ.js.map} +1 -1
  53. package/dist/{ReviewsPage-CCTPJN76.js → ReviewsPage-NAZWXVXT.js} +3 -3
  54. package/dist/{ReviewsPage-CCTPJN76.js.map → ReviewsPage-NAZWXVXT.js.map} +1 -1
  55. package/dist/{SeoCartWidget-Q5XK5MEW.js → SeoCartWidget-6NB6LT2Z.js} +25 -25
  56. package/dist/{SeoCartWidget-Q5XK5MEW.js.map → SeoCartWidget-6NB6LT2Z.js.map} +1 -1
  57. package/dist/{SettingsPage-DQAAMJE5.js → SettingsPage-GZ2NJIUR.js} +25 -25
  58. package/dist/{SettingsPage-DQAAMJE5.js.map → SettingsPage-GZ2NJIUR.js.map} +1 -1
  59. package/dist/{StoreClosedNotification-ZSDPBM3L.js → StoreClosedNotification-V72F7HE5.js} +26 -26
  60. package/dist/{StoreClosedNotification-ZSDPBM3L.js.map → StoreClosedNotification-V72F7HE5.js.map} +1 -1
  61. package/dist/{TestimonialsPage-6LGQSJSQ.js → TestimonialsPage-L6VBZFLT.js} +6 -6
  62. package/dist/{TestimonialsPage-6LGQSJSQ.js.map → TestimonialsPage-L6VBZFLT.js.map} +1 -1
  63. package/dist/{ThankYouPage-ZI6NEGN3.js → ThankYouPage-O5U3V6J4.js} +25 -25
  64. package/dist/{ThankYouPage-ZI6NEGN3.js.map → ThankYouPage-O5U3V6J4.js.map} +1 -1
  65. package/dist/{WalletPage-R6G5BQAI.js → WalletPage-NJBBZIMM.js} +26 -26
  66. package/dist/{WalletPage-R6G5BQAI.js.map → WalletPage-NJBBZIMM.js.map} +1 -1
  67. package/dist/{WebMcpTools-2NWIVDL2.js → WebMcpTools-VAZH3S5G.js} +9 -9
  68. package/dist/{WebMcpTools-2NWIVDL2.js.map → WebMcpTools-VAZH3S5G.js.map} +1 -1
  69. package/dist/{WishlistPage-CQ62GPLC.js → WishlistPage-UKOGNFKB.js} +27 -27
  70. package/dist/{WishlistPage-CQ62GPLC.js.map → WishlistPage-UKOGNFKB.js.map} +1 -1
  71. package/dist/api/advertisement.js +4 -4
  72. package/dist/api/apps.js +4 -4
  73. package/dist/api/blog.js +6 -6
  74. package/dist/api/brands.js +6 -6
  75. package/dist/api/cart.js +6 -6
  76. package/dist/api/category.js +6 -6
  77. package/dist/api/client.js +3 -3
  78. package/dist/api/home.js +4 -4
  79. package/dist/api/loyalty.js +6 -6
  80. package/dist/api/menu.js +4 -4
  81. package/dist/api/notification.js +4 -4
  82. package/dist/api/order.js +6 -6
  83. package/dist/api/page.js +6 -6
  84. package/dist/api/product.js +6 -6
  85. package/dist/api/profile.js +3 -3
  86. package/dist/api/store.js +5 -5
  87. package/dist/api/translations.js +4 -4
  88. package/dist/api/user.js +4 -4
  89. package/dist/api/wallet.js +4 -4
  90. package/dist/api/wishlist.js +7 -7
  91. package/dist/{chunk-ELYKF67K.js → chunk-2CILV5ME.js} +5 -5
  92. package/dist/{chunk-ELYKF67K.js.map → chunk-2CILV5ME.js.map} +1 -1
  93. package/dist/{chunk-JZ54GDXO.js → chunk-2HCODIC6.js} +4 -4
  94. package/dist/{chunk-JZ54GDXO.js.map → chunk-2HCODIC6.js.map} +1 -1
  95. package/dist/{chunk-BAJBKIGI.js → chunk-2ZC5YGMI.js} +3 -3
  96. package/dist/{chunk-BAJBKIGI.js.map → chunk-2ZC5YGMI.js.map} +1 -1
  97. package/dist/{chunk-WPRJVK7K.js → chunk-34L65JGK.js} +4 -4
  98. package/dist/{chunk-WPRJVK7K.js.map → chunk-34L65JGK.js.map} +1 -1
  99. package/dist/{chunk-T2752RH7.js → chunk-4E6FD5W7.js} +60 -4
  100. package/dist/chunk-4E6FD5W7.js.map +1 -0
  101. package/dist/{chunk-M5WTY3EH.js → chunk-5EAISVPV.js} +3 -3
  102. package/dist/{chunk-M5WTY3EH.js.map → chunk-5EAISVPV.js.map} +1 -1
  103. package/dist/{chunk-5PMEGLR6.js → chunk-5LI536P6.js} +5 -5
  104. package/dist/{chunk-5PMEGLR6.js.map → chunk-5LI536P6.js.map} +1 -1
  105. package/dist/{chunk-QOC7HUYN.js → chunk-5M2AK5KE.js} +4 -4
  106. package/dist/{chunk-QOC7HUYN.js.map → chunk-5M2AK5KE.js.map} +1 -1
  107. package/dist/{chunk-33327CFA.js → chunk-5NUCGUTE.js} +4 -4
  108. package/dist/{chunk-33327CFA.js.map → chunk-5NUCGUTE.js.map} +1 -1
  109. package/dist/{chunk-3BDSQIYZ.js → chunk-5RBXCPG6.js} +3 -3
  110. package/dist/{chunk-3BDSQIYZ.js.map → chunk-5RBXCPG6.js.map} +1 -1
  111. package/dist/{chunk-6T4HGLQM.js → chunk-5T4MJAUN.js} +3 -3
  112. package/dist/{chunk-6T4HGLQM.js.map → chunk-5T4MJAUN.js.map} +1 -1
  113. package/dist/{chunk-MA3R5QON.js → chunk-6H6BVZBV.js} +3 -3
  114. package/dist/{chunk-MA3R5QON.js.map → chunk-6H6BVZBV.js.map} +1 -1
  115. package/dist/{chunk-4FFABE3P.js → chunk-6QIF6WJH.js} +3 -3
  116. package/dist/{chunk-4FFABE3P.js.map → chunk-6QIF6WJH.js.map} +1 -1
  117. package/dist/{chunk-SLBO4SEE.js → chunk-6YEE3VHL.js} +3 -3
  118. package/dist/{chunk-SLBO4SEE.js.map → chunk-6YEE3VHL.js.map} +1 -1
  119. package/dist/{chunk-XMRNYUQY.js → chunk-7XAGU6CT.js} +3 -3
  120. package/dist/{chunk-XMRNYUQY.js.map → chunk-7XAGU6CT.js.map} +1 -1
  121. package/dist/{chunk-NWQUPGB4.js → chunk-AOQZHLZZ.js} +5 -5
  122. package/dist/{chunk-NWQUPGB4.js.map → chunk-AOQZHLZZ.js.map} +1 -1
  123. package/dist/{chunk-H7LRGY7U.js → chunk-B57KIBQL.js} +3 -3
  124. package/dist/{chunk-H7LRGY7U.js.map → chunk-B57KIBQL.js.map} +1 -1
  125. package/dist/{chunk-CUURFACL.js → chunk-BYGVKW3M.js} +4 -4
  126. package/dist/{chunk-CUURFACL.js.map → chunk-BYGVKW3M.js.map} +1 -1
  127. package/dist/{chunk-T55MRK24.js → chunk-CAULDK3N.js} +6 -6
  128. package/dist/{chunk-T55MRK24.js.map → chunk-CAULDK3N.js.map} +1 -1
  129. package/dist/{chunk-EGI7F57E.js → chunk-DPQIVZ4T.js} +3 -3
  130. package/dist/{chunk-EGI7F57E.js.map → chunk-DPQIVZ4T.js.map} +1 -1
  131. package/dist/{chunk-5ABT7QLS.js → chunk-EMAAVDEK.js} +7 -7
  132. package/dist/{chunk-5ABT7QLS.js.map → chunk-EMAAVDEK.js.map} +1 -1
  133. package/dist/{chunk-DQEJV5SR.js → chunk-FCCGJ4DI.js} +7 -7
  134. package/dist/{chunk-DQEJV5SR.js.map → chunk-FCCGJ4DI.js.map} +1 -1
  135. package/dist/{chunk-ZXEJ46OF.js → chunk-FL3OK7AQ.js} +36 -16
  136. package/dist/chunk-FL3OK7AQ.js.map +1 -0
  137. package/dist/{chunk-NRMAYV4G.js → chunk-GLSRVHYJ.js} +4 -4
  138. package/dist/{chunk-NRMAYV4G.js.map → chunk-GLSRVHYJ.js.map} +1 -1
  139. package/dist/{chunk-X5W7HZNX.js → chunk-I2LK4IC2.js} +4 -4
  140. package/dist/{chunk-X5W7HZNX.js.map → chunk-I2LK4IC2.js.map} +1 -1
  141. package/dist/{chunk-LILNJBFU.js → chunk-IEKP3HYS.js} +4 -4
  142. package/dist/{chunk-LILNJBFU.js.map → chunk-IEKP3HYS.js.map} +1 -1
  143. package/dist/{chunk-IHOUADLX.js → chunk-JK45RUVV.js} +3 -3
  144. package/dist/{chunk-IHOUADLX.js.map → chunk-JK45RUVV.js.map} +1 -1
  145. package/dist/{chunk-CNTXY27A.js → chunk-JSAWLWUN.js} +4 -4
  146. package/dist/{chunk-CNTXY27A.js.map → chunk-JSAWLWUN.js.map} +1 -1
  147. package/dist/{chunk-3WA5RJGC.js → chunk-KJ7NG3ZH.js} +3 -3
  148. package/dist/{chunk-3WA5RJGC.js.map → chunk-KJ7NG3ZH.js.map} +1 -1
  149. package/dist/{chunk-W2A5AWNA.js → chunk-LBZNLTBM.js} +3 -3
  150. package/dist/{chunk-W2A5AWNA.js.map → chunk-LBZNLTBM.js.map} +1 -1
  151. package/dist/{chunk-SCWUJ5PP.js → chunk-LWAJNEIM.js} +4 -4
  152. package/dist/{chunk-SCWUJ5PP.js.map → chunk-LWAJNEIM.js.map} +1 -1
  153. package/dist/{chunk-MJHYLDXL.js → chunk-O3XMYDNC.js} +5 -5
  154. package/dist/{chunk-MJHYLDXL.js.map → chunk-O3XMYDNC.js.map} +1 -1
  155. package/dist/{chunk-HPK6GB7G.js → chunk-O63WBEAC.js} +22 -22
  156. package/dist/{chunk-HPK6GB7G.js.map → chunk-O63WBEAC.js.map} +1 -1
  157. package/dist/{chunk-KUQQJTFA.js → chunk-OOZQVX7C.js} +6 -6
  158. package/dist/{chunk-KUQQJTFA.js.map → chunk-OOZQVX7C.js.map} +1 -1
  159. package/dist/{chunk-MGG4XAJ5.js → chunk-P2PPBXHD.js} +3 -3
  160. package/dist/{chunk-MGG4XAJ5.js.map → chunk-P2PPBXHD.js.map} +1 -1
  161. package/dist/{chunk-IFKCPNDF.js → chunk-PHPOMWQ4.js} +4 -4
  162. package/dist/{chunk-IFKCPNDF.js.map → chunk-PHPOMWQ4.js.map} +1 -1
  163. package/dist/{chunk-3AIK4QGW.js → chunk-PPFD456V.js} +3 -3
  164. package/dist/{chunk-3AIK4QGW.js.map → chunk-PPFD456V.js.map} +1 -1
  165. package/dist/{chunk-CAAIQPEN.js → chunk-PVOJJ2BV.js} +7 -6
  166. package/dist/chunk-PVOJJ2BV.js.map +1 -0
  167. package/dist/{chunk-GBJK6KKM.js → chunk-PYXAPLNB.js} +3 -3
  168. package/dist/{chunk-GBJK6KKM.js.map → chunk-PYXAPLNB.js.map} +1 -1
  169. package/dist/{chunk-7R43CIG7.js → chunk-PZP3372I.js} +4 -4
  170. package/dist/{chunk-7R43CIG7.js.map → chunk-PZP3372I.js.map} +1 -1
  171. package/dist/{chunk-WH73HWTE.js → chunk-Q7Z76F7N.js} +8 -8
  172. package/dist/{chunk-WH73HWTE.js.map → chunk-Q7Z76F7N.js.map} +1 -1
  173. package/dist/{chunk-23OJW6CK.js → chunk-QKKEBQ57.js} +6 -6
  174. package/dist/{chunk-23OJW6CK.js.map → chunk-QKKEBQ57.js.map} +1 -1
  175. package/dist/{chunk-QMWP2ZP6.js → chunk-R7QCNL62.js} +3 -3
  176. package/dist/{chunk-QMWP2ZP6.js.map → chunk-R7QCNL62.js.map} +1 -1
  177. package/dist/{chunk-CXKA35FJ.js → chunk-RB7RHMKJ.js} +5 -5
  178. package/dist/{chunk-CXKA35FJ.js.map → chunk-RB7RHMKJ.js.map} +1 -1
  179. package/dist/{chunk-C7LAIXEO.js → chunk-RY6VPXG6.js} +3 -3
  180. package/dist/{chunk-C7LAIXEO.js.map → chunk-RY6VPXG6.js.map} +1 -1
  181. package/dist/{chunk-R7VWIXFX.js → chunk-TEAYGNHT.js} +3 -3
  182. package/dist/{chunk-R7VWIXFX.js.map → chunk-TEAYGNHT.js.map} +1 -1
  183. package/dist/{chunk-W3QKGF2O.js → chunk-TXYLHBUH.js} +3 -3
  184. package/dist/{chunk-W3QKGF2O.js.map → chunk-TXYLHBUH.js.map} +1 -1
  185. package/dist/{chunk-6TFM3UTF.js → chunk-ULF4LPVA.js} +3 -3
  186. package/dist/{chunk-6TFM3UTF.js.map → chunk-ULF4LPVA.js.map} +1 -1
  187. package/dist/{chunk-V6IKYNU6.js → chunk-UUHLRFXB.js} +9 -9
  188. package/dist/chunk-UUHLRFXB.js.map +1 -0
  189. package/dist/{chunk-F3QHKYS3.js → chunk-VJA4DVVT.js} +4 -4
  190. package/dist/{chunk-F3QHKYS3.js.map → chunk-VJA4DVVT.js.map} +1 -1
  191. package/dist/{chunk-JDCZWE7N.js → chunk-W7CYFPGY.js} +6 -6
  192. package/dist/{chunk-JDCZWE7N.js.map → chunk-W7CYFPGY.js.map} +1 -1
  193. package/dist/{chunk-5V4W3GBI.js → chunk-WAKCWE6P.js} +5 -5
  194. package/dist/{chunk-5V4W3GBI.js.map → chunk-WAKCWE6P.js.map} +1 -1
  195. package/dist/{chunk-R72B5P4R.js → chunk-ZUVBDALM.js} +4 -4
  196. package/dist/{chunk-R72B5P4R.js.map → chunk-ZUVBDALM.js.map} +1 -1
  197. package/dist/components/cart/index.js +1 -1
  198. package/dist/components/common/index.js +1 -1
  199. package/dist/components/drawer/index.js +23 -23
  200. package/dist/components/home/index.js +28 -28
  201. package/dist/components/layout/index.js +6 -6
  202. package/dist/components/product/ProductCard.d.ts.map +1 -1
  203. package/dist/components/product/index.js +25 -25
  204. package/dist/components/store/index.js +24 -24
  205. package/dist/components/toast/index.js +4 -4
  206. package/dist/dev/editor/index.js +2 -2
  207. package/dist/dev/index.js +2 -2
  208. package/dist/document-class-N7WF3WXG.js +33 -0
  209. package/dist/{document-class-B57F7JZW.js.map → document-class-N7WF3WXG.js.map} +1 -1
  210. package/dist/hooks/index.js +23 -23
  211. package/dist/hooks/useComments.js +3 -3
  212. package/dist/hooks/useGtm.js +23 -23
  213. package/dist/hooks/useMoney.js +23 -23
  214. package/dist/hooks/useProduct.js +3 -3
  215. package/dist/hooks/useStore.js +23 -23
  216. package/dist/hooks/useUser.js +5 -5
  217. package/dist/hooks/useWishlist.js +3 -3
  218. package/dist/index.js +23 -23
  219. package/dist/native-app/index.js +3 -3
  220. package/dist/{navigation-N3WBAE74.js → navigation-5DPDZQUU.js} +8 -8
  221. package/dist/{navigation-N3WBAE74.js.map → navigation-5DPDZQUU.js.map} +1 -1
  222. package/dist/{navigation-VJBIYPFD.js → navigation-FRKMKNLK.js} +7 -7
  223. package/dist/{navigation-VJBIYPFD.js.map → navigation-FRKMKNLK.js.map} +1 -1
  224. package/dist/{not-found-KDDMHTAU.js → not-found-4U2TRCLF.js} +26 -26
  225. package/dist/{not-found-KDDMHTAU.js.map → not-found-4U2TRCLF.js.map} +1 -1
  226. package/dist/providers/index.js +23 -23
  227. package/dist/routes/account/orders.js +8 -8
  228. package/dist/routes/account.js +17 -17
  229. package/dist/routes/blog.js +12 -12
  230. package/dist/routes/brands.js +8 -8
  231. package/dist/routes/cart.js +32 -32
  232. package/dist/routes/home.js +29 -29
  233. package/dist/routes/index.js +6 -6
  234. package/dist/routes/loyalty.js +9 -9
  235. package/dist/routes/page.js +8 -8
  236. package/dist/routes/product-listing.js +33 -33
  237. package/dist/routes/product.js +28 -28
  238. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  239. package/dist/routes/seo-redirects.js +6 -6
  240. package/dist/routes/testimonials.js +4 -4
  241. package/dist/routes/thank-you.js +8 -8
  242. package/dist/skeleton.js +29 -29
  243. package/dist/{store-lookup-WBKOYMDU.js → store-lookup-S6JUSKNH.js} +11 -11
  244. package/dist/{store-lookup-WBKOYMDU.js.map → store-lookup-S6JUSKNH.js.map} +1 -1
  245. package/dist/tanstack.js +20 -20
  246. package/dist/utils/baseHead.js +2 -2
  247. package/dist/utils/index.js +6 -6
  248. package/dist/utils/shared-host-language.d.ts +5 -0
  249. package/dist/utils/shared-host-language.d.ts.map +1 -1
  250. package/dist/utils/store-base.d.ts +60 -0
  251. package/dist/utils/store-base.d.ts.map +1 -1
  252. package/dist/utils/store-identity.d.ts +14 -0
  253. package/dist/utils/store-identity.d.ts.map +1 -1
  254. package/dist/vite/index.js +3 -3
  255. package/package.json +1 -1
  256. package/tailwind/components/home/FixedProducts.tsx.txt +2 -2
  257. package/tailwind/components/product/ProductCard.tsx.txt +2 -1
  258. package/tailwind/routes/root/beforeLoad.ts.txt +37 -3
  259. package/dist/chunk-CAAIQPEN.js.map +0 -1
  260. package/dist/chunk-T2752RH7.js.map +0 -1
  261. package/dist/chunk-V6IKYNU6.js.map +0 -1
  262. package/dist/chunk-ZXEJ46OF.js.map +0 -1
  263. package/dist/document-class-B57F7JZW.js +0 -33
package/dist/skeleton.js CHANGED
@@ -1,53 +1,53 @@
1
1
  export { BlogSkeleton, BreadcrumbSkeleton, CartSkeleton, CustomerLayoutSkeleton, CustomerPageSkeleton, PageSkeleton, ProductCardSkeleton, ProductDetailSkeleton, ProductGridSkeleton, SkeletonPulse } from './chunk-N7CCSGZF.js';
2
- export { HomeSkeleton } from './chunk-JDCZWE7N.js';
2
+ export { HomeSkeleton } from './chunk-W7CYFPGY.js';
3
3
  import './chunk-IXHM24Z4.js';
4
- import './chunk-V6IKYNU6.js';
5
- import './chunk-W3QKGF2O.js';
6
- import './chunk-R72B5P4R.js';
7
- import './chunk-T55MRK24.js';
8
- import './chunk-CAAIQPEN.js';
4
+ import './chunk-UUHLRFXB.js';
5
+ import './chunk-TXYLHBUH.js';
6
+ import './chunk-ZUVBDALM.js';
7
+ import './chunk-CAULDK3N.js';
8
+ import './chunk-PVOJJ2BV.js';
9
9
  import './chunk-Y32RHCOH.js';
10
- import './chunk-HPK6GB7G.js';
10
+ import './chunk-O63WBEAC.js';
11
11
  import './chunk-Q77J3D2W.js';
12
- import './chunk-5ABT7QLS.js';
13
- import './chunk-6T4HGLQM.js';
14
- import './chunk-5V4W3GBI.js';
12
+ import './chunk-EMAAVDEK.js';
13
+ import './chunk-5T4MJAUN.js';
14
+ import './chunk-WAKCWE6P.js';
15
15
  import './chunk-X55R4VVK.js';
16
16
  import './chunk-YL6X3ZMG.js';
17
- import './chunk-LILNJBFU.js';
17
+ import './chunk-IEKP3HYS.js';
18
18
  import './chunk-OXMUPNMH.js';
19
- import './chunk-3BDSQIYZ.js';
19
+ import './chunk-5RBXCPG6.js';
20
20
  import './chunk-VVZNW5CB.js';
21
- import './chunk-EGI7F57E.js';
21
+ import './chunk-DPQIVZ4T.js';
22
22
  import './chunk-GD26FI4J.js';
23
- import './chunk-SLBO4SEE.js';
24
- import './chunk-MGG4XAJ5.js';
25
- import './chunk-MJHYLDXL.js';
23
+ import './chunk-6YEE3VHL.js';
24
+ import './chunk-P2PPBXHD.js';
25
+ import './chunk-O3XMYDNC.js';
26
26
  import './chunk-OUW6WESU.js';
27
- import './chunk-IHOUADLX.js';
27
+ import './chunk-JK45RUVV.js';
28
28
  import './chunk-HI5V5X3S.js';
29
- import './chunk-BAJBKIGI.js';
30
- import './chunk-GBJK6KKM.js';
29
+ import './chunk-2ZC5YGMI.js';
30
+ import './chunk-PYXAPLNB.js';
31
31
  import './chunk-6T55LXJL.js';
32
32
  import './chunk-Z653O7MX.js';
33
33
  import './chunk-ZCH7W7DZ.js';
34
- import './chunk-H7LRGY7U.js';
34
+ import './chunk-B57KIBQL.js';
35
35
  import './chunk-JWXJPJBO.js';
36
36
  import './chunk-CW625T2E.js';
37
37
  import './chunk-7V36I5GT.js';
38
38
  import './chunk-6WI7R2BD.js';
39
- import './chunk-M5WTY3EH.js';
39
+ import './chunk-5EAISVPV.js';
40
40
  import './chunk-OAMIDZKW.js';
41
- import './chunk-CUURFACL.js';
41
+ import './chunk-BYGVKW3M.js';
42
42
  import './chunk-OQIIJRAS.js';
43
43
  import './chunk-V2ZDTY6H.js';
44
- import './chunk-3AIK4QGW.js';
44
+ import './chunk-PPFD456V.js';
45
45
  import './chunk-5XDPAKF5.js';
46
46
  import './chunk-GCPEMNSU.js';
47
- import './chunk-CXKA35FJ.js';
47
+ import './chunk-RB7RHMKJ.js';
48
48
  import './chunk-Z5M4YYWT.js';
49
49
  import './chunk-TYNZ5B2B.js';
50
- import './chunk-W2A5AWNA.js';
50
+ import './chunk-LBZNLTBM.js';
51
51
  import './chunk-AXW67SY7.js';
52
52
  import './chunk-BYMOPN2S.js';
53
53
  import './chunk-SKLEJJ6M.js';
@@ -55,10 +55,10 @@ import './chunk-6BZ5TKEV.js';
55
55
  import './chunk-FZKRSGLP.js';
56
56
  import './chunk-KYMWEUN2.js';
57
57
  import './chunk-YA6ABQB7.js';
58
- import './chunk-QMWP2ZP6.js';
59
- import './chunk-6TFM3UTF.js';
60
- import './chunk-XMRNYUQY.js';
61
- import './chunk-T2752RH7.js';
58
+ import './chunk-R7QCNL62.js';
59
+ import './chunk-ULF4LPVA.js';
60
+ import './chunk-7XAGU6CT.js';
61
+ import './chunk-4E6FD5W7.js';
62
62
  import './chunk-6K34BCUP.js';
63
63
  import './chunk-T72DAX7R.js';
64
64
  import './chunk-DF6FBKDN.js';
@@ -1,15 +1,15 @@
1
- import { category } from './chunk-33327CFA.js';
2
- import { blog } from './chunk-WPRJVK7K.js';
3
- import { brand } from './chunk-CNTXY27A.js';
4
- import { product } from './chunk-R72B5P4R.js';
1
+ import { category } from './chunk-5NUCGUTE.js';
2
+ import { blog } from './chunk-34L65JGK.js';
3
+ import { brand } from './chunk-JSAWLWUN.js';
4
+ import { product } from './chunk-ZUVBDALM.js';
5
5
  import { DEV_LOOKUP_BUDGET_MS } from './chunk-OXMUPNMH.js';
6
- import './chunk-MJHYLDXL.js';
6
+ import './chunk-O3XMYDNC.js';
7
7
  import './chunk-OUW6WESU.js';
8
- import './chunk-CXKA35FJ.js';
8
+ import './chunk-RB7RHMKJ.js';
9
9
  import './chunk-Z5M4YYWT.js';
10
- import './chunk-6TFM3UTF.js';
11
- import './chunk-XMRNYUQY.js';
12
- import './chunk-T2752RH7.js';
10
+ import './chunk-ULF4LPVA.js';
11
+ import './chunk-7XAGU6CT.js';
12
+ import './chunk-4E6FD5W7.js';
13
13
  import './chunk-6K34BCUP.js';
14
14
  import './chunk-T72DAX7R.js';
15
15
  import './chunk-DF6FBKDN.js';
@@ -111,5 +111,5 @@ function lookupInStore(source, query) {
111
111
  }
112
112
 
113
113
  export { lookupInStore };
114
- //# sourceMappingURL=store-lookup-WBKOYMDU.js.map
115
- //# sourceMappingURL=store-lookup-WBKOYMDU.js.map
114
+ //# sourceMappingURL=store-lookup-S6JUSKNH.js.map
115
+ //# sourceMappingURL=store-lookup-S6JUSKNH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev/store-lookup.ts"],"names":["categories"],"mappings":"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","file":"store-lookup-WBKOYMDU.js","sourcesContent":["/**\n * Runs in the editor's frame (the storefront), which has the engine's API\n * client set up for the dev store: answers the editor's pickers with the real\n * store's products, categories, brands and blog. Loaded with `import()` on the\n * first lookup, so a storefront never carries it.\n *\n * Each item's `data` is what a block receives for it, in the API's shape: a\n * product block reads only the ids and fetches the rest, while categories and\n * brands are drawn from what is saved.\n */\n\nimport { product } from '../api/product';\nimport { category } from '../api/category';\nimport { brand } from '../api/brands';\nimport { blog } from '../api/blog';\nimport type { Category } from '../types';\nimport { DEV_LOOKUP_BUDGET_MS, type DevLookupItem, type DevLookupSource } from './schema-types';\n\n/** Enough to choose from; a search narrows it further. */\nconst PER_PAGE = 20;\n/** How far a paged list is searched before giving up, so a big store can't stall the picker. */\nconst MAX_PAGES = 10;\n\ninterface Page<T> {\n items: T[];\n next: string | null;\n}\n\n/**\n * The matching items of a paged list, read page after page until there are\n * enough, the pages run out, or the time budget is spent: a brand or article on\n * page three is still found, and what was found so far always reaches the\n * editor before it stops waiting (`DEV_LOOKUP_BUDGET_MS` < its timeout).\n */\nasync function collect<T>(\n fetchPage: (page: number, cursor: string | null) => Promise<Page<T>>,\n keep: (item: T) => boolean\n): Promise<T[]> {\n const deadline = Date.now() + DEV_LOOKUP_BUDGET_MS;\n const found: T[] = [];\n let cursor: string | null = null;\n for (let page = 1; page <= MAX_PAGES; page += 1) {\n const { items, next } = await fetchPage(page, cursor);\n found.push(...items.filter(keep));\n if (found.length >= PER_PAGE || !next || Date.now() >= deadline) break;\n cursor = next;\n }\n return found.slice(0, PER_PAGE);\n}\n\nfunction matches(name: string, query: string): boolean {\n return !query || name.toLowerCase().includes(query.toLowerCase());\n}\n\n/** Categories with their subcategories, flattened, parents first. */\nfunction flatten(categories: Category[]): Category[] {\n return categories.flatMap((c) => [c, ...flatten(c.sub_categories ?? [])]);\n}\n\nasync function products(query: string): Promise<DevLookupItem[]> {\n const { items } = await product.list({\n source: query ? 'search' : 'latest',\n ...(query ? { keyword: query } : {}),\n perPage: PER_PAGE,\n });\n // List responses send the id as a numeric string; the block reads a number. Use it for both.\n return items.map((p) => ({\n id: Number(p.id),\n name: p.name,\n image: p.image?.url,\n url: p.url,\n data: { id: Number(p.id), name: p.name, url: p.url, image: p.image?.url ?? null },\n }));\n}\n\nasync function categories(query: string): Promise<DevLookupItem[]> {\n return flatten(await category.list())\n .filter((c) => matches(c.name, query))\n .slice(0, PER_PAGE)\n .map((c) => ({\n id: c.id,\n name: c.name,\n image: c.image ?? undefined,\n url: c.url,\n data: { id: c.id, name: c.name, url: c.url, image: c.image ?? null, icon: c.icon ?? null },\n }));\n}\n\nasync function brands(query: string): Promise<DevLookupItem[]> {\n const found = await collect(\n (page) => brand.list(page),\n (b) => matches(b.name, query)\n );\n return found.map((b) => ({\n id: b.id,\n name: b.name,\n image: b.logo,\n url: b.url,\n data: { id: b.id, name: b.name, url: b.url, logo: b.logo, banner: b.banner ?? null },\n }));\n}\n\nasync function blogArticles(query: string): Promise<DevLookupItem[]> {\n const found = await collect(\n async (_page, cursor) => {\n const { data, cursor: pages } = await blog.articles.list(cursor ? { cursor } : undefined);\n return { items: data, next: pages?.next ?? null };\n },\n (a) => matches(a.name, query)\n );\n return found.map((a) => ({\n id: a.id,\n name: a.name,\n image: a.image,\n url: a.url,\n data: { id: a.id, name: a.name, url: a.url },\n }));\n}\n\nasync function blogCategories(query: string): Promise<DevLookupItem[]> {\n const { categories: list } = await blog.get();\n return list\n .filter((c) => matches(c.name, query))\n .slice(0, PER_PAGE)\n .map((c) => ({\n id: c.id,\n name: c.name,\n url: c.url,\n data: { id: c.id, name: c.name, url: c.url },\n }));\n}\n\nconst LOOKUPS: Record<DevLookupSource, (query: string) => Promise<DevLookupItem[]>> = {\n products,\n categories,\n brands,\n blog_articles: blogArticles,\n blog_categories: blogCategories,\n};\n\nexport function lookupInStore(source: DevLookupSource, query: string): Promise<DevLookupItem[]> {\n const lookup = LOOKUPS[source];\n if (!lookup) return Promise.reject(new Error(`no lookup for ${source}`));\n return lookup(query.trim());\n}\n"]}
1
+ {"version":3,"sources":["../src/dev/store-lookup.ts"],"names":["categories"],"mappings":"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","file":"store-lookup-S6JUSKNH.js","sourcesContent":["/**\n * Runs in the editor's frame (the storefront), which has the engine's API\n * client set up for the dev store: answers the editor's pickers with the real\n * store's products, categories, brands and blog. Loaded with `import()` on the\n * first lookup, so a storefront never carries it.\n *\n * Each item's `data` is what a block receives for it, in the API's shape: a\n * product block reads only the ids and fetches the rest, while categories and\n * brands are drawn from what is saved.\n */\n\nimport { product } from '../api/product';\nimport { category } from '../api/category';\nimport { brand } from '../api/brands';\nimport { blog } from '../api/blog';\nimport type { Category } from '../types';\nimport { DEV_LOOKUP_BUDGET_MS, type DevLookupItem, type DevLookupSource } from './schema-types';\n\n/** Enough to choose from; a search narrows it further. */\nconst PER_PAGE = 20;\n/** How far a paged list is searched before giving up, so a big store can't stall the picker. */\nconst MAX_PAGES = 10;\n\ninterface Page<T> {\n items: T[];\n next: string | null;\n}\n\n/**\n * The matching items of a paged list, read page after page until there are\n * enough, the pages run out, or the time budget is spent: a brand or article on\n * page three is still found, and what was found so far always reaches the\n * editor before it stops waiting (`DEV_LOOKUP_BUDGET_MS` < its timeout).\n */\nasync function collect<T>(\n fetchPage: (page: number, cursor: string | null) => Promise<Page<T>>,\n keep: (item: T) => boolean\n): Promise<T[]> {\n const deadline = Date.now() + DEV_LOOKUP_BUDGET_MS;\n const found: T[] = [];\n let cursor: string | null = null;\n for (let page = 1; page <= MAX_PAGES; page += 1) {\n const { items, next } = await fetchPage(page, cursor);\n found.push(...items.filter(keep));\n if (found.length >= PER_PAGE || !next || Date.now() >= deadline) break;\n cursor = next;\n }\n return found.slice(0, PER_PAGE);\n}\n\nfunction matches(name: string, query: string): boolean {\n return !query || name.toLowerCase().includes(query.toLowerCase());\n}\n\n/** Categories with their subcategories, flattened, parents first. */\nfunction flatten(categories: Category[]): Category[] {\n return categories.flatMap((c) => [c, ...flatten(c.sub_categories ?? [])]);\n}\n\nasync function products(query: string): Promise<DevLookupItem[]> {\n const { items } = await product.list({\n source: query ? 'search' : 'latest',\n ...(query ? { keyword: query } : {}),\n perPage: PER_PAGE,\n });\n // List responses send the id as a numeric string; the block reads a number. Use it for both.\n return items.map((p) => ({\n id: Number(p.id),\n name: p.name,\n image: p.image?.url,\n url: p.url,\n data: { id: Number(p.id), name: p.name, url: p.url, image: p.image?.url ?? null },\n }));\n}\n\nasync function categories(query: string): Promise<DevLookupItem[]> {\n return flatten(await category.list())\n .filter((c) => matches(c.name, query))\n .slice(0, PER_PAGE)\n .map((c) => ({\n id: c.id,\n name: c.name,\n image: c.image ?? undefined,\n url: c.url,\n data: { id: c.id, name: c.name, url: c.url, image: c.image ?? null, icon: c.icon ?? null },\n }));\n}\n\nasync function brands(query: string): Promise<DevLookupItem[]> {\n const found = await collect(\n (page) => brand.list(page),\n (b) => matches(b.name, query)\n );\n return found.map((b) => ({\n id: b.id,\n name: b.name,\n image: b.logo,\n url: b.url,\n data: { id: b.id, name: b.name, url: b.url, logo: b.logo, banner: b.banner ?? null },\n }));\n}\n\nasync function blogArticles(query: string): Promise<DevLookupItem[]> {\n const found = await collect(\n async (_page, cursor) => {\n const { data, cursor: pages } = await blog.articles.list(cursor ? { cursor } : undefined);\n return { items: data, next: pages?.next ?? null };\n },\n (a) => matches(a.name, query)\n );\n return found.map((a) => ({\n id: a.id,\n name: a.name,\n image: a.image,\n url: a.url,\n data: { id: a.id, name: a.name, url: a.url },\n }));\n}\n\nasync function blogCategories(query: string): Promise<DevLookupItem[]> {\n const { categories: list } = await blog.get();\n return list\n .filter((c) => matches(c.name, query))\n .slice(0, PER_PAGE)\n .map((c) => ({\n id: c.id,\n name: c.name,\n url: c.url,\n data: { id: c.id, name: c.name, url: c.url },\n }));\n}\n\nconst LOOKUPS: Record<DevLookupSource, (query: string) => Promise<DevLookupItem[]>> = {\n products,\n categories,\n brands,\n blog_articles: blogArticles,\n blog_categories: blogCategories,\n};\n\nexport function lookupInStore(source: DevLookupSource, query: string): Promise<DevLookupItem[]> {\n const lookup = LOOKUPS[source];\n if (!lookup) return Promise.reject(new Error(`no lookup for ${source}`));\n return lookup(query.trim());\n}\n"]}
package/dist/tanstack.js CHANGED
@@ -1,33 +1,33 @@
1
- export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-ZXEJ46OF.js';
2
- import { requestHostOf } from './chunk-23OJW6CK.js';
3
- export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-23OJW6CK.js';
1
+ export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-FL3OK7AQ.js';
2
+ import { requestHostOf } from './chunk-QKKEBQ57.js';
3
+ export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-QKKEBQ57.js';
4
4
  import './chunk-Z4Y55HWX.js';
5
- export { tanstackHeadAdapter as head, withHead } from './chunk-R7VWIXFX.js';
5
+ export { tanstackHeadAdapter as head, withHead } from './chunk-TEAYGNHT.js';
6
6
  import { CRITICAL_STYLE_HREF } from './chunk-4FJGZQD3.js';
7
- import { readNativeAppHeaders } from './chunk-KUQQJTFA.js';
8
- import './chunk-3WA5RJGC.js';
9
- import './chunk-5PMEGLR6.js';
10
- import './chunk-7R43CIG7.js';
11
- import './chunk-R72B5P4R.js';
12
- import { rootHead } from './chunk-5V4W3GBI.js';
7
+ import { readNativeAppHeaders } from './chunk-OOZQVX7C.js';
8
+ import './chunk-KJ7NG3ZH.js';
9
+ import './chunk-5LI536P6.js';
10
+ import './chunk-PZP3372I.js';
11
+ import './chunk-ZUVBDALM.js';
12
+ import { rootHead } from './chunk-WAKCWE6P.js';
13
13
  import './chunk-X55R4VVK.js';
14
- import './chunk-3BDSQIYZ.js';
15
- import './chunk-EGI7F57E.js';
14
+ import './chunk-5RBXCPG6.js';
15
+ import './chunk-DPQIVZ4T.js';
16
16
  import './chunk-GD26FI4J.js';
17
- import { maintenanceEvidence, MAINTENANCE_EVIDENCE_HEADER, maintenanceEvidenceHeader } from './chunk-SLBO4SEE.js';
18
- import './chunk-MGG4XAJ5.js';
19
- import './chunk-MJHYLDXL.js';
17
+ import { maintenanceEvidence, MAINTENANCE_EVIDENCE_HEADER, maintenanceEvidenceHeader } from './chunk-6YEE3VHL.js';
18
+ import './chunk-P2PPBXHD.js';
19
+ import './chunk-O3XMYDNC.js';
20
20
  import './chunk-OUW6WESU.js';
21
21
  import './chunk-JWXJPJBO.js';
22
22
  export { mergeDocumentDescriptors as mergeAttrs } from './chunk-CW625T2E.js';
23
- import './chunk-3AIK4QGW.js';
24
- import './chunk-CXKA35FJ.js';
23
+ import './chunk-PPFD456V.js';
24
+ import './chunk-RB7RHMKJ.js';
25
25
  import './chunk-Z5M4YYWT.js';
26
26
  import './chunk-TYNZ5B2B.js';
27
27
  import './chunk-BYMOPN2S.js';
28
- import './chunk-6TFM3UTF.js';
29
- import './chunk-XMRNYUQY.js';
30
- import { AUTH_TOKEN_COOKIE_NAME, extractTokenFromCookies, resolveRequestScope, resolveAddressedStore, STORE_BASE_HEADER, resolveRequestVersionId, legacyLocaleRedirectHref } from './chunk-T2752RH7.js';
28
+ import './chunk-ULF4LPVA.js';
29
+ import './chunk-7XAGU6CT.js';
30
+ import { AUTH_TOKEN_COOKIE_NAME, extractTokenFromCookies, resolveRequestScope, resolveAddressedStore, STORE_BASE_HEADER, resolveRequestVersionId, legacyLocaleRedirectHref } from './chunk-4E6FD5W7.js';
31
31
  import { runWithTwilightContext, getTwilightContext } from './chunk-6K34BCUP.js';
32
32
  export { getTwilightContext, runWithTwilightContext, updateTwilightContext } from './chunk-6K34BCUP.js';
33
33
  import './chunk-T72DAX7R.js';
@@ -1,5 +1,5 @@
1
- export { buildBaseHead, buildHreflangAlternates, localeToOgLocale, storePageUrl } from '../chunk-MGG4XAJ5.js';
2
- import '../chunk-T2752RH7.js';
1
+ export { buildBaseHead, buildHreflangAlternates, localeToOgLocale, storePageUrl } from '../chunk-P2PPBXHD.js';
2
+ import '../chunk-4E6FD5W7.js';
3
3
  import '../chunk-6K34BCUP.js';
4
4
  import '../chunk-T72DAX7R.js';
5
5
  import '../chunk-DGUM43GV.js';
@@ -1,17 +1,17 @@
1
1
  export { stripUnsafeHtml } from '../chunk-RUHSV4Z6.js';
2
2
  export { formatSallaPlural } from '../chunk-BT6HEEAP.js';
3
- export { dispatchRouteChanged } from '../chunk-7R43CIG7.js';
3
+ export { dispatchRouteChanged } from '../chunk-PZP3372I.js';
4
4
  export { sortOptions } from '../chunk-3LZJXKVO.js';
5
5
  export { color } from '../chunk-VVZNW5CB.js';
6
- export { applyAppScopeMocks, registerThemeHookSlots } from '../chunk-EGI7F57E.js';
6
+ export { applyAppScopeMocks, registerThemeHookSlots } from '../chunk-DPQIVZ4T.js';
7
7
  export { mergeHead, resolveHead, setHeadAdapter } from '../chunk-GD26FI4J.js';
8
- export { buildBaseHead, buildHreflangAlternates, localeToOgLocale } from '../chunk-MGG4XAJ5.js';
8
+ export { buildBaseHead, buildHreflangAlternates, localeToOgLocale } from '../chunk-P2PPBXHD.js';
9
9
  export { asset, cdn, isPlaceholder } from '../chunk-ZCH7W7DZ.js';
10
10
  export { mergeDocumentDescriptors, mergeElementAttrs, normalizeClasses, syncAttrsToElement, toReactProps } from '../chunk-CW625T2E.js';
11
- import '../chunk-CXKA35FJ.js';
11
+ import '../chunk-RB7RHMKJ.js';
12
12
  import '../chunk-Z5M4YYWT.js';
13
- export { getSallaSDK, getStoreIdentifier, onSallaEvent, whenSallaLoaded, whenSallaReady } from '../chunk-XMRNYUQY.js';
14
- export { AUTH_TOKEN_COOKIE_NAME, clearAuthTokenCookie, extractTokenFromCookies } from '../chunk-T2752RH7.js';
13
+ export { getSallaSDK, getStoreIdentifier, onSallaEvent, whenSallaLoaded, whenSallaReady } from '../chunk-7XAGU6CT.js';
14
+ export { AUTH_TOKEN_COOKIE_NAME, clearAuthTokenCookie, extractTokenFromCookies } from '../chunk-4E6FD5W7.js';
15
15
  import '../chunk-6K34BCUP.js';
16
16
  import '../chunk-T72DAX7R.js';
17
17
  import '../chunk-DGUM43GV.js';
@@ -14,6 +14,11 @@ import type { StoreContext } from '../api/store';
14
14
  export declare function hasLanguageParam(search: string): boolean;
15
15
  /** The language the `s-lang` cookie remembers, if it is a known one. */
16
16
  export declare function languageFromCookies(cookieHeader: string | null): string | null;
17
+ /**
18
+ * The language the visitor chose on a shared host: `?lang=`, then the `s-lang` cookie. Null when
19
+ * neither names a language the engine knows, which is when {@link virtualLocale} falls back.
20
+ */
21
+ export declare function chosenLocale(search: string, cookieHeader: string | null): string | null;
17
22
  /**
18
23
  * The language a request on a shared host is for, before the store's settings are known:
19
24
  * `?lang=`, then the `s-lang` cookie, then {@link FALLBACK_LOCALE}. Each must be a language
@@ -1 +1 @@
1
- {"version":3,"file":"shared-host-language.d.ts","sourceRoot":"","sources":["../../src/utils/shared-host-language.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA2BjD,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEjF;AAUD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGtF;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAOrE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,CAMxE;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAOvE;AAED,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4GAA4G;IAC5G,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,kBAAkB,CAyBrB"}
1
+ {"version":3,"file":"shared-host-language.d.ts","sourceRoot":"","sources":["../../src/utils/shared-host-language.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA2BjD,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAE9E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAEvF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEjF;AAUD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGtF;AAED,uGAAuG;AACvG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAOrE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,CAMxE;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAOvE;AAED,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4GAA4G;IAC5G,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GAAG,kBAAkB,CAyBrB"}
@@ -129,6 +129,66 @@ export declare function stoppedDomainRedirectHref(args: {
129
129
  storeUrl: string | null | undefined;
130
130
  username: string | null | undefined;
131
131
  }): string | null;
132
+ /**
133
+ * The hosts where Twig serves a store at its username even when the store has a domain of its own,
134
+ * because `checkUsername` takes every request there for a preview: its preview host
135
+ * (`salla.app.preview_domain`) and its template host (`salla.app.template_domain`).
136
+ */
137
+ export declare const TWIG_PREVIEW_HOSTS: readonly string[];
138
+ /**
139
+ * The lowest `cf-bot-score` Twig takes for a person's: `checkUsername` treats a lower score as a
140
+ * bot's, and a request without the header as a score of 0.
141
+ */
142
+ export declare const HUMAN_BOT_SCORE = 11;
143
+ /** Where {@link ownDomainRedirect} sends a request, and with which status. */
144
+ export interface OwnDomainRedirect {
145
+ href: string;
146
+ statusCode: 301 | 307;
147
+ }
148
+ /**
149
+ * Where a page on a Salla shared host sends a shopper when its store is served on a domain of its
150
+ * own, as Twig's `checkUsername` does: `salla.sa/diamondneedles/cart?x=1` →
151
+ * `https://d-needles.com/cart?x=1`. Null for any other request.
152
+ *
153
+ * The settings already say it. Core builds `store.url` (`isUrlWithoutDomain`) as
154
+ * `https://salla.sa/<username>/` for a basic-plan store and for a store whose domain is not
155
+ * active, and otherwise as its own domain: its market's domain when it has markets, followed by a
156
+ * language when it is multilingual (`https://sa.reefperfumes.com/ar/`). A `store.url` whose path
157
+ * is at most a language, on another host, is therefore the address of a store that is not on the
158
+ * basic plan and has an active domain, which is what `checkUsername` checks. The plan (`ray`) is
159
+ * not read: Twig sends a store with no plan to its domain too.
160
+ *
161
+ * - **Where:** only on a request the dispatcher named its store for, by the username in the path
162
+ * of a shared host (`x-salla-store-base`). Never on the preview host or a dev server, and never on
163
+ * Twig's preview hosts ({@link TWIG_PREVIEW_HOSTS}). A store's own host is the store, so a
164
+ * request there is never sent to another of its hosts (a market's domain, the `www.` address),
165
+ * which Twig serves too.
166
+ * - **The address:** the target's origin, then the page's path without the username, then its
167
+ * query. Like Twig's, it carries no language, except one the shopper chose (`locale`: `?lang=` or
168
+ * the `s-lang` cookie) that the store offers and that is not its default. That one goes in front
169
+ * of the path (`?lang=en` becomes `/en/…`), because only a shared host reads the parameter.
170
+ * - **The status:** 301, but 307 for a person's home page (`cf-bot-score` {@link HUMAN_BOT_SCORE}
171
+ * or more), as Twig answers. A browser keeps a 301 for good, and the home page is the address a
172
+ * shopper comes back to if the merchant drops the domain. A request without a score counts as a
173
+ * bot's, as in Twig.
174
+ *
175
+ * `href` is the router's own href: a virtual language in front of the path and no store segment
176
+ * (`/ar/cart?x=1`). The router keeps it percent-encoded, so the result is safe to put in a
177
+ * `Location` header.
178
+ */
179
+ export declare function ownDomainRedirect(args: {
180
+ host: string | null | undefined;
181
+ /** The store segment the dispatcher named on a shared host, or null when it named none. */
182
+ sharedHostBase: string | null;
183
+ storeUrl: string | null | undefined;
184
+ href: string;
185
+ /** The language the shopper chose, or null when they chose none. */
186
+ locale: string | null;
187
+ /** The languages the store offers, or null when its settings do not list them. */
188
+ offeredLocales: readonly string[] | null;
189
+ defaultLocale: string | null;
190
+ botScore: number | null;
191
+ }): OwnDomainRedirect | null;
132
192
  /**
133
193
  * Where to send a guest who opened a customer-only page: the locale's home with
134
194
  * `intended_to`, which the SDK reads to open the login modal and come back after.
@@ -1 +1 @@
1
- {"version":3,"file":"store-base.d.ts","sourceRoot":"","sources":["../../src/utils/store-base.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,MAAM,CAY5F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAOnF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,UAAQ,GAAG,MAAM,CAYzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBjF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAMT;AAUD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,GAAG,IAAI,CAShB;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,qFAAqF;IACrF,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACrC,GAAG,MAAM,GAAG,IAAI,CAgBhB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,GAAG,MAAM,GAAG,IAAI,CAUhB"}
1
+ {"version":3,"file":"store-base.d.ts","sourceRoot":"","sources":["../../src/utils/store-base.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { type OwnDomainRedirect } from './store-base';
2
+ import type { StoreContext } from '../api/store';
1
3
  import type { Store } from '../types';
2
4
  /**
3
5
  * Which store to ask about, in the order the answers can be trusted.
@@ -87,4 +89,16 @@ export declare function resolveStoreBaseRedirect(username: string | null | undef
87
89
  * @param store - the store the settings were answered for
88
90
  */
89
91
  export declare function resolveStoppedDomainRedirect(store: Store | null | undefined): string | null;
92
+ /**
93
+ * The store's own domain, when this request reached a store served there by its username on a
94
+ * Salla shared host; null otherwise. See `ownDomainRedirect` for the rules.
95
+ *
96
+ * @param settings - the settings the request loaded
97
+ * @param href - the router's own href for the page, without any store segment
98
+ * @param request - the request's `Cookie` header (for `s-lang`) and its `cf-bot-score`
99
+ */
100
+ export declare function resolveOwnDomainRedirect(settings: StoreContext, href: string, request: {
101
+ cookieHeader: string | null;
102
+ botScore: number | null;
103
+ }): OwnDomainRedirect | null;
90
104
  //# sourceMappingURL=store-identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store-identity.d.ts","sourceRoot":"","sources":["../../src/utils/store-identity.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBhE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAUhD;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAOvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAI3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAOf;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQ3F"}
1
+ {"version":3,"file":"store-identity.d.ts","sourceRoot":"","sources":["../../src/utils/store-identity.ts"],"names":[],"mappings":"AAsBA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBhE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAUhD;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAOvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAI3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAOf;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQ3F;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAChE,iBAAiB,GAAG,IAAI,CAY1B"}
@@ -1,13 +1,13 @@
1
1
  import { validateTwilightManifest } from '../chunk-X5NK4TZH.js';
2
2
  export { REACT_THEME_TYPE, describeThemeTypeIssue, getThemeType, isReactThemeManifest, validateTwilightManifest } from '../chunk-X5NK4TZH.js';
3
- import { tanstackHeadAdapter } from '../chunk-R7VWIXFX.js';
3
+ import { tanstackHeadAdapter } from '../chunk-TEAYGNHT.js';
4
4
  import { nextjsHeadAdapter } from '../chunk-HOSHJBPS.js';
5
5
  import '../chunk-X55R4VVK.js';
6
6
  import { EMPTY_DEV_SCHEMA, DEV_PREVIEW_GLOBAL, DEV_PREVIEW_ENDPOINT, normalizePreviewState, DEV_PREVIEW_EVENT, DEV_EDITOR_PATH, DEV_PREVIEW_IMAGE_ENDPOINT, DEV_PREVIEW_IMAGE_MAX_BYTES } from '../chunk-OXMUPNMH.js';
7
7
  import { setHeadAdapter } from '../chunk-GD26FI4J.js';
8
- import '../chunk-MGG4XAJ5.js';
8
+ import '../chunk-P2PPBXHD.js';
9
9
  import { RouteId } from '../chunk-OUW6WESU.js';
10
- import '../chunk-T2752RH7.js';
10
+ import '../chunk-4E6FD5W7.js';
11
11
  import '../chunk-6K34BCUP.js';
12
12
  import '../chunk-T72DAX7R.js';
13
13
  import '../chunk-DGUM43GV.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salla.sa/twilight-theme-engine",
3
- "version": "1.0.148",
3
+ "version": "1.0.150",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -29,8 +29,8 @@ export function FixedProducts({ data }: FixedProductsProps) {
29
29
  // isn't a positive whole number falls back to what the API returns.
30
30
  const parsedLimit = Number(data.limit);
31
31
  const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? parsedLimit : undefined;
32
- // Matches Twig Raed: `theme.settings.get('vertical_fixed_products', true)`.
33
- const isVertical = data.isVertical ?? theme.settings.vertical_fixed_products ?? true;
32
+ // As Twig Raed, the merchant's switch decides: the API sends `isVertical: true` regardless.
33
+ const isVertical = theme.settings.vertical_fixed_products ?? data.isVertical ?? true;
34
34
 
35
35
  const { data: result, isLoading } = useQuery(
36
36
  product.queries.list({
@@ -154,7 +154,8 @@ const ProductCardContent = memo(function ProductCardContent({
154
154
  's-product-card-entry',
155
155
  isVertical ? 's-product-card-vertical' : '',
156
156
  isHorizontal ? 's-product-card-horizontal' : '',
157
- fitImageHeight && isVertical ? `s-product-card-fit-height` : '',
157
+ // As Twig's card: the store's unified image height sizes horizontal cards too.
158
+ fitImageHeight && (isVertical || isHorizontal) ? `s-product-card-fit-height` : '',
158
159
  isSpecial ? 's-product-card-special' : '',
159
160
  isFullImage ? 's-product-card-full-image' : '',
160
161
  isMinimal ? 's-product-card-minimal' : '',
@@ -34,6 +34,7 @@ import {
34
34
  currentHost,
35
35
  resolveStoreBase,
36
36
  resolveStoreBaseFollowsLocale,
37
+ resolveOwnDomainRedirect,
37
38
  resolveStoreBaseRedirect,
38
39
  resolveStoppedDomainRedirect,
39
40
  } from '../../utils/store-identity';
@@ -188,6 +189,21 @@ export const persistRequestScope = createIsomorphicFn()
188
189
  })
189
190
  .client((): void => {});
190
191
 
192
+ /**
193
+ * The request's Cloudflare bot score (`cf-bot-score`), or null when it has none, as in the
194
+ * browser. Twig's `checkUsername` reads the same header to choose a redirect's status.
195
+ */
196
+ const readBotScore = createIsomorphicFn()
197
+ .server((): number | null => {
198
+ try {
199
+ const score = Number.parseInt(getRequestHeader('cf-bot-score') ?? '', 10);
200
+ return Number.isFinite(score) ? score : null;
201
+ } catch {
202
+ return null;
203
+ }
204
+ })
205
+ .client((): number | null => null);
206
+
191
207
  /** The request's cookie header: the framework's on the server, the document's in the browser. */
192
208
  const requestCookies = createIsomorphicFn()
193
209
  .server((): string | null => {
@@ -295,11 +311,16 @@ function settleSharedHostLanguage(
295
311
  * `/<username>/…`. A request that found its store some other way (`?storeId=`, the preview
296
312
  * cookie, `VITE_STORE_DOMAIN`) is sent there now that the settings say what the username is.
297
313
  *
298
- * A basic-plan store is not served on its own domain: Twig's `checkUsername` sends any page
299
- * of it to the Store's "this domain is stopped" page, with a 302.
314
+ * Twig's `checkUsername` decides the other two, and the engine answers them as it does:
315
+ *
316
+ * - A basic-plan store is not served on its own domain: any page of it goes to the Store's
317
+ * "this domain is stopped" page, with a 302.
318
+ * - Any other store with an active domain is not served at its username on a shared host:
319
+ * `salla.sa/<username>/…` goes to the same page on that domain, with a 301 (a 307 for a
320
+ * person's home page).
300
321
  *
301
322
  * Full loads rather than client navigations: the router handling this request was built
302
- * without that root, and the stopped page is the Store's.
323
+ * without that root, and the other two addresses are on other hosts.
303
324
  */
304
325
  function settleStoreAddress(settings: StoreContext, href: string): void {
305
326
  const storeBaseHref = resolveStoreBaseRedirect(settings.store?.username, href);
@@ -311,6 +332,19 @@ function settleStoreAddress(settings: StoreContext, href: string): void {
311
332
  if (stoppedHref) {
312
333
  throw redirect({ href: stoppedHref, statusCode: 302, reloadDocument: true, replace: true });
313
334
  }
335
+
336
+ const ownDomain = resolveOwnDomainRedirect(settings, href, {
337
+ cookieHeader: readCookieHeader(),
338
+ botScore: readBotScore(),
339
+ });
340
+ if (ownDomain) {
341
+ throw redirect({
342
+ href: ownDomain.href,
343
+ statusCode: ownDomain.statusCode,
344
+ reloadDocument: true,
345
+ replace: true,
346
+ });
347
+ }
314
348
  }
315
349
 
316
350
  export interface BeforeLoadResult {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/product/ProductCard.tsx"],"names":["ProductCardContent","ProductCard"],"mappings":"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","file":"chunk-CAAIQPEN.js","sourcesContent":["import { memo, useCallback, useMemo } from 'react';\nimport { SallaAddProductButton } from '@salla.sa/twilight-components-react/add-product-button';\nimport { SallaButton } from '@salla.sa/twilight-components-react/button';\nimport { useHostAttributes } from '@salla.sa/twilight-theme-engine/hooks/useHostAttributes';\nimport { useMoney } from '../../hooks/useMoney';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { useTwilight } from '../../providers/TwilightProvider';\nimport { useWishlist } from '../../hooks/useWishlist';\nimport { useAsset } from '../../hooks/useAsset';\nimport { useNumber } from '../../hooks/useNumber';\nimport { registry } from '../ComponentRegistry';\nimport { Image } from '../common';\nimport type { Product } from '../../types';\n\nconst PRODUCT_CARD_KEY = 'product:card';\n\nconst PRODUCT_IMAGE_SRCSET_WIDTHS = [150, 300, 450, 600] as const;\n/** Matches `.s-products-list-vertical-cards`: 2-col below 768px, 4-col above. */\nconst PRODUCT_IMAGE_SIZES = '(min-width: 768px) 25vw, 50vw';\n/** fullImage / minimal slots in FeaturedProductsStyle3 (`lg:grid-cols-2`). */\nconst PRODUCT_WIDE_IMAGE_SIZES = '(min-width: 1024px) 50vw, 100vw';\n\n/** Product card layout variants - mutually exclusive */\nexport type ProductCardLayout = 'vertical' | 'horizontal' | 'fullImage' | 'minimal' | 'special';\n\nexport interface ProductCardProps {\n product: Product;\n layout?: ProductCardLayout;\n className?: string;\n withShadow?: boolean;\n withQuantity?: boolean;\n withoutAddButton?: boolean;\n index?: number;\n imagePriority?: boolean;\n /** Overrides the layout-based image `sizes` hint. */\n sizes?: string;\n}\n\n/**\n * ProductCard - Displays a product in various layouts\n *\n * Layouts:\n * - vertical: Default card with image top, content bottom\n * - horizontal: Side-by-side image and content\n * - fullImage: Full bleed image with overlay content\n * - minimal: Compact version with reduced info\n * - special: Featured card with quantity pie chart\n *\n * Features:\n * - Native lazy loading for images\n * - Product badges (promotion, preorder, quantity, out of stock)\n * - Wishlist toggle button\n * - Price display (sale, starting, regular)\n * - Rating display\n * - Add to cart button via SallaAddProductButton (handles labels internally)\n */\nconst ProductCardContent = memo(function ProductCardContent({\n product,\n layout = 'vertical',\n className = '',\n withShadow = false,\n withQuantity = false,\n withoutAddButton = false,\n index = 0,\n imagePriority = false,\n sizes,\n}: ProductCardProps) {\n const { format } = useMoney();\n const { t } = useTranslation();\n const { store, theme } = useTwilight();\n const wishlist = useWishlist();\n const { isPlaceholder } = useAsset();\n const { format: formatNumber } = useNumber();\n\n // Out-of-stock cards offer \"notify me when available\" instead of a dead button, unless\n // the merchant switched `notify_when_available_in_card` off (Twig theme-raed parity).\n const notifyInCard = theme?.settings?.notify_when_available_in_card !== false;\n const addButtonStatus =\n notifyInCard &&\n product.is_out_of_stock &&\n product.type !== 'donating' &&\n product.type !== 'financial_support'\n ? 'out-and-notify'\n : product.status;\n\n const addButtonRef = useHostAttributes({ fill: 'outline', width: 'wide' });\n\n // Layout flags\n const isVertical = layout === 'vertical';\n const isHorizontal = layout === 'horizontal';\n const isFullImage = layout === 'fullImage';\n const isMinimal = layout === 'minimal';\n const isSpecial = layout === 'special';\n\n // Wishlist status\n const productInWishlist = wishlist.has(Number(product.id));\n const handleWishlistToggle = useCallback(() => {\n wishlist.toggle(Number(product.id));\n }, [wishlist, product.id]);\n\n // Get image fit type from store settings\n const fitImageHeight = store?.settings?.product?.fit_type;\n\n // Product badge component\n const getProductBadge = () => {\n if (product?.preorder?.label && typeof product.preorder.label === 'string') {\n return <div className=\"s-product-card-promotion-title\">{product.preorder.label}</div>;\n }\n if (product.promotion_title) {\n return <div className=\"s-product-card-promotion-title\">{product.promotion_title}</div>;\n }\n if (withQuantity && product?.quantity) {\n const formattedQty = formatNumber(product.quantity);\n return (\n <div className=\"s-product-card-quantity\">\n {t('pages.products.remained', 'Remained')} {formattedQty}\n </div>\n );\n }\n if (withQuantity && product?.is_out_of_stock) {\n return (\n <div className=\"s-product-card-out-badge\">\n {t('pages.products.out_of_stock', 'Out of Stock')}\n </div>\n );\n }\n return null;\n };\n\n // Price display component\n const getProductPrice = () => {\n if (product.is_on_sale && product.sale_price) {\n return (\n <div className=\"s-product-card-sale-price\">\n <h4>{format(product.sale_price)}</h4>\n {product.regular_price && <span>{format(product.regular_price)}</span>}\n </div>\n );\n }\n if (product.starting_price) {\n return (\n <div className=\"s-product-card-starting-price\">\n <p>{t('pages.products.starting_price', 'Starting from')}</p>\n <h4>{format(product.starting_price)}</h4>\n </div>\n );\n }\n return <h4 className=\"s-product-card-price\">{format(product.price)}</h4>;\n };\n\n // Build card class names\n const cardClassName = [\n 's-product-card',\n 's-product-card-entry',\n isVertical ? 's-product-card-vertical' : '',\n isHorizontal ? 's-product-card-horizontal' : '',\n fitImageHeight && isVertical ? `s-product-card-fit-height` : '',\n isSpecial ? 's-product-card-special' : '',\n isFullImage ? 's-product-card-full-image' : '',\n isMinimal ? 's-product-card-minimal' : '',\n product?.donation ? 's-product-card-donation' : '',\n withShadow ? 's-product-card-shadow' : '',\n product?.is_out_of_stock ? 's-product-card-out-of-stock' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n // Image fit class\n const isProductPlaceholder = isPlaceholder(product.image?.url);\n const imageFitClass = isProductPlaceholder ? 'contain' : fitImageHeight || 'cover';\n\n return (\n <div\n id={`product-card-${product.id}`}\n className={cardClassName}\n data-product-id={product.id}\n style={{\n animationDelay: `${index * 100}ms`,\n }}\n >\n <div className={isFullImage ? 's-product-card-image-full' : 's-product-card-image'}>\n <a href={product.url} aria-label={product.image?.alt || product.name}>\n <Image\n className={`s-product-card-image-${imageFitClass}`}\n src={product.image?.url}\n alt={product.image?.alt ?? product.name}\n width={300}\n height={300}\n sizes={\n sizes ?? (isFullImage || isMinimal ? PRODUCT_WIDE_IMAGE_SIZES : PRODUCT_IMAGE_SIZES)\n }\n srcSetWidths={PRODUCT_IMAGE_SRCSET_WIDTHS}\n aspectRatio=\"1/1\"\n priority={imagePriority}\n />\n {!isFullImage && !isMinimal && getProductBadge()}\n </a>\n {isFullImage && (\n <a href={product.url} aria-label={product.name} className=\"s-product-card-overlay\" />\n )}\n {!isHorizontal && !isFullImage && (\n <SallaButton\n shape=\"icon\"\n fill=\"outline\"\n color=\"light\"\n ariaLabel={t('pages.wishlist.toggle', 'Add or remove to wishlist')}\n className={`s-product-card-wishlist-btn animated ${productInWishlist ? 's-product-card-wishlist-added pulse-anime' : 'not-added un-favorited'}`}\n onClick={handleWishlistToggle}\n data-id={product.id}\n >\n <i className=\"sicon-heart\" />\n </SallaButton>\n )}\n </div>\n <div className=\"s-product-card-content\">\n {/* Special card: quantity pie */}\n {isSpecial && product?.quantity && (\n <div className=\"s-product-card-content-pie\">\n <span>\n <b>{formatNumber(product.quantity)}</b>\n {t('pages.products.remained', 'Remained')}\n </span>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"-2 -1 36 34\"\n className=\"s-product-card-content-pie-svg\"\n >\n <circle cx=\"16\" cy=\"16\" r=\"15.9155\" className=\"s-product-card-content-pie-svg-base\" />\n <circle cx=\"16\" cy=\"16\" r=\"15.9155\" className=\"s-product-card-content-pie-svg-bar\" />\n </svg>\n </div>\n )}\n\n <div\n className={`s-product-card-content-main ${isSpecial ? 's-product-card-content-extra-padding' : ''}`}\n >\n <h3 className=\"s-product-card-content-title\">\n <a href={product.url}>{product.name}</a>\n </h3>\n {product.subtitle && !isMinimal && (\n <p className=\"s-product-card-content-subtitle opacity-80\">{product.subtitle}</p>\n )}\n </div>\n\n <div\n className={`s-product-card-content-sub ${isSpecial ? 's-product-card-content-extra-padding' : ''}`}\n >\n {!product?.donation?.can_donate && getProductPrice()}\n {product.rating?.stars && (\n <div className=\"s-product-card-rating\">\n <i className=\"sicon-star2 text-orange-300\" />\n <span>{product.rating.stars}</span>\n </div>\n )}\n </div>\n\n {!withoutAddButton && (\n <div className=\"s-product-card-content-footer gap-2\">\n <SallaAddProductButton\n ref={addButtonRef}\n fill=\"outline\"\n width=\"wide\"\n productId={product.id}\n productStatus={addButtonStatus}\n productType={product.type}\n hasPreOrder={product.has_preorder_campaign}\n />\n {(isHorizontal || isFullImage) && (\n <SallaButton\n shape=\"icon\"\n fill=\"outline\"\n color=\"light\"\n ariaLabel={t('pages.wishlist.toggle', 'Add or remove to wishlist')}\n className={`s-product-card-wishlist-btn animated ${productInWishlist ? 's-product-card-wishlist-added pulse-anime' : 'not-added un-favorited'}`}\n onClick={handleWishlistToggle}\n data-id={product.id}\n >\n <i className=\"sicon-heart\" />\n </SallaButton>\n )}\n </div>\n )}\n </div>\n </div>\n );\n});\n\nexport const ProductCard = memo(function ProductCard(props: ProductCardProps) {\n const Component = useMemo(() => {\n const hasOverride = registry.getOriginal<ProductCardProps>(PRODUCT_CARD_KEY) !== null;\n if (hasOverride) {\n return registry.resolve<ProductCardProps>(PRODUCT_CARD_KEY);\n }\n return null;\n }, []);\n\n if (Component) {\n return <Component {...props} />;\n }\n\n return <ProductCardContent {...props} />;\n});\n\nexport default ProductCard;\n"]}