@salla.sa/twilight-theme-engine 1.0.108 → 1.0.110

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 (324) hide show
  1. package/dist/{AddToCartForm-CF4H32X7.js → AddToCartForm-JKGAATX3.js} +3 -3
  2. package/dist/{AddToCartForm-CF4H32X7.js.map → AddToCartForm-JKGAATX3.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-LHYDUFDA.js → BlogAuthorPage-GM2T2QPS.js} +29 -28
  4. package/dist/BlogAuthorPage-GM2T2QPS.js.map +1 -0
  5. package/dist/{BlogCategoryPage-6BORI4YG.js → BlogCategoryPage-KSC5UCJY.js} +29 -28
  6. package/dist/BlogCategoryPage-KSC5UCJY.js.map +1 -0
  7. package/dist/{BlogPage-TSRWNX6M.js → BlogPage-5QTDYSZR.js} +27 -26
  8. package/dist/BlogPage-5QTDYSZR.js.map +1 -0
  9. package/dist/{BlogSinglePage-TLTW67S7.js → BlogSinglePage-JKRNJ3P7.js} +27 -26
  10. package/dist/BlogSinglePage-JKRNJ3P7.js.map +1 -0
  11. package/dist/{BlogTagPage-RAMP5XNR.js → BlogTagPage-JTOBAXV2.js} +29 -28
  12. package/dist/BlogTagPage-JTOBAXV2.js.map +1 -0
  13. package/dist/{BrandsPage-KUFEUFVZ.js → BrandsPage-6IEMAQ3V.js} +28 -27
  14. package/dist/BrandsPage-6IEMAQ3V.js.map +1 -0
  15. package/dist/{Breadcrumb-ZS3ZMMTM.js → Breadcrumb-267KWOPY.js} +27 -26
  16. package/dist/Breadcrumb-267KWOPY.js.map +1 -0
  17. package/dist/{CartItem-7QCAQ3QQ.js → CartItem-BUP3WUZC.js} +27 -26
  18. package/dist/CartItem-BUP3WUZC.js.map +1 -0
  19. package/dist/{CartSummary-ZPG7IAXE.js → CartSummary-U3MOISSP.js} +27 -26
  20. package/dist/CartSummary-U3MOISSP.js.map +1 -0
  21. package/dist/{Copyright-VPJMIQSO.js → Copyright-FSNCI3EE.js} +3 -3
  22. package/dist/{Copyright-VPJMIQSO.js.map → Copyright-FSNCI3EE.js.map} +1 -1
  23. package/dist/{CustomerLayout-E5FYPKT4.js → CustomerLayout-JCOMMGZ7.js} +27 -26
  24. package/dist/CustomerLayout-JCOMMGZ7.js.map +1 -0
  25. package/dist/{Footer-GIPFBQEY.js → Footer-VP3IBUMQ.js} +5 -4
  26. package/dist/{Footer-GIPFBQEY.js.map → Footer-VP3IBUMQ.js.map} +1 -1
  27. package/dist/Header-3YOZ7XLJ.js +22 -0
  28. package/dist/{Header-HYTNO4IR.js.map → Header-3YOZ7XLJ.js.map} +1 -1
  29. package/dist/{LoyaltyPage-YMK7SISF.js → LoyaltyPage-5X42RIJQ.js} +27 -26
  30. package/dist/LoyaltyPage-5X42RIJQ.js.map +1 -0
  31. package/dist/{LoyaltyPointsPage-V2463UQ6.js → LoyaltyPointsPage-67KYJN2Z.js} +10 -9
  32. package/dist/LoyaltyPointsPage-67KYJN2Z.js.map +1 -0
  33. package/dist/{MainMenu-IP6AVEIF.js → MainMenu-FYIK55JU.js} +8 -8
  34. package/dist/{MainMenu-IP6AVEIF.js.map → MainMenu-FYIK55JU.js.map} +1 -1
  35. package/dist/MaintenancePage-UBJ5Q3L5.js +7 -0
  36. package/dist/{MaintenancePage-Z34IQCUV.js.map → MaintenancePage-UBJ5Q3L5.js.map} +1 -1
  37. package/dist/MasterLayout-UMZHQTU2.js +54 -0
  38. package/dist/{MasterLayout-3YSR4VFQ.js.map → MasterLayout-UMZHQTU2.js.map} +1 -1
  39. package/dist/{MobileMenu-ZJLXCG4P.js → MobileMenu-FFPJYJ7F.js} +28 -27
  40. package/dist/MobileMenu-FFPJYJ7F.js.map +1 -0
  41. package/dist/{NotificationsPage-XKSW3DFD.js → NotificationsPage-HKJN6ME2.js} +27 -26
  42. package/dist/NotificationsPage-HKJN6ME2.js.map +1 -0
  43. package/dist/{OrderSinglePage-WSUNHCY6.js → OrderSinglePage-ASYL4SMQ.js} +28 -27
  44. package/dist/OrderSinglePage-ASYL4SMQ.js.map +1 -0
  45. package/dist/{OrdersPage-TAME5ACG.js → OrdersPage-IQXHFGLQ.js} +27 -26
  46. package/dist/OrdersPage-IQXHFGLQ.js.map +1 -0
  47. package/dist/{PageSingle-MYDLIP55.js → PageSingle-B4WQVQVQ.js} +7 -7
  48. package/dist/{PageSingle-MYDLIP55.js.map → PageSingle-B4WQVQVQ.js.map} +1 -1
  49. package/dist/{ProductDetails-MFAKRQ72.js → ProductDetails-WSEGLJSW.js} +8 -8
  50. package/dist/{ProductDetails-MFAKRQ72.js.map → ProductDetails-WSEGLJSW.js.map} +1 -1
  51. package/dist/{ProfilePage-4W7DBXLW.js → ProfilePage-6GNEI6OV.js} +27 -26
  52. package/dist/ProfilePage-6GNEI6OV.js.map +1 -0
  53. package/dist/{ReviewsPage-G3IEPOOO.js → ReviewsPage-JP4LZI4A.js} +3 -3
  54. package/dist/{ReviewsPage-G3IEPOOO.js.map → ReviewsPage-JP4LZI4A.js.map} +1 -1
  55. package/dist/{SeoCartWidget-7UDOVSWP.js → SeoCartWidget-KCB4E65P.js} +27 -26
  56. package/dist/SeoCartWidget-KCB4E65P.js.map +1 -0
  57. package/dist/{SettingsPage-TEMXC3OF.js → SettingsPage-UFGVJOI2.js} +27 -26
  58. package/dist/SettingsPage-UFGVJOI2.js.map +1 -0
  59. package/dist/StoreClosedNotification-Q4QPPYEH.js +55 -0
  60. package/dist/{StoreClosedNotification-YMPBP56U.js.map → StoreClosedNotification-Q4QPPYEH.js.map} +1 -1
  61. package/dist/{TestimonialsPage-G2S3JQNT.js → TestimonialsPage-K5PHW7WD.js} +7 -7
  62. package/dist/{TestimonialsPage-G2S3JQNT.js.map → TestimonialsPage-K5PHW7WD.js.map} +1 -1
  63. package/dist/{ThankYouPage-HPF3PIAT.js → ThankYouPage-DSDAYYJN.js} +27 -26
  64. package/dist/ThankYouPage-DSDAYYJN.js.map +1 -0
  65. package/dist/{WalletPage-G7FOMHFX.js → WalletPage-3LWCFG25.js} +28 -27
  66. package/dist/WalletPage-3LWCFG25.js.map +1 -0
  67. package/dist/{WishlistPage-VULTU6K2.js → WishlistPage-LF4A2H3I.js} +29 -28
  68. package/dist/WishlistPage-LF4A2H3I.js.map +1 -0
  69. package/dist/api/advertisement.js +5 -5
  70. package/dist/api/apps.js +5 -5
  71. package/dist/api/blog.js +7 -7
  72. package/dist/api/brands.js +7 -7
  73. package/dist/api/cart.js +7 -7
  74. package/dist/api/category.js +7 -7
  75. package/dist/api/client.js +4 -4
  76. package/dist/api/home.js +5 -5
  77. package/dist/api/loyalty.js +7 -7
  78. package/dist/api/menu.js +5 -5
  79. package/dist/api/notification.js +5 -5
  80. package/dist/api/order.js +7 -7
  81. package/dist/api/page.js +7 -7
  82. package/dist/api/product.js +7 -7
  83. package/dist/api/profile.js +4 -4
  84. package/dist/api/store.d.ts.map +1 -1
  85. package/dist/api/store.js +5 -5
  86. package/dist/api/translations.js +5 -5
  87. package/dist/api/user.js +5 -5
  88. package/dist/api/wallet.js +5 -5
  89. package/dist/api/wishlist.js +8 -8
  90. package/dist/{chunk-XL42DUCQ.js → chunk-2MHMQOMJ.js} +3 -3
  91. package/dist/{chunk-XL42DUCQ.js.map → chunk-2MHMQOMJ.js.map} +1 -1
  92. package/dist/{chunk-KSS7OA3Q.js → chunk-3DNVQVNY.js} +3 -3
  93. package/dist/{chunk-KSS7OA3Q.js.map → chunk-3DNVQVNY.js.map} +1 -1
  94. package/dist/{chunk-2IW3JRWL.js → chunk-4INSECDW.js} +5 -5
  95. package/dist/{chunk-2IW3JRWL.js.map → chunk-4INSECDW.js.map} +1 -1
  96. package/dist/{chunk-VUWBGAET.js → chunk-56OZRZIZ.js} +4 -4
  97. package/dist/{chunk-VUWBGAET.js.map → chunk-56OZRZIZ.js.map} +1 -1
  98. package/dist/{chunk-D7XWUD6T.js → chunk-6NV6T24C.js} +4 -4
  99. package/dist/{chunk-D7XWUD6T.js.map → chunk-6NV6T24C.js.map} +1 -1
  100. package/dist/{chunk-SQXUWX4B.js → chunk-6T7FUHJY.js} +5 -5
  101. package/dist/{chunk-SQXUWX4B.js.map → chunk-6T7FUHJY.js.map} +1 -1
  102. package/dist/{chunk-UZGP2KFA.js → chunk-6Z6BGS7P.js} +3 -3
  103. package/dist/{chunk-UZGP2KFA.js.map → chunk-6Z6BGS7P.js.map} +1 -1
  104. package/dist/{chunk-6UG4IVUF.js → chunk-72DGJN4Q.js} +23 -23
  105. package/dist/{chunk-6UG4IVUF.js.map → chunk-72DGJN4Q.js.map} +1 -1
  106. package/dist/{chunk-FQLF555I.js → chunk-7T5UR3XD.js} +4 -4
  107. package/dist/{chunk-FQLF555I.js.map → chunk-7T5UR3XD.js.map} +1 -1
  108. package/dist/{chunk-T4BRWJSI.js → chunk-7ZBSIOVM.js} +7 -7
  109. package/dist/{chunk-T4BRWJSI.js.map → chunk-7ZBSIOVM.js.map} +1 -1
  110. package/dist/{chunk-3DVAXIY3.js → chunk-ALAHGZPN.js} +4 -4
  111. package/dist/{chunk-3DVAXIY3.js.map → chunk-ALAHGZPN.js.map} +1 -1
  112. package/dist/{chunk-YDSWLCOY.js → chunk-BFA2U7P3.js} +5 -5
  113. package/dist/{chunk-YDSWLCOY.js.map → chunk-BFA2U7P3.js.map} +1 -1
  114. package/dist/{chunk-F6XPGONG.js → chunk-CA3QVM6Y.js} +5 -5
  115. package/dist/{chunk-F6XPGONG.js.map → chunk-CA3QVM6Y.js.map} +1 -1
  116. package/dist/{chunk-24UCMWQB.js → chunk-CFARTPUQ.js} +3 -3
  117. package/dist/{chunk-24UCMWQB.js.map → chunk-CFARTPUQ.js.map} +1 -1
  118. package/dist/chunk-D6XIFBYA.js +14 -0
  119. package/dist/{chunk-47C3MTZI.js.map → chunk-D6XIFBYA.js.map} +1 -1
  120. package/dist/{chunk-UWDUMPL7.js → chunk-E5PEYI5I.js} +6 -6
  121. package/dist/{chunk-UWDUMPL7.js.map → chunk-E5PEYI5I.js.map} +1 -1
  122. package/dist/{chunk-TWUOIBO7.js → chunk-E7AO2Q32.js} +3 -3
  123. package/dist/{chunk-TWUOIBO7.js.map → chunk-E7AO2Q32.js.map} +1 -1
  124. package/dist/{chunk-Y464WYUT.js → chunk-EJLVOWXU.js} +5 -5
  125. package/dist/{chunk-Y464WYUT.js.map → chunk-EJLVOWXU.js.map} +1 -1
  126. package/dist/{chunk-T5VU67NQ.js → chunk-FJQD3LTR.js} +4 -4
  127. package/dist/{chunk-T5VU67NQ.js.map → chunk-FJQD3LTR.js.map} +1 -1
  128. package/dist/{chunk-BR56OEPZ.js → chunk-FMSRB2TT.js} +4 -4
  129. package/dist/{chunk-BR56OEPZ.js.map → chunk-FMSRB2TT.js.map} +1 -1
  130. package/dist/chunk-FNM2OUPD.js +182 -0
  131. package/dist/chunk-FNM2OUPD.js.map +1 -0
  132. package/dist/{chunk-ZLLHL3NI.js → chunk-G3VAJVY5.js} +7 -7
  133. package/dist/{chunk-ZLLHL3NI.js.map → chunk-G3VAJVY5.js.map} +1 -1
  134. package/dist/{chunk-ZVYJK6XQ.js → chunk-GAGTCI3J.js} +5 -5
  135. package/dist/{chunk-ZVYJK6XQ.js.map → chunk-GAGTCI3J.js.map} +1 -1
  136. package/dist/{chunk-U6KJ7XBO.js → chunk-I7WSIN27.js} +3 -3
  137. package/dist/{chunk-U6KJ7XBO.js.map → chunk-I7WSIN27.js.map} +1 -1
  138. package/dist/{chunk-2CL6AEO4.js → chunk-IAHWLUFK.js} +3 -3
  139. package/dist/{chunk-2CL6AEO4.js.map → chunk-IAHWLUFK.js.map} +1 -1
  140. package/dist/{chunk-QA4FBMFJ.js → chunk-K7U46BT2.js} +4 -4
  141. package/dist/{chunk-QA4FBMFJ.js.map → chunk-K7U46BT2.js.map} +1 -1
  142. package/dist/{chunk-4PT5MXGR.js → chunk-LU5DRXS5.js} +4 -4
  143. package/dist/{chunk-4PT5MXGR.js.map → chunk-LU5DRXS5.js.map} +1 -1
  144. package/dist/{chunk-EHX45KZG.js → chunk-LZZ6EESI.js} +3 -3
  145. package/dist/{chunk-EHX45KZG.js.map → chunk-LZZ6EESI.js.map} +1 -1
  146. package/dist/{chunk-HNSR4KLL.js → chunk-MEMJOJO4.js} +3 -3
  147. package/dist/{chunk-HNSR4KLL.js.map → chunk-MEMJOJO4.js.map} +1 -1
  148. package/dist/{chunk-RBFLDI2Z.js → chunk-MJ7TL42D.js} +4 -4
  149. package/dist/{chunk-RBFLDI2Z.js.map → chunk-MJ7TL42D.js.map} +1 -1
  150. package/dist/{chunk-W354TTIE.js → chunk-MVBMVM22.js} +7 -7
  151. package/dist/{chunk-W354TTIE.js.map → chunk-MVBMVM22.js.map} +1 -1
  152. package/dist/{chunk-ENC6POPF.js → chunk-OMY65JIW.js} +4 -4
  153. package/dist/{chunk-ENC6POPF.js.map → chunk-OMY65JIW.js.map} +1 -1
  154. package/dist/chunk-OQIIJRAS.js +30 -0
  155. package/dist/chunk-OQIIJRAS.js.map +1 -0
  156. package/dist/{chunk-GFUXGVER.js → chunk-OSAFBMRT.js} +3 -3
  157. package/dist/{chunk-GFUXGVER.js.map → chunk-OSAFBMRT.js.map} +1 -1
  158. package/dist/{chunk-OHUTM224.js → chunk-PF2WSBJ7.js} +4 -4
  159. package/dist/{chunk-OHUTM224.js.map → chunk-PF2WSBJ7.js.map} +1 -1
  160. package/dist/{chunk-L4JI2AAL.js → chunk-PKJJ6Z7A.js} +4 -4
  161. package/dist/{chunk-L4JI2AAL.js.map → chunk-PKJJ6Z7A.js.map} +1 -1
  162. package/dist/{chunk-GXZW6BJY.js → chunk-POI4G5EA.js} +113 -8
  163. package/dist/chunk-POI4G5EA.js.map +1 -0
  164. package/dist/{chunk-JNAJTCJD.js → chunk-QRHXAKJ3.js} +5 -3
  165. package/dist/chunk-QRHXAKJ3.js.map +1 -0
  166. package/dist/{chunk-5L37UNQQ.js → chunk-S67SB2O2.js} +7 -7
  167. package/dist/{chunk-5L37UNQQ.js.map → chunk-S67SB2O2.js.map} +1 -1
  168. package/dist/{chunk-B2OJZKU4.js → chunk-SCSJROJX.js} +8 -8
  169. package/dist/{chunk-B2OJZKU4.js.map → chunk-SCSJROJX.js.map} +1 -1
  170. package/dist/{chunk-SCRNQWZT.js → chunk-TL256OK3.js} +4 -4
  171. package/dist/{chunk-SCRNQWZT.js.map → chunk-TL256OK3.js.map} +1 -1
  172. package/dist/{chunk-4SZZPXM2.js → chunk-TMMK2VYE.js} +50 -17
  173. package/dist/chunk-TMMK2VYE.js.map +1 -0
  174. package/dist/{chunk-LUFLN7WL.js → chunk-VFXAHTB3.js} +7 -7
  175. package/dist/{chunk-LUFLN7WL.js.map → chunk-VFXAHTB3.js.map} +1 -1
  176. package/dist/{chunk-PTQVBPPN.js → chunk-VIR6L7KJ.js} +6 -4
  177. package/dist/chunk-VIR6L7KJ.js.map +1 -0
  178. package/dist/{chunk-OSSOU36J.js → chunk-WD576F4S.js} +3 -3
  179. package/dist/{chunk-OSSOU36J.js.map → chunk-WD576F4S.js.map} +1 -1
  180. package/dist/{chunk-BQ2MNEN7.js → chunk-WN35SBLD.js} +3 -3
  181. package/dist/{chunk-BQ2MNEN7.js.map → chunk-WN35SBLD.js.map} +1 -1
  182. package/dist/{chunk-GKKHNGLI.js → chunk-WRYCOIYC.js} +9 -9
  183. package/dist/{chunk-GKKHNGLI.js.map → chunk-WRYCOIYC.js.map} +1 -1
  184. package/dist/{chunk-3NFVZJNI.js → chunk-X2JCU7GY.js} +3 -3
  185. package/dist/{chunk-3NFVZJNI.js.map → chunk-X2JCU7GY.js.map} +1 -1
  186. package/dist/{chunk-S5EVFWAL.js → chunk-XU33IHQA.js} +8 -8
  187. package/dist/{chunk-S5EVFWAL.js.map → chunk-XU33IHQA.js.map} +1 -1
  188. package/dist/{chunk-5N74JJ2Z.js → chunk-YSYA64WS.js} +103 -21
  189. package/dist/chunk-YSYA64WS.js.map +1 -0
  190. package/dist/{chunk-A4NN6C5B.js → chunk-YYMKDBZV.js} +3 -3
  191. package/dist/{chunk-A4NN6C5B.js.map → chunk-YYMKDBZV.js.map} +1 -1
  192. package/dist/{chunk-RA6ZTHN6.js → chunk-Z4UTYKKV.js} +4 -4
  193. package/dist/{chunk-RA6ZTHN6.js.map → chunk-Z4UTYKKV.js.map} +1 -1
  194. package/dist/{chunk-UKLYL5LM.js → chunk-ZDKQL2E4.js} +4 -4
  195. package/dist/{chunk-UKLYL5LM.js.map → chunk-ZDKQL2E4.js.map} +1 -1
  196. package/dist/{chunk-BEMWHR4T.js → chunk-ZRT6L6TC.js} +3 -3
  197. package/dist/{chunk-BEMWHR4T.js.map → chunk-ZRT6L6TC.js.map} +1 -1
  198. package/dist/components/cart/index.js +1 -1
  199. package/dist/components/common/index.js +1 -1
  200. package/dist/components/drawer/index.js +25 -24
  201. package/dist/components/home/index.js +29 -28
  202. package/dist/components/layout/Footer.d.ts.map +1 -1
  203. package/dist/components/layout/MadeWithSalla.d.ts +9 -0
  204. package/dist/components/layout/MadeWithSalla.d.ts.map +1 -0
  205. package/dist/components/layout/index.d.ts +2 -0
  206. package/dist/components/layout/index.d.ts.map +1 -1
  207. package/dist/components/layout/index.js +8 -7
  208. package/dist/components/product/index.js +26 -25
  209. package/dist/components/store/index.js +27 -26
  210. package/dist/components/toast/index.js +5 -5
  211. package/dist/dev/editor/index.js +3 -3
  212. package/dist/dev/index.js +3 -3
  213. package/dist/document-class-5BRFPS6J.js +29 -0
  214. package/dist/{document-class-B2MXKYAQ.js.map → document-class-5BRFPS6J.js.map} +1 -1
  215. package/dist/hooks/index.js +25 -24
  216. package/dist/hooks/useComments.js +4 -4
  217. package/dist/hooks/useGtm.js +25 -24
  218. package/dist/hooks/useMoney.js +25 -24
  219. package/dist/hooks/useProduct.js +4 -4
  220. package/dist/hooks/useStore.js +25 -24
  221. package/dist/hooks/useUser.js +6 -6
  222. package/dist/hooks/useWishlist.js +4 -4
  223. package/dist/index.d.ts +1 -0
  224. package/dist/index.d.ts.map +1 -1
  225. package/dist/index.js +25 -24
  226. package/dist/index.js.map +1 -1
  227. package/dist/native-app/index.js +4 -4
  228. package/dist/{navigation-LSRNHKGJ.js → navigation-NM4AO2OX.js} +8 -8
  229. package/dist/{navigation-LSRNHKGJ.js.map → navigation-NM4AO2OX.js.map} +1 -1
  230. package/dist/navigation-S5EUYOVI.js +14 -0
  231. package/dist/{navigation-WASYQTFC.js.map → navigation-S5EUYOVI.js.map} +1 -1
  232. package/dist/{not-found-M3ZPUVVC.js → not-found-NO54GPIK.js} +28 -27
  233. package/dist/not-found-NO54GPIK.js.map +1 -0
  234. package/dist/providers/index.js +25 -24
  235. package/dist/routes/account/orders.js +9 -9
  236. package/dist/routes/account.js +18 -18
  237. package/dist/routes/blog.js +13 -13
  238. package/dist/routes/brands.js +9 -9
  239. package/dist/routes/cart.js +33 -32
  240. package/dist/routes/cart.js.map +1 -1
  241. package/dist/routes/home.js +30 -29
  242. package/dist/routes/index.js +7 -7
  243. package/dist/routes/loyalty.js +10 -10
  244. package/dist/routes/page.js +9 -9
  245. package/dist/routes/product-listing.js +31 -30
  246. package/dist/routes/product-listing.js.map +1 -1
  247. package/dist/routes/product.js +29 -28
  248. package/dist/routes/product.js.map +1 -1
  249. package/dist/routes/root/beforeLoad.d.ts +6 -0
  250. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  251. package/dist/routes/seo-redirects.js +7 -7
  252. package/dist/routes/testimonials.js +5 -4
  253. package/dist/routes/testimonials.js.map +1 -1
  254. package/dist/routes/thank-you.js +9 -9
  255. package/dist/skeleton.js +30 -29
  256. package/dist/{store-lookup-EW6ALPQF.js → store-lookup-LVKWUL6Z.js} +12 -12
  257. package/dist/{store-lookup-EW6ALPQF.js.map → store-lookup-LVKWUL6Z.js.map} +1 -1
  258. package/dist/tanstack/middleware/twilight.d.ts.map +1 -1
  259. package/dist/tanstack/store-base.d.ts +10 -2
  260. package/dist/tanstack/store-base.d.ts.map +1 -1
  261. package/dist/tanstack/templates/locale-wrapper.d.ts +2 -1
  262. package/dist/tanstack/templates/locale-wrapper.d.ts.map +1 -1
  263. package/dist/tanstack.js +45 -23
  264. package/dist/tanstack.js.map +1 -1
  265. package/dist/types/index.d.ts +8 -0
  266. package/dist/types/index.d.ts.map +1 -1
  267. package/dist/utils/baseHead.d.ts +6 -1
  268. package/dist/utils/baseHead.d.ts.map +1 -1
  269. package/dist/utils/baseHead.js +3 -1
  270. package/dist/utils/cookies.d.ts +6 -0
  271. package/dist/utils/cookies.d.ts.map +1 -1
  272. package/dist/utils/errors.d.ts +18 -1
  273. package/dist/utils/errors.d.ts.map +1 -1
  274. package/dist/utils/index.js +7 -7
  275. package/dist/utils/language-cookie.d.ts +10 -0
  276. package/dist/utils/language-cookie.d.ts.map +1 -0
  277. package/dist/utils/shared-host-language.d.ts +72 -0
  278. package/dist/utils/shared-host-language.d.ts.map +1 -0
  279. package/dist/utils/store-base.d.ts +28 -6
  280. package/dist/utils/store-base.d.ts.map +1 -1
  281. package/dist/vite/index.js +43 -7
  282. package/dist/vite/index.js.map +1 -1
  283. package/package.json +1 -1
  284. package/tailwind/components/layout/Footer.tsx.txt +2 -0
  285. package/tailwind/components/layout/MadeWithSalla.tsx.txt +34 -0
  286. package/tailwind/components/layout/index.ts.txt +3 -0
  287. package/tailwind/routes/root/beforeLoad.ts.txt +61 -3
  288. package/dist/BlogAuthorPage-LHYDUFDA.js.map +0 -1
  289. package/dist/BlogCategoryPage-6BORI4YG.js.map +0 -1
  290. package/dist/BlogPage-TSRWNX6M.js.map +0 -1
  291. package/dist/BlogSinglePage-TLTW67S7.js.map +0 -1
  292. package/dist/BlogTagPage-RAMP5XNR.js.map +0 -1
  293. package/dist/BrandsPage-KUFEUFVZ.js.map +0 -1
  294. package/dist/Breadcrumb-ZS3ZMMTM.js.map +0 -1
  295. package/dist/CartItem-7QCAQ3QQ.js.map +0 -1
  296. package/dist/CartSummary-ZPG7IAXE.js.map +0 -1
  297. package/dist/CustomerLayout-E5FYPKT4.js.map +0 -1
  298. package/dist/Header-HYTNO4IR.js +0 -22
  299. package/dist/LoyaltyPage-YMK7SISF.js.map +0 -1
  300. package/dist/LoyaltyPointsPage-V2463UQ6.js.map +0 -1
  301. package/dist/MaintenancePage-Z34IQCUV.js +0 -7
  302. package/dist/MasterLayout-3YSR4VFQ.js +0 -53
  303. package/dist/MobileMenu-ZJLXCG4P.js.map +0 -1
  304. package/dist/NotificationsPage-XKSW3DFD.js.map +0 -1
  305. package/dist/OrderSinglePage-WSUNHCY6.js.map +0 -1
  306. package/dist/OrdersPage-TAME5ACG.js.map +0 -1
  307. package/dist/ProfilePage-4W7DBXLW.js.map +0 -1
  308. package/dist/SeoCartWidget-7UDOVSWP.js.map +0 -1
  309. package/dist/SettingsPage-TEMXC3OF.js.map +0 -1
  310. package/dist/StoreClosedNotification-YMPBP56U.js +0 -54
  311. package/dist/ThankYouPage-HPF3PIAT.js.map +0 -1
  312. package/dist/WalletPage-G7FOMHFX.js.map +0 -1
  313. package/dist/WishlistPage-VULTU6K2.js.map +0 -1
  314. package/dist/chunk-47C3MTZI.js +0 -14
  315. package/dist/chunk-4SZZPXM2.js.map +0 -1
  316. package/dist/chunk-5N74JJ2Z.js.map +0 -1
  317. package/dist/chunk-D42M66E4.js +0 -127
  318. package/dist/chunk-D42M66E4.js.map +0 -1
  319. package/dist/chunk-GXZW6BJY.js.map +0 -1
  320. package/dist/chunk-JNAJTCJD.js.map +0 -1
  321. package/dist/chunk-PTQVBPPN.js.map +0 -1
  322. package/dist/document-class-B2MXKYAQ.js +0 -29
  323. package/dist/navigation-WASYQTFC.js +0 -14
  324. package/dist/not-found-M3ZPUVVC.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { onSallaEvent } from './chunk-3NFVZJNI.js';
1
+ import { onSallaEvent } from './chunk-X2JCU7GY.js';
2
2
  import { useState, useCallback, useEffect } from 'react';
3
3
 
4
4
  function useComments() {
@@ -16,5 +16,5 @@ function useComments() {
16
16
  }
17
17
 
18
18
  export { useComments };
19
- //# sourceMappingURL=chunk-KSS7OA3Q.js.map
20
- //# sourceMappingURL=chunk-KSS7OA3Q.js.map
19
+ //# sourceMappingURL=chunk-3DNVQVNY.js.map
20
+ //# sourceMappingURL=chunk-3DNVQVNY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useComments.ts"],"names":[],"mappings":";;;AAuCO,SAAS,WAAA,GAAiC;AAC/C,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAEhD,EAAA,MAAM,OAAA,GAAU,YAAY,MAAM;AAChC,IAAA,cAAA,CAAe,CAAC,IAAA,KAAS,IAAA,GAAO,CAAC,CAAA;AAAA,EACnC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,qBAAqB,MAAM;AAC/B,MAAA,cAAA,CAAe,CAAC,IAAA,KAAS,IAAA,GAAO,CAAC,CAAA;AAAA,IACnC,CAAA;AAEA,IAAA,OAAO,YAAA,CAAa,kBAAkB,kBAAkB,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,aAAa,OAAA,EAAQ;AAChC","file":"chunk-KSS7OA3Q.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { onSallaEvent } from '../utils/sdk-helpers';\n\n/**\n * UseCommentsResult - Return type for useComments hook\n *\n * @property commentsKey - Key to pass to salla-comments component for re-render\n * @property refresh - Function to manually trigger a comments refresh\n */\nexport interface UseCommentsResult {\n commentsKey: number;\n refresh: () => void;\n}\n\n/**\n * useComments - Hook for managing salla-comments web component re-renders\n *\n * Listens to the Salla SDK's comment added events and automatically\n * increments a re-render key for the salla-comments component. This\n * eliminates the need for full page reloads when comments are added.\n *\n * @returns Object with comments key for component re-rendering and manual refresh function\n *\n * @example\n * ```tsx\n * function ProductPage({ product }) {\n * const { commentsKey } = useComments();\n *\n * return (\n * <salla-comments\n * key={commentsKey}\n * item-id={product.id}\n * type=\"product\"\n * />\n * );\n * }\n * ```\n */\n\nexport function useComments(): UseCommentsResult {\n const [commentsKey, setCommentsKey] = useState(0);\n\n const refresh = useCallback(() => {\n setCommentsKey((prev) => prev + 1);\n }, []);\n\n useEffect(() => {\n const handleCommentAdded = () => {\n setCommentsKey((prev) => prev + 1);\n };\n\n return onSallaEvent('comment::added', handleCommentAdded);\n }, []);\n\n return { commentsKey, refresh };\n}\n"]}
1
+ {"version":3,"sources":["../src/hooks/useComments.ts"],"names":[],"mappings":";;;AAuCO,SAAS,WAAA,GAAiC;AAC/C,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAEhD,EAAA,MAAM,OAAA,GAAU,YAAY,MAAM;AAChC,IAAA,cAAA,CAAe,CAAC,IAAA,KAAS,IAAA,GAAO,CAAC,CAAA;AAAA,EACnC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,qBAAqB,MAAM;AAC/B,MAAA,cAAA,CAAe,CAAC,IAAA,KAAS,IAAA,GAAO,CAAC,CAAA;AAAA,IACnC,CAAA;AAEA,IAAA,OAAO,YAAA,CAAa,kBAAkB,kBAAkB,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,aAAa,OAAA,EAAQ;AAChC","file":"chunk-3DNVQVNY.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { onSallaEvent } from '../utils/sdk-helpers';\n\n/**\n * UseCommentsResult - Return type for useComments hook\n *\n * @property commentsKey - Key to pass to salla-comments component for re-render\n * @property refresh - Function to manually trigger a comments refresh\n */\nexport interface UseCommentsResult {\n commentsKey: number;\n refresh: () => void;\n}\n\n/**\n * useComments - Hook for managing salla-comments web component re-renders\n *\n * Listens to the Salla SDK's comment added events and automatically\n * increments a re-render key for the salla-comments component. This\n * eliminates the need for full page reloads when comments are added.\n *\n * @returns Object with comments key for component re-rendering and manual refresh function\n *\n * @example\n * ```tsx\n * function ProductPage({ product }) {\n * const { commentsKey } = useComments();\n *\n * return (\n * <salla-comments\n * key={commentsKey}\n * item-id={product.id}\n * type=\"product\"\n * />\n * );\n * }\n * ```\n */\n\nexport function useComments(): UseCommentsResult {\n const [commentsKey, setCommentsKey] = useState(0);\n\n const refresh = useCallback(() => {\n setCommentsKey((prev) => prev + 1);\n }, []);\n\n useEffect(() => {\n const handleCommentAdded = () => {\n setCommentsKey((prev) => prev + 1);\n };\n\n return onSallaEvent('comment::added', handleCommentAdded);\n }, []);\n\n return { commentsKey, refresh };\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { ensureTwilightContextFromMatches } from './chunk-EHX45KZG.js';
2
- import { storePageUrl } from './chunk-4SZZPXM2.js';
3
- import { getTwilightContext, SettingsError } from './chunk-JNAJTCJD.js';
1
+ import { ensureTwilightContextFromMatches } from './chunk-LZZ6EESI.js';
2
+ import { storePageUrl } from './chunk-TMMK2VYE.js';
3
+ import { getTwilightContext, SettingsError } from './chunk-QRHXAKJ3.js';
4
4
 
5
5
  // src/tanstack/head.ts
6
6
  function normalizeOgImages(images) {
@@ -125,5 +125,5 @@ function withHead(route, extend) {
125
125
  }
126
126
 
127
127
  export { tanstackHeadAdapter, withHead };
128
- //# sourceMappingURL=chunk-2IW3JRWL.js.map
129
- //# sourceMappingURL=chunk-2IW3JRWL.js.map
128
+ //# sourceMappingURL=chunk-4INSECDW.js.map
129
+ //# sourceMappingURL=chunk-4INSECDW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tanstack/head.ts"],"names":[],"mappings":"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","file":"chunk-2IW3JRWL.js","sourcesContent":["import type { HeadDescriptor, OpenGraphImage } from '../utils/head';\nimport type { TwilightContext } from '../twilight/context';\nimport { getTwilightContext } from '../twilight/context';\nimport type { TwilightContextMatch } from '../twilight/ensure-context';\nimport { ensureTwilightContextFromMatches } from '../twilight/ensure-context';\nimport { SettingsError } from '../utils/errors';\nimport { storePageUrl } from '../utils/baseHead';\n\ntype OgImagesInput = string | OpenGraphImage | Array<string | OpenGraphImage> | undefined;\n\nfunction normalizeOgImages(images: OgImagesInput): OpenGraphImage[] {\n if (!images) return [];\n const arr = Array.isArray(images) ? images : [images];\n return arr.map((img) => (typeof img === 'string' ? { url: img } : img));\n}\n\n/** Merchant descriptions are rich-text HTML; description meta tags take plain text. */\nfunction plainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>|<\\/(?:p|div|li|h[1-6])>/gi, ' ')\n .replace(/<[^>]*>/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function tanstackHeadAdapter(descriptor: HeadDescriptor) {\n const meta: Array<Record<string, unknown>> = [];\n const links: Array<Record<string, unknown>> = [];\n const scripts: Array<Record<string, unknown>> = [];\n const styles: Record<string, unknown>[] = [];\n\n if (descriptor.title) meta.push({ title: descriptor.title });\n if (descriptor.description)\n meta.push({ name: 'description', content: plainText(descriptor.description) });\n\n if (descriptor.keywords) {\n const kw = Array.isArray(descriptor.keywords)\n ? descriptor.keywords.join(', ')\n : descriptor.keywords;\n meta.push({ name: 'keywords', content: kw });\n }\n\n if (descriptor.robots) meta.push({ name: 'robots', content: descriptor.robots });\n\n // Open Graph\n const og = descriptor.openGraph;\n if (og) {\n if (og.siteName) meta.push({ property: 'og:site_name', content: og.siteName });\n if (og.type) meta.push({ property: 'og:type', content: og.type });\n if (og.title) meta.push({ property: 'og:title', content: og.title });\n if (og.description)\n meta.push({ property: 'og:description', content: plainText(og.description) });\n if (og.url) meta.push({ property: 'og:url', content: og.url });\n if (og.locale) meta.push({ property: 'og:locale', content: og.locale });\n for (const alt of og.alternateLocale ?? []) {\n meta.push({ property: 'og:locale:alternate', content: alt });\n }\n for (const img of normalizeOgImages(og.images)) {\n meta.push({ property: 'og:image', content: img.url });\n if (img.width != null) meta.push({ property: 'og:image:width', content: String(img.width) });\n if (img.height != null)\n meta.push({ property: 'og:image:height', content: String(img.height) });\n if (img.alt) meta.push({ property: 'og:image:alt', content: img.alt });\n }\n if (og.publishedTime)\n meta.push({ property: 'article:published_time', content: og.publishedTime });\n if (og.modifiedTime) meta.push({ property: 'article:modified_time', content: og.modifiedTime });\n }\n\n // Twitter Card\n const tw = descriptor.twitter;\n if (tw) {\n if (tw.card) meta.push({ name: 'twitter:card', content: tw.card });\n if (tw.title) meta.push({ name: 'twitter:title', content: tw.title });\n if (tw.description)\n meta.push({ name: 'twitter:description', content: plainText(tw.description) });\n if (tw.site) meta.push({ name: 'twitter:site', content: tw.site });\n if (tw.creator) meta.push({ name: 'twitter:creator', content: tw.creator });\n if (tw.url) meta.push({ name: 'twitter:url', content: tw.url });\n const twImages = tw.images ? (Array.isArray(tw.images) ? tw.images : [tw.images]) : [];\n for (const img of twImages) {\n meta.push({ name: 'twitter:image', content: img });\n }\n }\n\n // Canonical\n if (descriptor.canonical) links.push({ rel: 'canonical', href: descriptor.canonical });\n\n // hreflang alternates (React requires camelCase: hrefLang)\n for (const alt of descriptor.alternateLanguages ?? []) {\n links.push({ rel: 'alternate', hrefLang: alt.hreflang, href: alt.href });\n }\n\n // JSON-LD\n if (descriptor.jsonLd) {\n scripts.push({ type: 'application/ld+json', children: JSON.stringify(descriptor.jsonLd) });\n }\n\n // Escape hatches\n for (const m of descriptor.meta ?? []) {\n const { httpEquiv, ...rest } = m as typeof m & { httpEquiv?: string };\n meta.push(httpEquiv ? { httpEquiv, ...rest } : rest);\n }\n for (const l of descriptor.links ?? []) links.push(l);\n for (const s of descriptor.styles ?? []) styles.push(s as unknown as Record<string, unknown>);\n\n // Import maps must be emitted before module scripts that rely on bare specifiers.\n for (const im of descriptor.importMap ?? []) {\n scripts.push({ type: 'importmap', children: JSON.stringify(im) });\n }\n for (const s of descriptor.scripts ?? []) scripts.push(s);\n\n return { meta, links, styles, scripts };\n}\n\n// ============================================================================\n// withHead - Simplified head callback wrapper for TanStack Router\n// ============================================================================\n\n/** Twig's page title format: \"<page title> - <store meta title or store name>\". */\nfunction appendStoreTitle(\n descriptor: HeadDescriptor,\n settings: TwilightContext['settings']\n): HeadDescriptor {\n const store = settings?.store;\n const storeTitle = store?.meta?.title || store?.name;\n const pageTitle = descriptor.title;\n if (!pageTitle || !storeTitle || descriptor.appendStoreTitle === false) return descriptor;\n if (pageTitle === storeTitle) return descriptor;\n\n const title = `${pageTitle} - ${storeTitle}`;\n // Share titles follow the page title too, unless the route set its own.\n const shareTitle = (current?: string) => (!current || current === pageTitle ? title : current);\n return {\n ...descriptor,\n title,\n openGraph: { ...descriptor.openGraph, title: shareTitle(descriptor.openGraph?.title) },\n twitter: { ...descriptor.twitter, title: shareTitle(descriptor.twitter?.title) },\n };\n}\n\n/**\n * Twig's page URL for a page that names none: its own path on the store's domain, without the\n * query, as the canonical and the og:url and twitter:url share cards read.\n */\nfunction withPageUrl(descriptor: HeadDescriptor, ctx: TwilightContext): HeadDescriptor {\n const pathname = ctx.location?.pathname;\n const canonical =\n descriptor.canonical ?? (pathname ? storePageUrl(ctx.settings, pathname) : undefined);\n if (!canonical) return descriptor;\n return {\n ...descriptor,\n canonical,\n openGraph: { ...descriptor.openGraph, url: descriptor.openGraph?.url ?? canonical },\n twitter: { ...descriptor.twitter, url: descriptor.twitter?.url ?? canonical },\n };\n}\n\n/**\n * Minimal shape we need from TanStack Router's AssetFnContextOptions.\n * `loaderData` feeds the route's own head function; `matches` is the recovery\n * source for store settings when the twilight module store is not populated yet\n * (see `ensureTwilightContextFromMatches`).\n */\ntype HeadContext = {\n loaderData?: unknown;\n matches?: readonly TwilightContextMatch[];\n};\n\n/**\n * Wraps a route module's head function for TanStack Router.\n *\n * @example\n * ```typescript\n * head: withHead(Offers)\n * head: withHead(Product, (result) => ({ ...result, robots: 'noindex, follow' }))\n * ```\n */\nexport function withHead<T>(\n route: { head: (ctx: TwilightContext, data: T) => HeadDescriptor },\n extend?: (result: HeadDescriptor, _ctx: TwilightContext, data: T) => HeadDescriptor\n): (_ctx: Record<string, unknown>) => Record<string, unknown> {\n return (ctx: HeadContext) => {\n const loaderData = ctx.loaderData;\n\n if (!loaderData) return {};\n\n // TanStack re-runs every matched route's head() during client hydration,\n // where the twilight module store can still be empty. Recover it from the\n // match context TanStack has already resolved before giving up.\n ensureTwilightContextFromMatches(ctx.matches);\n\n try {\n const context = getTwilightContext();\n const result = route.head(context, loaderData as T);\n const extended = extend ? extend(result, context, loaderData as T) : result;\n const finalResult = withPageUrl(appendStoreTitle(extended, context.settings), context);\n\n return tanstackHeadAdapter(finalResult);\n } catch (error) {\n // A head function must never throw: TanStack surfaces the throw as a\n // hydration error, React then discards the server-rendered tree and the\n // storefront renders blank. Dropping this route's head tags degrades\n // gracefully — the server-rendered ones stay in the document.\n if (error instanceof SettingsError) return {};\n throw error;\n }\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/tanstack/head.ts"],"names":[],"mappings":"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","file":"chunk-4INSECDW.js","sourcesContent":["import type { HeadDescriptor, OpenGraphImage } from '../utils/head';\nimport type { TwilightContext } from '../twilight/context';\nimport { getTwilightContext } from '../twilight/context';\nimport type { TwilightContextMatch } from '../twilight/ensure-context';\nimport { ensureTwilightContextFromMatches } from '../twilight/ensure-context';\nimport { SettingsError } from '../utils/errors';\nimport { storePageUrl } from '../utils/baseHead';\n\ntype OgImagesInput = string | OpenGraphImage | Array<string | OpenGraphImage> | undefined;\n\nfunction normalizeOgImages(images: OgImagesInput): OpenGraphImage[] {\n if (!images) return [];\n const arr = Array.isArray(images) ? images : [images];\n return arr.map((img) => (typeof img === 'string' ? { url: img } : img));\n}\n\n/** Merchant descriptions are rich-text HTML; description meta tags take plain text. */\nfunction plainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>|<\\/(?:p|div|li|h[1-6])>/gi, ' ')\n .replace(/<[^>]*>/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function tanstackHeadAdapter(descriptor: HeadDescriptor) {\n const meta: Array<Record<string, unknown>> = [];\n const links: Array<Record<string, unknown>> = [];\n const scripts: Array<Record<string, unknown>> = [];\n const styles: Record<string, unknown>[] = [];\n\n if (descriptor.title) meta.push({ title: descriptor.title });\n if (descriptor.description)\n meta.push({ name: 'description', content: plainText(descriptor.description) });\n\n if (descriptor.keywords) {\n const kw = Array.isArray(descriptor.keywords)\n ? descriptor.keywords.join(', ')\n : descriptor.keywords;\n meta.push({ name: 'keywords', content: kw });\n }\n\n if (descriptor.robots) meta.push({ name: 'robots', content: descriptor.robots });\n\n // Open Graph\n const og = descriptor.openGraph;\n if (og) {\n if (og.siteName) meta.push({ property: 'og:site_name', content: og.siteName });\n if (og.type) meta.push({ property: 'og:type', content: og.type });\n if (og.title) meta.push({ property: 'og:title', content: og.title });\n if (og.description)\n meta.push({ property: 'og:description', content: plainText(og.description) });\n if (og.url) meta.push({ property: 'og:url', content: og.url });\n if (og.locale) meta.push({ property: 'og:locale', content: og.locale });\n for (const alt of og.alternateLocale ?? []) {\n meta.push({ property: 'og:locale:alternate', content: alt });\n }\n for (const img of normalizeOgImages(og.images)) {\n meta.push({ property: 'og:image', content: img.url });\n if (img.width != null) meta.push({ property: 'og:image:width', content: String(img.width) });\n if (img.height != null)\n meta.push({ property: 'og:image:height', content: String(img.height) });\n if (img.alt) meta.push({ property: 'og:image:alt', content: img.alt });\n }\n if (og.publishedTime)\n meta.push({ property: 'article:published_time', content: og.publishedTime });\n if (og.modifiedTime) meta.push({ property: 'article:modified_time', content: og.modifiedTime });\n }\n\n // Twitter Card\n const tw = descriptor.twitter;\n if (tw) {\n if (tw.card) meta.push({ name: 'twitter:card', content: tw.card });\n if (tw.title) meta.push({ name: 'twitter:title', content: tw.title });\n if (tw.description)\n meta.push({ name: 'twitter:description', content: plainText(tw.description) });\n if (tw.site) meta.push({ name: 'twitter:site', content: tw.site });\n if (tw.creator) meta.push({ name: 'twitter:creator', content: tw.creator });\n if (tw.url) meta.push({ name: 'twitter:url', content: tw.url });\n const twImages = tw.images ? (Array.isArray(tw.images) ? tw.images : [tw.images]) : [];\n for (const img of twImages) {\n meta.push({ name: 'twitter:image', content: img });\n }\n }\n\n // Canonical\n if (descriptor.canonical) links.push({ rel: 'canonical', href: descriptor.canonical });\n\n // hreflang alternates (React requires camelCase: hrefLang)\n for (const alt of descriptor.alternateLanguages ?? []) {\n links.push({ rel: 'alternate', hrefLang: alt.hreflang, href: alt.href });\n }\n\n // JSON-LD\n if (descriptor.jsonLd) {\n scripts.push({ type: 'application/ld+json', children: JSON.stringify(descriptor.jsonLd) });\n }\n\n // Escape hatches\n for (const m of descriptor.meta ?? []) {\n const { httpEquiv, ...rest } = m as typeof m & { httpEquiv?: string };\n meta.push(httpEquiv ? { httpEquiv, ...rest } : rest);\n }\n for (const l of descriptor.links ?? []) links.push(l);\n for (const s of descriptor.styles ?? []) styles.push(s as unknown as Record<string, unknown>);\n\n // Import maps must be emitted before module scripts that rely on bare specifiers.\n for (const im of descriptor.importMap ?? []) {\n scripts.push({ type: 'importmap', children: JSON.stringify(im) });\n }\n for (const s of descriptor.scripts ?? []) scripts.push(s);\n\n return { meta, links, styles, scripts };\n}\n\n// ============================================================================\n// withHead - Simplified head callback wrapper for TanStack Router\n// ============================================================================\n\n/** Twig's page title format: \"<page title> - <store meta title or store name>\". */\nfunction appendStoreTitle(\n descriptor: HeadDescriptor,\n settings: TwilightContext['settings']\n): HeadDescriptor {\n const store = settings?.store;\n const storeTitle = store?.meta?.title || store?.name;\n const pageTitle = descriptor.title;\n if (!pageTitle || !storeTitle || descriptor.appendStoreTitle === false) return descriptor;\n if (pageTitle === storeTitle) return descriptor;\n\n const title = `${pageTitle} - ${storeTitle}`;\n // Share titles follow the page title too, unless the route set its own.\n const shareTitle = (current?: string) => (!current || current === pageTitle ? title : current);\n return {\n ...descriptor,\n title,\n openGraph: { ...descriptor.openGraph, title: shareTitle(descriptor.openGraph?.title) },\n twitter: { ...descriptor.twitter, title: shareTitle(descriptor.twitter?.title) },\n };\n}\n\n/**\n * Twig's page URL for a page that names none: its own path on the store's domain, without the\n * query, as the canonical and the og:url and twitter:url share cards read.\n */\nfunction withPageUrl(descriptor: HeadDescriptor, ctx: TwilightContext): HeadDescriptor {\n const pathname = ctx.location?.pathname;\n const canonical =\n descriptor.canonical ?? (pathname ? storePageUrl(ctx.settings, pathname) : undefined);\n if (!canonical) return descriptor;\n return {\n ...descriptor,\n canonical,\n openGraph: { ...descriptor.openGraph, url: descriptor.openGraph?.url ?? canonical },\n twitter: { ...descriptor.twitter, url: descriptor.twitter?.url ?? canonical },\n };\n}\n\n/**\n * Minimal shape we need from TanStack Router's AssetFnContextOptions.\n * `loaderData` feeds the route's own head function; `matches` is the recovery\n * source for store settings when the twilight module store is not populated yet\n * (see `ensureTwilightContextFromMatches`).\n */\ntype HeadContext = {\n loaderData?: unknown;\n matches?: readonly TwilightContextMatch[];\n};\n\n/**\n * Wraps a route module's head function for TanStack Router.\n *\n * @example\n * ```typescript\n * head: withHead(Offers)\n * head: withHead(Product, (result) => ({ ...result, robots: 'noindex, follow' }))\n * ```\n */\nexport function withHead<T>(\n route: { head: (ctx: TwilightContext, data: T) => HeadDescriptor },\n extend?: (result: HeadDescriptor, _ctx: TwilightContext, data: T) => HeadDescriptor\n): (_ctx: Record<string, unknown>) => Record<string, unknown> {\n return (ctx: HeadContext) => {\n const loaderData = ctx.loaderData;\n\n if (!loaderData) return {};\n\n // TanStack re-runs every matched route's head() during client hydration,\n // where the twilight module store can still be empty. Recover it from the\n // match context TanStack has already resolved before giving up.\n ensureTwilightContextFromMatches(ctx.matches);\n\n try {\n const context = getTwilightContext();\n const result = route.head(context, loaderData as T);\n const extended = extend ? extend(result, context, loaderData as T) : result;\n const finalResult = withPageUrl(appendStoreTitle(extended, context.settings), context);\n\n return tanstackHeadAdapter(finalResult);\n } catch (error) {\n // A head function must never throw: TanStack surfaces the throw as a\n // hydration error, React then discards the server-rendered tree and the\n // storefront renders blank. Dropping this route's head tags degrades\n // gracefully — the server-rendered ones stay in the document.\n if (error instanceof SettingsError) return {};\n throw error;\n }\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { orThrow } from './chunk-UWDUMPL7.js';
2
- import { getActiveScope, api } from './chunk-YDSWLCOY.js';
1
+ import { orThrow } from './chunk-E5PEYI5I.js';
2
+ import { getActiveScope, api } from './chunk-BFA2U7P3.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  var category = {
@@ -26,5 +26,5 @@ var category = {
26
26
  };
27
27
 
28
28
  export { category };
29
- //# sourceMappingURL=chunk-VUWBGAET.js.map
30
- //# sourceMappingURL=chunk-VUWBGAET.js.map
29
+ //# sourceMappingURL=chunk-56OZRZIZ.js.map
30
+ //# sourceMappingURL=chunk-56OZRZIZ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/category.ts"],"names":[],"mappings":";;;;AAKO,IAAM,QAAA,GAAW;AAAA,EACtB,IAAA,EAAM,OAAO,EAAA,KAAkC;AAC7C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,WAAA,EAAc,EAAE,CAAA,CAAE,CAAA,CAAE,IAAA,EAAyB;AAC5E,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAAA,EAEA,aAAa,CAAC,EAAA,KAAkC,QAAQ,QAAA,CAAS,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,EAEzE,MAAM,YAAiC;AACrC,IAAA,MAAM,EAAE,MAAK,GAAI,MAAM,IAAI,GAAA,CAAI,YAAY,EAAE,IAAA,EAA2B;AACxE,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,CAAC,EAAA,KACP,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,YAAA,EAAc,QAAA,EAAU,EAAE,CAAA;AAAA,MACrC,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA,CAAK,EAAE;AAAA,KAChC,CAAA;AAAA,IAEH,IAAA,EAAM,MACJ,YAAA,CAAa;AAAA;AAAA,MAEX,QAAA,EAAU,CAAC,YAAA,EAAc,MAAA,EAAQ,EAAE,KAAA,EAAO,cAAA,IAAkB,CAAA;AAAA,MAC5D,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA;AAAK,KAC9B;AAAA;AAEP","file":"chunk-VUWBGAET.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { Category } from '../types';\nimport { orThrow } from '../providers/NavigationProvider';\n\nexport const category = {\n find: async (id: string): Promise<Category> => {\n const { data } = await api.get(`categories/${id}`).json<{ data: Category }>();\n return data;\n },\n\n findOrThrow: (id: string): Promise<Category> => orThrow(category.find(id)),\n\n list: async (): Promise<Category[]> => {\n const { data } = await api.get('categories').json<{ data: Category[] }>();\n return data ?? [];\n },\n\n queries: {\n detail: (id: string) =>\n queryOptions({\n queryKey: ['categories', 'detail', id],\n queryFn: () => category.find(id),\n }),\n\n list: () =>\n queryOptions({\n // Scope (branch) varies the API response — key must include it.\n queryKey: ['categories', 'list', { scope: getActiveScope() }],\n queryFn: () => category.list(),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/category.ts"],"names":[],"mappings":";;;;AAKO,IAAM,QAAA,GAAW;AAAA,EACtB,IAAA,EAAM,OAAO,EAAA,KAAkC;AAC7C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,WAAA,EAAc,EAAE,CAAA,CAAE,CAAA,CAAE,IAAA,EAAyB;AAC5E,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAAA,EAEA,aAAa,CAAC,EAAA,KAAkC,QAAQ,QAAA,CAAS,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,EAEzE,MAAM,YAAiC;AACrC,IAAA,MAAM,EAAE,MAAK,GAAI,MAAM,IAAI,GAAA,CAAI,YAAY,EAAE,IAAA,EAA2B;AACxE,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,CAAC,EAAA,KACP,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,YAAA,EAAc,QAAA,EAAU,EAAE,CAAA;AAAA,MACrC,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA,CAAK,EAAE;AAAA,KAChC,CAAA;AAAA,IAEH,IAAA,EAAM,MACJ,YAAA,CAAa;AAAA;AAAA,MAEX,QAAA,EAAU,CAAC,YAAA,EAAc,MAAA,EAAQ,EAAE,KAAA,EAAO,cAAA,IAAkB,CAAA;AAAA,MAC5D,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA;AAAK,KAC9B;AAAA;AAEP","file":"chunk-56OZRZIZ.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { Category } from '../types';\nimport { orThrow } from '../providers/NavigationProvider';\n\nexport const category = {\n find: async (id: string): Promise<Category> => {\n const { data } = await api.get(`categories/${id}`).json<{ data: Category }>();\n return data;\n },\n\n findOrThrow: (id: string): Promise<Category> => orThrow(category.find(id)),\n\n list: async (): Promise<Category[]> => {\n const { data } = await api.get('categories').json<{ data: Category[] }>();\n return data ?? [];\n },\n\n queries: {\n detail: (id: string) =>\n queryOptions({\n queryKey: ['categories', 'detail', id],\n queryFn: () => category.find(id),\n }),\n\n list: () =>\n queryOptions({\n // Scope (branch) varies the API response — key must include it.\n queryKey: ['categories', 'list', { scope: getActiveScope() }],\n queryFn: () => category.list(),\n }),\n },\n};\n"]}
@@ -1,5 +1,5 @@
1
- import { filesCdn, cdn } from './chunk-YDSWLCOY.js';
2
- import { storeTranslationsQueryKey, translationsQueryKey, composeMessages, isPlainObject } from './chunk-JNAJTCJD.js';
1
+ import { filesCdn, cdn } from './chunk-BFA2U7P3.js';
2
+ import { storeTranslationsQueryKey, translationsQueryKey, composeMessages, isPlainObject } from './chunk-QRHXAKJ3.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  var LEGACY_GLOBAL_FILE = "js/translations.json";
@@ -126,5 +126,5 @@ var translations = {
126
126
  };
127
127
 
128
128
  export { commonTranslationsPath, storeTranslationsPath, translations };
129
- //# sourceMappingURL=chunk-D7XWUD6T.js.map
130
- //# sourceMappingURL=chunk-D7XWUD6T.js.map
129
+ //# sourceMappingURL=chunk-6NV6T24C.js.map
130
+ //# sourceMappingURL=chunk-6NV6T24C.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/translations.ts"],"names":[],"mappings":"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","file":"chunk-D7XWUD6T.js","sourcesContent":["/**\n * @fileoverview Where a storefront's words come from.\n *\n * Two files, merged: the platform's copy for this language, and the merchant's\n * own edits for this language and this store. Both are plain JSON objects on\n * the uploader's CDN, one per language.\n *\n * ```\n * https://cdn.files.salla.network/translations/common/<locale>.json the platform's\n * https://cdn.files.salla.network/translations/<storeId>/<locale>.json the merchant's\n * ```\n *\n * **What this replaces, and why.** Until now the engine read a single global\n * file, `cdn.salla.network/js/translations.json`, holding every language keyed\n * `\"<locale>.trans\"`. Nothing publishes that file: it is an object last written\n * on 2026-03-26, carrying only `ar` and `en` where the platform has 39 locales,\n * 405 keys behind `Languages-Module` and 959 English strings textually\n * different from it. So every React storefront has been serving copy from\n * March, and a key added since has never reached one. It also carried no\n * merchant overrides at all — a merchant editing their theme's wording in the\n * Dashboard changed nothing on a React theme.\n *\n * **Merchant overrides are read, and only when there are any.** Getting here\n * took two corrections worth keeping.\n *\n * The first is the address. A merchant's own wording lives at\n * `translations/<storeId>/<locale>.json`, keyed by `store()->getRouteKey()` —\n * the Optimus-encoded numeric id. An early version addressed it with\n * `resolveStoreIdentifier()`, on the claim that the two are the same string.\n * That is true of the `store-identifier` *header*, which accepts a host, a\n * username or an id, and false of the R2 key: on a custom domain the resolver\n * returns `reefperfumes.com` and on a shared host a username like\n * `mtgr-alaatr-2`. Both 404, both then read as \"this store has no overrides\",\n * and the merchant's wording silently never appears — so the feature would have\n * worked under `?storeId=` alone, which is preview and localhost. It is\n * `settings.store.id` now, which is known only after the settings query.\n *\n * The second is when to ask at all. Most stores have never customised a word,\n * and a miss is an uncached round trip (`cf-cache-status: DYNAMIC` on the 404)\n * on the critical path of every SSR render. So the request is made only when\n * `settings.languages[<ISO>].has_custom_translations` says there is something\n * to get — a flag `Languages-Module` writes when a merchant saves a\n * translation. A store without overrides pays nothing, which is what made this\n * shippable at all.\n *\n * ⚠️ The flag is written on save, so a store whose wording predates it reads as\n * `false` until someone edits a translation or the backfill runs. That is a\n * store keeping today's behaviour, not a regression — React themes have never\n * read merchant overrides — but it does mean the feature is only as complete as\n * the backfill.\n *\n * **Rollout is by fallback, not by flag.** `translations/common/` is written by\n * a sync in the theme build service that may not have run yet, and a hard switch\n * would leave every storefront with no platform strings at all. A missing common\n * file therefore falls back to the old global one, which is exactly today's\n * behaviour — so this is safe to ship before the bucket is populated, and stops\n * using the fallback on its own once it is.\n */\nimport { queryOptions } from '@tanstack/react-query';\nimport { cdn, filesCdn } from './client';\nimport { storeTranslationsQueryKey, translationsQueryKey } from './translations-key';\nimport { composeMessages, isPlainObject, type Messages } from './messages';\nimport type { TranslationMessages } from '../providers/I18nProvider';\n\n/** The global file this used to be the only reader of. See the file comment. */\nconst LEGACY_GLOBAL_FILE = 'js/translations.json';\n\n/** One language of platform copy, shared by every store. */\nexport function commonTranslationsPath(locale: string): string {\n return `translations/common/${locale}.json`;\n}\n\n/**\n * One language of a single merchant's own wording.\n *\n * `storeId` is `settings.store.id`, which is the value `Languages-Module` names\n * the object with (`store()->getRouteKey()`, the Optimus-encoded numeric id).\n * It is **not** `resolveStoreIdentifier()`: that returns a hostname on a custom\n * domain and a username on a shared host, both of which 404 here and would read\n * as \"this merchant has no overrides\" — silently, on every store but a preview.\n */\nexport function storeTranslationsPath(storeId: string | number, locale: string): string {\n return `translations/${storeId}/${locale}.json`;\n}\n\n/**\n * Reads one language file, or `null` when there is nothing to read.\n *\n * A 404 is the ordinary answer, not a failure: most stores have never had a\n * word customised, so their file does not exist. Distinguishing it from a real\n * error matters only for the log — both end in `null` — but a warning on every\n * page load of every uncustomised store is a warning nobody will read.\n */\nasync function readLocaleFile(\n path: string,\n { failLoudly = false }: { failLoudly?: boolean } = {}\n): Promise<Messages | null> {\n /** A 404 always means \"absent\"; everything else is a failure to read. */\n const unreadable = (reason: string, cause?: unknown): null => {\n if (failLoudly) throw new Error(`[translations] ${path}: ${reason}`, { cause });\n console.warn('[translations]', reason, path, cause ?? '');\n return null;\n };\n\n try {\n const response = await filesCdn.get(path, { throwHttpErrors: false, timeout: 5000 });\n if (response.status === 404) return null;\n\n if (!response.ok) {\n return unreadable(`answered ${response.status}`);\n }\n\n const data: unknown = await response.json();\n if (!isPlainObject(data)) {\n return unreadable('is not a JSON object');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith('[translations]')) throw error;\n return unreadable('could not be read', error);\n }\n}\n\n/**\n * The pre-CDN global file, sliced to one language.\n *\n * Only reached when `translations/common/<locale>.json` is missing, which is\n * the state of the bucket until the sync has run once.\n */\nasync function readLegacyGlobal(locale: string): Promise<Messages | null> {\n try {\n const data = await cdn.get(LEGACY_GLOBAL_FILE, { timeout: 5000 }).json<TranslationMessages>();\n const forLocale = data?.[`${locale}.trans`];\n return isPlainObject(forLocale) ? forLocale : null;\n } catch {\n console.warn('[translations] the legacy global file could not be read either');\n return null;\n }\n}\n\nexport const translations = {\n /**\n * The platform's copy for `locale`.\n *\n * One file, so one request. See the file comment for why the merchant's own\n * wording is not merged in here yet and what it is waiting on.\n */\n get: async (locale: string): Promise<TranslationMessages | null> => {\n const common = await readLocaleFile(commonTranslationsPath(locale));\n const base = common ?? (await readLegacyGlobal(locale));\n if (!base) return null;\n\n // Still wrapped in the `<locale>.trans` shape the rest of the engine reads.\n // `createI18nInstance` slices by that key and so does the SDK bridge in\n // `I18nProvider`; changing the envelope here would be a second change for\n // no gain, since one language is all any of them ever take out of it.\n return { [`${locale}.trans`]: base as Record<string, string> };\n },\n\n /**\n * This merchant's own wording for `locale`, or `null` if they have none.\n *\n * Only worth calling when `settings.languages[<ISO>].has_custom_translations`\n * says there is something to get. Most stores have never customised a word,\n * and a miss here is an uncached round trip — `cf-cache-status: DYNAMIC` on a\n * 404 — on the critical path of an SSR render. The flag is what makes this\n * free for everyone who does not use it.\n *\n * Returned unwrapped, unlike {@link translations.get}: this is merged into\n * that one's messages rather than handed to i18next on its own.\n */\n forStore: async (storeId: string | number, locale: string): Promise<Messages | null> =>\n // `failLoudly`, unlike the platform file: this is only ever called because\n // the settings said overrides exist, so a 500, a timeout or a body that is\n // not JSON is a failure to read them — not a store that has none. Returning\n // `null` there would cache \"no overrides\" as a success, skip the query's\n // retry, and serve Salla's wording in place of the merchant's until the\n // entry expired. A 404 still means absent, and `rootBeforeLoad` catches the\n // throw and keeps the platform copy, so the worst case is unchanged.\n readLocaleFile(storeTranslationsPath(storeId, locale), { failLoudly: true }),\n\n /**\n * The platform's copy for `locale` with this merchant's wording laid over it.\n *\n * Takes the two as values rather than fetching them, so the caller decides\n * whether the second request happens at all and both stay separately cached.\n */\n /**\n * The platform's copy for `locale` with this merchant's wording over it.\n *\n * Delegates to `composeMessages`, which every other reader of these two\n * entries also uses — see `api/messages.ts` for why there is exactly one.\n */\n merge: (\n common: TranslationMessages | null,\n overrides: Messages | null,\n locale: string\n ): TranslationMessages | null => composeMessages(common, overrides, locale) ?? null,\n\n queries: {\n /**\n * @param locale taken as an argument rather than read from the twilight\n * context, and that is load-bearing. This key is built on the server, on\n * hydration, and again lazily from the context accessor; if any of the\n * three read a locale the others had not been given yet, the hydrated page\n * would miss the dehydrated entry and refetch both files it was just\n * handed. Every caller already has the locale in hand.\n *\n * The store is deliberately **not** in the key. One document serves one\n * store — a request that names a different one is redirected with\n * `reloadDocument`, so the client never changes store under a live cache —\n * and adding a value that resolves from the request on the server and from\n * the injected env on the client is how a key stops matching across\n * hydration.\n */\n byLocale: (locale: string) =>\n queryOptions({\n queryKey: translationsQueryKey(locale),\n queryFn: () => translations.get(locale),\n }),\n\n /**\n * This merchant's overrides, cached apart from the platform's copy.\n *\n * Its own entry rather than a wider `byLocale` key, so the common file is\n * fetched and dehydrated once per language whatever the store does, and a\n * store with no overrides never has an entry at all. Both sides compute the\n * key from the settings payload, so the hydrated page finds what the server\n * dehydrated instead of refetching it.\n */\n byStore: (storeId: string | number, locale: string) =>\n queryOptions({\n queryKey: storeTranslationsQueryKey(storeId, locale),\n queryFn: () => translations.forStore(storeId, locale),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/translations.ts"],"names":[],"mappings":";;;;AAiEA,IAAM,kBAAA,GAAqB,sBAAA;AAGpB,SAAS,uBAAuB,MAAA,EAAwB;AAC7D,EAAA,OAAO,uBAAuB,MAAM,CAAA,KAAA,CAAA;AACtC;AAWO,SAAS,qBAAA,CAAsB,SAA0B,MAAA,EAAwB;AACtF,EAAA,OAAO,CAAA,aAAA,EAAgB,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,KAAA,CAAA;AAC1C;AAUA,eAAe,eACb,IAAA,EACA,EAAE,aAAa,KAAA,EAAM,GAA8B,EAAC,EAC1B;AAE1B,EAAA,MAAM,UAAA,GAAa,CAAC,MAAA,EAAgB,KAAA,KAA0B;AAC5D,IAAA,IAAI,UAAA,EAAY,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,CAAA;AAC9E,IAAA,OAAA,CAAQ,IAAA,CAAK,gBAAA,EAAkB,MAAA,EAAQ,IAAA,EAAM,SAAS,EAAE,CAAA;AACxD,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAS,GAAA,CAAI,IAAA,EAAM,EAAE,eAAA,EAAiB,KAAA,EAAO,OAAA,EAAS,GAAA,EAAM,CAAA;AACnF,IAAA,IAAI,QAAA,CAAS,MAAA,KAAW,GAAA,EAAK,OAAO,IAAA;AAEpC,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,OAAO,UAAA,CAAW,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,IAAA,GAAgB,MAAM,QAAA,CAAS,IAAA,EAAK;AAC1C,IAAA,IAAI,CAAC,aAAA,CAAc,IAAI,CAAA,EAAG;AACxB,MAAA,OAAO,WAAW,sBAAsB,CAAA;AAAA,IAC1C;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,QAAQ,UAAA,CAAW,gBAAgB,GAAG,MAAM,KAAA;AAChF,IAAA,OAAO,UAAA,CAAW,qBAAqB,KAAK,CAAA;AAAA,EAC9C;AACF;AAQA,eAAe,iBAAiB,MAAA,EAA0C;AACxE,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,GAAA,CAAI,kBAAA,EAAoB,EAAE,OAAA,EAAS,GAAA,EAAM,CAAA,CAAE,IAAA,EAA0B;AAC5F,IAAA,MAAM,SAAA,GAAY,IAAA,GAAO,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,CAAA;AAC1C,IAAA,OAAO,aAAA,CAAc,SAAS,CAAA,GAAI,SAAA,GAAY,IAAA;AAAA,EAChD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,CAAQ,KAAK,gEAAgE,CAAA;AAC7E,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,IAAM,YAAA,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO1B,GAAA,EAAK,OAAO,MAAA,KAAwD;AAClE,IAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,sBAAA,CAAuB,MAAM,CAAC,CAAA;AAClE,IAAA,MAAM,IAAA,GAAO,MAAA,IAAW,MAAM,gBAAA,CAAiB,MAAM,CAAA;AACrD,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAMlB,IAAA,OAAO,EAAE,CAAC,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,GAAG,IAAA,EAA+B;AAAA,EAC/D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,QAAA,EAAU,OAAO,OAAA,EAA0B,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQzC,cAAA,CAAe,sBAAsB,OAAA,EAAS,MAAM,GAAG,EAAE,UAAA,EAAY,MAAM;AAAA,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc7E,KAAA,EAAO,CACL,MAAA,EACA,SAAA,EACA,WAC+B,eAAA,CAAgB,MAAA,EAAQ,SAAA,EAAW,MAAM,CAAA,IAAK,IAAA;AAAA,EAE/E,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBP,QAAA,EAAU,CAAC,MAAA,KACT,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,qBAAqB,MAAM,CAAA;AAAA,MACrC,OAAA,EAAS,MAAM,YAAA,CAAa,GAAA,CAAI,MAAM;AAAA,KACvC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWH,OAAA,EAAS,CAAC,OAAA,EAA0B,MAAA,KAClC,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,yBAAA,CAA0B,OAAA,EAAS,MAAM,CAAA;AAAA,MACnD,OAAA,EAAS,MAAM,YAAA,CAAa,QAAA,CAAS,SAAS,MAAM;AAAA,KACrD;AAAA;AAEP","file":"chunk-6NV6T24C.js","sourcesContent":["/**\n * @fileoverview Where a storefront's words come from.\n *\n * Two files, merged: the platform's copy for this language, and the merchant's\n * own edits for this language and this store. Both are plain JSON objects on\n * the uploader's CDN, one per language.\n *\n * ```\n * https://cdn.files.salla.network/translations/common/<locale>.json the platform's\n * https://cdn.files.salla.network/translations/<storeId>/<locale>.json the merchant's\n * ```\n *\n * **What this replaces, and why.** Until now the engine read a single global\n * file, `cdn.salla.network/js/translations.json`, holding every language keyed\n * `\"<locale>.trans\"`. Nothing publishes that file: it is an object last written\n * on 2026-03-26, carrying only `ar` and `en` where the platform has 39 locales,\n * 405 keys behind `Languages-Module` and 959 English strings textually\n * different from it. So every React storefront has been serving copy from\n * March, and a key added since has never reached one. It also carried no\n * merchant overrides at all — a merchant editing their theme's wording in the\n * Dashboard changed nothing on a React theme.\n *\n * **Merchant overrides are read, and only when there are any.** Getting here\n * took two corrections worth keeping.\n *\n * The first is the address. A merchant's own wording lives at\n * `translations/<storeId>/<locale>.json`, keyed by `store()->getRouteKey()` —\n * the Optimus-encoded numeric id. An early version addressed it with\n * `resolveStoreIdentifier()`, on the claim that the two are the same string.\n * That is true of the `store-identifier` *header*, which accepts a host, a\n * username or an id, and false of the R2 key: on a custom domain the resolver\n * returns `reefperfumes.com` and on a shared host a username like\n * `mtgr-alaatr-2`. Both 404, both then read as \"this store has no overrides\",\n * and the merchant's wording silently never appears — so the feature would have\n * worked under `?storeId=` alone, which is preview and localhost. It is\n * `settings.store.id` now, which is known only after the settings query.\n *\n * The second is when to ask at all. Most stores have never customised a word,\n * and a miss is an uncached round trip (`cf-cache-status: DYNAMIC` on the 404)\n * on the critical path of every SSR render. So the request is made only when\n * `settings.languages[<ISO>].has_custom_translations` says there is something\n * to get — a flag `Languages-Module` writes when a merchant saves a\n * translation. A store without overrides pays nothing, which is what made this\n * shippable at all.\n *\n * ⚠️ The flag is written on save, so a store whose wording predates it reads as\n * `false` until someone edits a translation or the backfill runs. That is a\n * store keeping today's behaviour, not a regression — React themes have never\n * read merchant overrides — but it does mean the feature is only as complete as\n * the backfill.\n *\n * **Rollout is by fallback, not by flag.** `translations/common/` is written by\n * a sync in the theme build service that may not have run yet, and a hard switch\n * would leave every storefront with no platform strings at all. A missing common\n * file therefore falls back to the old global one, which is exactly today's\n * behaviour — so this is safe to ship before the bucket is populated, and stops\n * using the fallback on its own once it is.\n */\nimport { queryOptions } from '@tanstack/react-query';\nimport { cdn, filesCdn } from './client';\nimport { storeTranslationsQueryKey, translationsQueryKey } from './translations-key';\nimport { composeMessages, isPlainObject, type Messages } from './messages';\nimport type { TranslationMessages } from '../providers/I18nProvider';\n\n/** The global file this used to be the only reader of. See the file comment. */\nconst LEGACY_GLOBAL_FILE = 'js/translations.json';\n\n/** One language of platform copy, shared by every store. */\nexport function commonTranslationsPath(locale: string): string {\n return `translations/common/${locale}.json`;\n}\n\n/**\n * One language of a single merchant's own wording.\n *\n * `storeId` is `settings.store.id`, which is the value `Languages-Module` names\n * the object with (`store()->getRouteKey()`, the Optimus-encoded numeric id).\n * It is **not** `resolveStoreIdentifier()`: that returns a hostname on a custom\n * domain and a username on a shared host, both of which 404 here and would read\n * as \"this merchant has no overrides\" — silently, on every store but a preview.\n */\nexport function storeTranslationsPath(storeId: string | number, locale: string): string {\n return `translations/${storeId}/${locale}.json`;\n}\n\n/**\n * Reads one language file, or `null` when there is nothing to read.\n *\n * A 404 is the ordinary answer, not a failure: most stores have never had a\n * word customised, so their file does not exist. Distinguishing it from a real\n * error matters only for the log — both end in `null` — but a warning on every\n * page load of every uncustomised store is a warning nobody will read.\n */\nasync function readLocaleFile(\n path: string,\n { failLoudly = false }: { failLoudly?: boolean } = {}\n): Promise<Messages | null> {\n /** A 404 always means \"absent\"; everything else is a failure to read. */\n const unreadable = (reason: string, cause?: unknown): null => {\n if (failLoudly) throw new Error(`[translations] ${path}: ${reason}`, { cause });\n console.warn('[translations]', reason, path, cause ?? '');\n return null;\n };\n\n try {\n const response = await filesCdn.get(path, { throwHttpErrors: false, timeout: 5000 });\n if (response.status === 404) return null;\n\n if (!response.ok) {\n return unreadable(`answered ${response.status}`);\n }\n\n const data: unknown = await response.json();\n if (!isPlainObject(data)) {\n return unreadable('is not a JSON object');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith('[translations]')) throw error;\n return unreadable('could not be read', error);\n }\n}\n\n/**\n * The pre-CDN global file, sliced to one language.\n *\n * Only reached when `translations/common/<locale>.json` is missing, which is\n * the state of the bucket until the sync has run once.\n */\nasync function readLegacyGlobal(locale: string): Promise<Messages | null> {\n try {\n const data = await cdn.get(LEGACY_GLOBAL_FILE, { timeout: 5000 }).json<TranslationMessages>();\n const forLocale = data?.[`${locale}.trans`];\n return isPlainObject(forLocale) ? forLocale : null;\n } catch {\n console.warn('[translations] the legacy global file could not be read either');\n return null;\n }\n}\n\nexport const translations = {\n /**\n * The platform's copy for `locale`.\n *\n * One file, so one request. See the file comment for why the merchant's own\n * wording is not merged in here yet and what it is waiting on.\n */\n get: async (locale: string): Promise<TranslationMessages | null> => {\n const common = await readLocaleFile(commonTranslationsPath(locale));\n const base = common ?? (await readLegacyGlobal(locale));\n if (!base) return null;\n\n // Still wrapped in the `<locale>.trans` shape the rest of the engine reads.\n // `createI18nInstance` slices by that key and so does the SDK bridge in\n // `I18nProvider`; changing the envelope here would be a second change for\n // no gain, since one language is all any of them ever take out of it.\n return { [`${locale}.trans`]: base as Record<string, string> };\n },\n\n /**\n * This merchant's own wording for `locale`, or `null` if they have none.\n *\n * Only worth calling when `settings.languages[<ISO>].has_custom_translations`\n * says there is something to get. Most stores have never customised a word,\n * and a miss here is an uncached round trip — `cf-cache-status: DYNAMIC` on a\n * 404 — on the critical path of an SSR render. The flag is what makes this\n * free for everyone who does not use it.\n *\n * Returned unwrapped, unlike {@link translations.get}: this is merged into\n * that one's messages rather than handed to i18next on its own.\n */\n forStore: async (storeId: string | number, locale: string): Promise<Messages | null> =>\n // `failLoudly`, unlike the platform file: this is only ever called because\n // the settings said overrides exist, so a 500, a timeout or a body that is\n // not JSON is a failure to read them — not a store that has none. Returning\n // `null` there would cache \"no overrides\" as a success, skip the query's\n // retry, and serve Salla's wording in place of the merchant's until the\n // entry expired. A 404 still means absent, and `rootBeforeLoad` catches the\n // throw and keeps the platform copy, so the worst case is unchanged.\n readLocaleFile(storeTranslationsPath(storeId, locale), { failLoudly: true }),\n\n /**\n * The platform's copy for `locale` with this merchant's wording laid over it.\n *\n * Takes the two as values rather than fetching them, so the caller decides\n * whether the second request happens at all and both stay separately cached.\n */\n /**\n * The platform's copy for `locale` with this merchant's wording over it.\n *\n * Delegates to `composeMessages`, which every other reader of these two\n * entries also uses — see `api/messages.ts` for why there is exactly one.\n */\n merge: (\n common: TranslationMessages | null,\n overrides: Messages | null,\n locale: string\n ): TranslationMessages | null => composeMessages(common, overrides, locale) ?? null,\n\n queries: {\n /**\n * @param locale taken as an argument rather than read from the twilight\n * context, and that is load-bearing. This key is built on the server, on\n * hydration, and again lazily from the context accessor; if any of the\n * three read a locale the others had not been given yet, the hydrated page\n * would miss the dehydrated entry and refetch both files it was just\n * handed. Every caller already has the locale in hand.\n *\n * The store is deliberately **not** in the key. One document serves one\n * store — a request that names a different one is redirected with\n * `reloadDocument`, so the client never changes store under a live cache —\n * and adding a value that resolves from the request on the server and from\n * the injected env on the client is how a key stops matching across\n * hydration.\n */\n byLocale: (locale: string) =>\n queryOptions({\n queryKey: translationsQueryKey(locale),\n queryFn: () => translations.get(locale),\n }),\n\n /**\n * This merchant's overrides, cached apart from the platform's copy.\n *\n * Its own entry rather than a wider `byLocale` key, so the common file is\n * fetched and dehydrated once per language whatever the store does, and a\n * store with no overrides never has an entry at all. Both sides compute the\n * key from the settings payload, so the hydrated page finds what the server\n * dehydrated instead of refetching it.\n */\n byStore: (storeId: string | number, locale: string) =>\n queryOptions({\n queryKey: storeTranslationsQueryKey(storeId, locale),\n queryFn: () => translations.forStore(storeId, locale),\n }),\n },\n};\n"]}
@@ -1,6 +1,6 @@
1
- import { orThrow } from './chunk-UWDUMPL7.js';
2
- import { getActiveScope, api } from './chunk-YDSWLCOY.js';
3
- import { getTwilightContext } from './chunk-JNAJTCJD.js';
1
+ import { orThrow } from './chunk-E5PEYI5I.js';
2
+ import { getActiveScope, api } from './chunk-BFA2U7P3.js';
3
+ import { getTwilightContext } from './chunk-QRHXAKJ3.js';
4
4
  import { defaultShouldDehydrateQuery, queryOptions } from '@tanstack/react-query';
5
5
 
6
6
  function queryClientOrNull() {
@@ -194,5 +194,5 @@ var product = {
194
194
  };
195
195
 
196
196
  export { getProductPreview, isProductPreviewQuery, parseNextPageToken, product, productDetailQueryKey, productPreviewQueryKey, rememberProductPreview, shouldDehydrateQuery };
197
- //# sourceMappingURL=chunk-SQXUWX4B.js.map
198
- //# sourceMappingURL=chunk-SQXUWX4B.js.map
197
+ //# sourceMappingURL=chunk-6T7FUHJY.js.map
198
+ //# sourceMappingURL=chunk-6T7FUHJY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/product.ts"],"names":["product"],"mappings":"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","file":"chunk-SQXUWX4B.js","sourcesContent":["import { queryOptions, defaultShouldDehydrateQuery } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { Product } from '../types';\nimport type { Pagination, PaginatedResult } from './types';\nimport { orThrow } from '../providers/NavigationProvider';\nimport { getTwilightContext } from '../twilight/context';\nimport type { ActiveScope } from '../utils/cookies';\n\n// ===== Filter Types =====\n\nexport interface FilterValue {\n key?: string;\n count?: number;\n value?: string;\n from?: number | '*';\n to?: number | '*';\n}\n\nexport interface Filter {\n key?: string;\n label?: string;\n type?: string;\n values?: FilterValue[];\n max?: number;\n min?: number;\n}\n\n// ===== Product List Types =====\n\nexport type ProductsListSource =\n | 'brands'\n | 'categories'\n | 'json'\n | 'landing-page'\n | 'latest'\n | 'offers'\n | 'recently'\n | 'related'\n | 'selected'\n | 'tags'\n | 'top-rated'\n | 'wishlist'\n | 'search'\n | 'sales'\n | 'reorder'\n | 'best_selling';\n\nexport interface ProductsListParams {\n /** Source type (wishlist, latest, brands, etc.) */\n source: ProductsListSource;\n /**\n * The ids the source reads, as an array: category, brand, tag or product ids\n * (`sourceValue: [708738657]`). Sent as `source_value[]`.\n */\n sourceValue?: string | number | number[] | null;\n /** The search words when `source` is `'search'`. Sent as `keyword`; other sources ignore it. */\n keyword?: string;\n /** Page number for offset-based pagination */\n page?: number;\n /** Cursor for cursor-based pagination (from previous response) */\n cursor?: string | null;\n /** Items per page (default: 15) */\n perPage?: number;\n /** Sort option */\n sort?: string;\n /** Enable filters on the response */\n filterable?: boolean;\n /** Applied `<salla-filters>` selection (the `salla-filters::changed` payload). */\n filters?: ProductListFilters;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n}\n\n/** One `<salla-filters>` value: a scalar, a list, or a nested `{ sub-key: value }` (variants). */\nexport type ProductListFilterValue =\n string | number | Array<string | number> | { [key: string]: ProductListFilterValue };\n\n/** A `<salla-filters>` selection, i.e. the `salla-filters::changed` payload. */\nexport type ProductListFilters = Record<string, ProductListFilterValue>;\n\nexport type ProductsListResult = PaginatedResult<Product> & {\n filters?: Filter[];\n};\n\nexport interface ProductsListResponse {\n data: Product[];\n cursor?: Pagination;\n filters?: Filter[];\n}\n\n// ===== List-card preview cache =====\n// List payloads are a subset of details (one `image`, no `options` / `images[]`).\n// They live on a separate query key so they can paint a sheet/quick-view without\n// being treated as a successful `products/{id}/details` fetch.\n\nfunction queryClientOrNull() {\n try {\n const queryClient = getTwilightContext().queryClient;\n return queryClient && typeof queryClient.setQueryData === 'function' ? queryClient : null;\n } catch {\n return null;\n }\n}\n\nexport function productPreviewQueryKey(id: string) {\n return ['products', 'preview', String(id), { scope: getActiveScope() }] as const;\n}\n\nexport function productDetailQueryKey(id: string) {\n return ['products', 'detail', id, { scope: getActiveScope() }] as const;\n}\n\n/** True when this query is a list-card stand-in — skip it when dehydrating SSR. */\nexport function isProductPreviewQuery(query: { queryKey: readonly unknown[] }): boolean {\n return query.queryKey[0] === 'products' && query.queryKey[1] === 'preview';\n}\n\n/**\n * Default dehydrate policy (success) plus pending SSR-stream queries, minus\n * list-card stand-ins. Replacing the default wholesale would ship error states.\n */\nexport function shouldDehydrateQuery(\n query: Parameters<typeof defaultShouldDehydrateQuery>[0]\n): boolean {\n return (\n !isProductPreviewQuery(query) &&\n (defaultShouldDehydrateQuery(query) || query.state.status === 'pending')\n );\n}\n\n/**\n * Remember a list/card product so `product.queries.detail(id)` can use it as\n * `placeholderData` while details load. No-op if details for this id are already\n * cached. Themes that fetch products outside `product.list` should call this.\n */\nexport function rememberProductPreview(product: Product): void {\n const queryClient = queryClientOrNull();\n if (!queryClient || product?.id == null) return;\n const id = String(product.id);\n if (queryClient.getQueryState(productDetailQueryKey(id))?.status === 'success') return;\n queryClient.setQueryData(productPreviewQueryKey(id), product);\n}\n\nfunction scopeFromQueryKey(queryKey: readonly unknown[]): ActiveScope | null | undefined {\n const last = queryKey[queryKey.length - 1];\n if (last == null || typeof last !== 'object' || !('scope' in last)) return undefined;\n return (last as { scope: ActiveScope | null }).scope;\n}\n\nfunction isSameScope(a: ActiveScope | null | undefined, b: ActiveScope | null): boolean {\n if (a === undefined) return false;\n if (a === b) return true;\n if (a == null || b == null) return a == null && b == null;\n return (\n a.id === b.id &&\n a.type === b.type &&\n a.allocation_id === b.allocation_id &&\n a.allocation_type === b.allocation_type\n );\n}\n\nconst LIST_QUERY_PREFIXES = [\n ['products', 'list'],\n ['wishlist', 'list'],\n] as const;\n\n/**\n * Rebuild the scoped preview index from hydrated list/wishlist queries (SSR\n * dehydrate drops preview keys). Subsequent lookups hit `productPreviewQueryKey`.\n */\nfunction findProductInScopedLists(\n queryClient: NonNullable<ReturnType<typeof queryClientOrNull>>,\n id: string\n): Product | undefined {\n const scope = getActiveScope();\n let found: Product | undefined;\n for (const prefix of LIST_QUERY_PREFIXES) {\n for (const [queryKey, data] of queryClient.getQueriesData<ProductsListResult>({\n queryKey: prefix,\n })) {\n if (!isSameScope(scopeFromQueryKey(queryKey), scope)) continue;\n for (const item of data?.items ?? []) {\n if (item?.id == null) continue;\n rememberProductPreview(item);\n if (!found && String(item.id) === id) found = item;\n }\n }\n }\n return found;\n}\n\n/**\n * List-card product for `placeholderData`. Prefers the preview key; if that was\n * dropped on SSR dehydrate, rebuilds it from the current-scope list/wishlist.\n */\nexport function getProductPreview(id: string): Product | undefined {\n const queryClient = queryClientOrNull();\n if (!queryClient) return undefined;\n const key = String(id);\n return (\n queryClient.getQueryData(productPreviewQueryKey(key)) ??\n findProductInScopedLists(queryClient, key)\n );\n}\n\nfunction rememberProductPreviews(items: Product[]): void {\n for (const item of items) rememberProductPreview(item);\n}\n\n/**\n * Search sends its words as `keyword` (a `sourceValue` string is still read there, as before);\n * every other source sends its ids as `source_value[]`, which the API requires as an array.\n */\nfunction appendSourceParams(\n searchParams: URLSearchParams,\n { source, sourceValue, keyword }: Pick<ProductsListParams, 'source' | 'sourceValue' | 'keyword'>\n): void {\n if (source === 'search') {\n const words = keyword ?? sourceValue;\n if (words !== undefined) searchParams.set('keyword', String(words));\n } else if (Array.isArray(sourceValue)) {\n sourceValue.forEach((val) => searchParams.append('source_value[]', String(val)));\n } else if (sourceValue !== undefined) {\n searchParams.append('source_value[]', String(sourceValue));\n }\n}\n\n/**\n * Sends an applied filter selection the way the SDK's `<salla-products-list>` does:\n * `filters[key]=v`, `filters[key][]=v` or `filters[key][sub]=v`.\n */\nfunction appendFilterParams(\n searchParams: URLSearchParams,\n filters?: Record<string, ProductListFilterValue>,\n parentKey = 'filters'\n): void {\n if (!filters) return;\n for (const [key, value] of Object.entries(filters)) {\n const fullKey = `${parentKey}[${key}]`;\n if (Array.isArray(value)) {\n value.forEach((item) => searchParams.append(`${fullKey}[]`, String(item)));\n } else if (value !== null && typeof value === 'object') {\n appendFilterParams(searchParams, value, fullKey);\n } else if (value !== undefined && value !== null) {\n searchParams.append(fullKey, String(value));\n }\n }\n}\n\n/** A `category_id` filter replaces the page's category as the list source (as in the SDK). */\nfunction categoryFilterIds(filters?: ProductListFilters): number[] | null {\n const raw = filters?.category_id;\n if (raw === undefined || raw === null) return null;\n const ids = Array.isArray(raw) ? raw : typeof raw === 'object' ? Object.values(raw) : [raw];\n return ids.map(Number);\n}\n\n// ===== Pagination =====\n\n/**\n * The API's own `cursor.next` (the previous page's response) is usually a\n * bare opaque cursor token, but for sources that don't support true\n * cursor-based pagination (observed: `source=offers`) it's instead a full\n * next-page URL carrying its own `page=N` — and no `cursor=` param at all.\n *\n * Passing that whole URL straight through as `list()`'s own `cursor` used to\n * smuggle its embedded `source` / `per_page` / `sort` into the request on\n * top of the ones `list()` already sets unconditionally, producing a\n * doubled query string (`source=offers&source=offers&...`) the API can't\n * paginate from correctly — every subsequent scroll re-fetched the exact\n * same first page instead of advancing. Pulling just the `page` number back\n * out here, the same way an actual `cursor=` is already pulled out, keeps\n * `list()`'s request to the one copy of each param it's supposed to have.\n */\nexport function parseNextPageToken(nextUrl: string | null | undefined): {\n cursor?: string;\n page?: number;\n} {\n if (!nextUrl) return {};\n\n const cursorMatch = nextUrl.match(/[?&]cursor=([^&]+)/);\n if (cursorMatch) return { cursor: decodeURIComponent(cursorMatch[1]) };\n\n const pageMatch = nextUrl.match(/[?&]page=([^&]+)/);\n if (pageMatch) {\n const page = Number(decodeURIComponent(pageMatch[1]));\n if (Number.isFinite(page)) return { page };\n }\n\n // Neither pattern matched: not a URL at all, just the bare opaque token itself.\n return { cursor: nextUrl };\n}\n\n// ===== API Functions =====\n\nexport const product = {\n find: async (id: string): Promise<Product> => {\n const endpoint = `products/${id}/details?with[]=images&with[]=category&with[]=rating&with[]=notify_availability&with[]=tags&with[]=brand&with[]=options&with[]=skus&with[]=skus_availability&with[]=included_products&with[]=bundle&with[]=sold_quantity`;\n const { data } = await api.get(endpoint).json<{ data: Product }>();\n return data;\n },\n\n findOrThrow: (id: string): Promise<Product> => orThrow(product.find(id)),\n\n /** A tag's name. The list endpoint returns every product for an unknown tag; this one answers 410. */\n tag: async (id: string): Promise<{ id: number; name: string }> => {\n const { tag } = await api\n .get(`products/tags/${id}`)\n .json<{ tag: { id: number; name: string } }>();\n return tag;\n },\n\n /**\n * Fetch products list with pagination support\n * Used by native ProductsList component for SSR loaders\n *\n * API pattern: GET /products?source=wishlist&page=1\n */\n list: async (params: ProductsListParams): Promise<ProductsListResult> => {\n const {\n source,\n sourceValue,\n keyword,\n page,\n cursor,\n perPage = 16,\n sort,\n filterable,\n filters,\n signal,\n } = params;\n\n // Build URL with query parameters\n const searchParams = new URLSearchParams();\n searchParams.set('source', source);\n // Only send page when explicitly provided — cursor-based callers omit it entirely\n if (page !== undefined) searchParams.set('page', String(page));\n searchParams.set('per_page', String(perPage));\n\n appendSourceParams(searchParams, {\n source,\n sourceValue: (source === 'categories' && categoryFilterIds(filters)) || sourceValue,\n keyword,\n });\n appendFilterParams(searchParams, filters);\n\n // Add filterable parameter\n if (filterable !== undefined) {\n searchParams.set('filterable', filterable ? '1' : '0');\n }\n\n // Add sort parameter\n if (sort) {\n searchParams.set('sort', sort);\n }\n\n // Add cursor for cursor-based pagination\n if (cursor) {\n searchParams.set('cursor', cursor);\n }\n\n // Make the request\n const options: Record<string, unknown> = {};\n if (signal) options.signal = signal;\n\n const response = await api\n .get(`products?${searchParams.toString()}`, options as any)\n .json<ProductsListResponse>();\n\n const items = response.data ?? [];\n rememberProductPreviews(items);\n\n return {\n items,\n next: response.cursor?.next ?? null,\n filters: response.filters,\n };\n },\n\n queries: {\n detail: (id: string) =>\n queryOptions({\n // Stock and availability are resolved per branch allocation — same as the list.\n queryKey: productDetailQueryKey(id),\n queryFn: () => product.find(id),\n // List-card product, if one was remembered. Not written as the detail\n // cache entry — `queryFn` still hits products/{id}/details.\n placeholderData: () => getProductPreview(id),\n }),\n tag: (id: string) =>\n queryOptions({\n queryKey: ['products', 'tag', id],\n queryFn: () => product.tag(id),\n }),\n list: (params: Omit<ProductsListParams, 'signal'>) =>\n queryOptions({\n // Scope (branch) varies product availability — key must include it.\n queryKey: ['products', 'list', params, { scope: getActiveScope() }],\n queryFn: ({ signal }) => product.list({ ...params, signal }),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/product.ts"],"names":["product"],"mappings":"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","file":"chunk-6T7FUHJY.js","sourcesContent":["import { queryOptions, defaultShouldDehydrateQuery } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { Product } from '../types';\nimport type { Pagination, PaginatedResult } from './types';\nimport { orThrow } from '../providers/NavigationProvider';\nimport { getTwilightContext } from '../twilight/context';\nimport type { ActiveScope } from '../utils/cookies';\n\n// ===== Filter Types =====\n\nexport interface FilterValue {\n key?: string;\n count?: number;\n value?: string;\n from?: number | '*';\n to?: number | '*';\n}\n\nexport interface Filter {\n key?: string;\n label?: string;\n type?: string;\n values?: FilterValue[];\n max?: number;\n min?: number;\n}\n\n// ===== Product List Types =====\n\nexport type ProductsListSource =\n | 'brands'\n | 'categories'\n | 'json'\n | 'landing-page'\n | 'latest'\n | 'offers'\n | 'recently'\n | 'related'\n | 'selected'\n | 'tags'\n | 'top-rated'\n | 'wishlist'\n | 'search'\n | 'sales'\n | 'reorder'\n | 'best_selling';\n\nexport interface ProductsListParams {\n /** Source type (wishlist, latest, brands, etc.) */\n source: ProductsListSource;\n /**\n * The ids the source reads, as an array: category, brand, tag or product ids\n * (`sourceValue: [708738657]`). Sent as `source_value[]`.\n */\n sourceValue?: string | number | number[] | null;\n /** The search words when `source` is `'search'`. Sent as `keyword`; other sources ignore it. */\n keyword?: string;\n /** Page number for offset-based pagination */\n page?: number;\n /** Cursor for cursor-based pagination (from previous response) */\n cursor?: string | null;\n /** Items per page (default: 15) */\n perPage?: number;\n /** Sort option */\n sort?: string;\n /** Enable filters on the response */\n filterable?: boolean;\n /** Applied `<salla-filters>` selection (the `salla-filters::changed` payload). */\n filters?: ProductListFilters;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n}\n\n/** One `<salla-filters>` value: a scalar, a list, or a nested `{ sub-key: value }` (variants). */\nexport type ProductListFilterValue =\n string | number | Array<string | number> | { [key: string]: ProductListFilterValue };\n\n/** A `<salla-filters>` selection, i.e. the `salla-filters::changed` payload. */\nexport type ProductListFilters = Record<string, ProductListFilterValue>;\n\nexport type ProductsListResult = PaginatedResult<Product> & {\n filters?: Filter[];\n};\n\nexport interface ProductsListResponse {\n data: Product[];\n cursor?: Pagination;\n filters?: Filter[];\n}\n\n// ===== List-card preview cache =====\n// List payloads are a subset of details (one `image`, no `options` / `images[]`).\n// They live on a separate query key so they can paint a sheet/quick-view without\n// being treated as a successful `products/{id}/details` fetch.\n\nfunction queryClientOrNull() {\n try {\n const queryClient = getTwilightContext().queryClient;\n return queryClient && typeof queryClient.setQueryData === 'function' ? queryClient : null;\n } catch {\n return null;\n }\n}\n\nexport function productPreviewQueryKey(id: string) {\n return ['products', 'preview', String(id), { scope: getActiveScope() }] as const;\n}\n\nexport function productDetailQueryKey(id: string) {\n return ['products', 'detail', id, { scope: getActiveScope() }] as const;\n}\n\n/** True when this query is a list-card stand-in — skip it when dehydrating SSR. */\nexport function isProductPreviewQuery(query: { queryKey: readonly unknown[] }): boolean {\n return query.queryKey[0] === 'products' && query.queryKey[1] === 'preview';\n}\n\n/**\n * Default dehydrate policy (success) plus pending SSR-stream queries, minus\n * list-card stand-ins. Replacing the default wholesale would ship error states.\n */\nexport function shouldDehydrateQuery(\n query: Parameters<typeof defaultShouldDehydrateQuery>[0]\n): boolean {\n return (\n !isProductPreviewQuery(query) &&\n (defaultShouldDehydrateQuery(query) || query.state.status === 'pending')\n );\n}\n\n/**\n * Remember a list/card product so `product.queries.detail(id)` can use it as\n * `placeholderData` while details load. No-op if details for this id are already\n * cached. Themes that fetch products outside `product.list` should call this.\n */\nexport function rememberProductPreview(product: Product): void {\n const queryClient = queryClientOrNull();\n if (!queryClient || product?.id == null) return;\n const id = String(product.id);\n if (queryClient.getQueryState(productDetailQueryKey(id))?.status === 'success') return;\n queryClient.setQueryData(productPreviewQueryKey(id), product);\n}\n\nfunction scopeFromQueryKey(queryKey: readonly unknown[]): ActiveScope | null | undefined {\n const last = queryKey[queryKey.length - 1];\n if (last == null || typeof last !== 'object' || !('scope' in last)) return undefined;\n return (last as { scope: ActiveScope | null }).scope;\n}\n\nfunction isSameScope(a: ActiveScope | null | undefined, b: ActiveScope | null): boolean {\n if (a === undefined) return false;\n if (a === b) return true;\n if (a == null || b == null) return a == null && b == null;\n return (\n a.id === b.id &&\n a.type === b.type &&\n a.allocation_id === b.allocation_id &&\n a.allocation_type === b.allocation_type\n );\n}\n\nconst LIST_QUERY_PREFIXES = [\n ['products', 'list'],\n ['wishlist', 'list'],\n] as const;\n\n/**\n * Rebuild the scoped preview index from hydrated list/wishlist queries (SSR\n * dehydrate drops preview keys). Subsequent lookups hit `productPreviewQueryKey`.\n */\nfunction findProductInScopedLists(\n queryClient: NonNullable<ReturnType<typeof queryClientOrNull>>,\n id: string\n): Product | undefined {\n const scope = getActiveScope();\n let found: Product | undefined;\n for (const prefix of LIST_QUERY_PREFIXES) {\n for (const [queryKey, data] of queryClient.getQueriesData<ProductsListResult>({\n queryKey: prefix,\n })) {\n if (!isSameScope(scopeFromQueryKey(queryKey), scope)) continue;\n for (const item of data?.items ?? []) {\n if (item?.id == null) continue;\n rememberProductPreview(item);\n if (!found && String(item.id) === id) found = item;\n }\n }\n }\n return found;\n}\n\n/**\n * List-card product for `placeholderData`. Prefers the preview key; if that was\n * dropped on SSR dehydrate, rebuilds it from the current-scope list/wishlist.\n */\nexport function getProductPreview(id: string): Product | undefined {\n const queryClient = queryClientOrNull();\n if (!queryClient) return undefined;\n const key = String(id);\n return (\n queryClient.getQueryData(productPreviewQueryKey(key)) ??\n findProductInScopedLists(queryClient, key)\n );\n}\n\nfunction rememberProductPreviews(items: Product[]): void {\n for (const item of items) rememberProductPreview(item);\n}\n\n/**\n * Search sends its words as `keyword` (a `sourceValue` string is still read there, as before);\n * every other source sends its ids as `source_value[]`, which the API requires as an array.\n */\nfunction appendSourceParams(\n searchParams: URLSearchParams,\n { source, sourceValue, keyword }: Pick<ProductsListParams, 'source' | 'sourceValue' | 'keyword'>\n): void {\n if (source === 'search') {\n const words = keyword ?? sourceValue;\n if (words !== undefined) searchParams.set('keyword', String(words));\n } else if (Array.isArray(sourceValue)) {\n sourceValue.forEach((val) => searchParams.append('source_value[]', String(val)));\n } else if (sourceValue !== undefined) {\n searchParams.append('source_value[]', String(sourceValue));\n }\n}\n\n/**\n * Sends an applied filter selection the way the SDK's `<salla-products-list>` does:\n * `filters[key]=v`, `filters[key][]=v` or `filters[key][sub]=v`.\n */\nfunction appendFilterParams(\n searchParams: URLSearchParams,\n filters?: Record<string, ProductListFilterValue>,\n parentKey = 'filters'\n): void {\n if (!filters) return;\n for (const [key, value] of Object.entries(filters)) {\n const fullKey = `${parentKey}[${key}]`;\n if (Array.isArray(value)) {\n value.forEach((item) => searchParams.append(`${fullKey}[]`, String(item)));\n } else if (value !== null && typeof value === 'object') {\n appendFilterParams(searchParams, value, fullKey);\n } else if (value !== undefined && value !== null) {\n searchParams.append(fullKey, String(value));\n }\n }\n}\n\n/** A `category_id` filter replaces the page's category as the list source (as in the SDK). */\nfunction categoryFilterIds(filters?: ProductListFilters): number[] | null {\n const raw = filters?.category_id;\n if (raw === undefined || raw === null) return null;\n const ids = Array.isArray(raw) ? raw : typeof raw === 'object' ? Object.values(raw) : [raw];\n return ids.map(Number);\n}\n\n// ===== Pagination =====\n\n/**\n * The API's own `cursor.next` (the previous page's response) is usually a\n * bare opaque cursor token, but for sources that don't support true\n * cursor-based pagination (observed: `source=offers`) it's instead a full\n * next-page URL carrying its own `page=N` — and no `cursor=` param at all.\n *\n * Passing that whole URL straight through as `list()`'s own `cursor` used to\n * smuggle its embedded `source` / `per_page` / `sort` into the request on\n * top of the ones `list()` already sets unconditionally, producing a\n * doubled query string (`source=offers&source=offers&...`) the API can't\n * paginate from correctly — every subsequent scroll re-fetched the exact\n * same first page instead of advancing. Pulling just the `page` number back\n * out here, the same way an actual `cursor=` is already pulled out, keeps\n * `list()`'s request to the one copy of each param it's supposed to have.\n */\nexport function parseNextPageToken(nextUrl: string | null | undefined): {\n cursor?: string;\n page?: number;\n} {\n if (!nextUrl) return {};\n\n const cursorMatch = nextUrl.match(/[?&]cursor=([^&]+)/);\n if (cursorMatch) return { cursor: decodeURIComponent(cursorMatch[1]) };\n\n const pageMatch = nextUrl.match(/[?&]page=([^&]+)/);\n if (pageMatch) {\n const page = Number(decodeURIComponent(pageMatch[1]));\n if (Number.isFinite(page)) return { page };\n }\n\n // Neither pattern matched: not a URL at all, just the bare opaque token itself.\n return { cursor: nextUrl };\n}\n\n// ===== API Functions =====\n\nexport const product = {\n find: async (id: string): Promise<Product> => {\n const endpoint = `products/${id}/details?with[]=images&with[]=category&with[]=rating&with[]=notify_availability&with[]=tags&with[]=brand&with[]=options&with[]=skus&with[]=skus_availability&with[]=included_products&with[]=bundle&with[]=sold_quantity`;\n const { data } = await api.get(endpoint).json<{ data: Product }>();\n return data;\n },\n\n findOrThrow: (id: string): Promise<Product> => orThrow(product.find(id)),\n\n /** A tag's name. The list endpoint returns every product for an unknown tag; this one answers 410. */\n tag: async (id: string): Promise<{ id: number; name: string }> => {\n const { tag } = await api\n .get(`products/tags/${id}`)\n .json<{ tag: { id: number; name: string } }>();\n return tag;\n },\n\n /**\n * Fetch products list with pagination support\n * Used by native ProductsList component for SSR loaders\n *\n * API pattern: GET /products?source=wishlist&page=1\n */\n list: async (params: ProductsListParams): Promise<ProductsListResult> => {\n const {\n source,\n sourceValue,\n keyword,\n page,\n cursor,\n perPage = 16,\n sort,\n filterable,\n filters,\n signal,\n } = params;\n\n // Build URL with query parameters\n const searchParams = new URLSearchParams();\n searchParams.set('source', source);\n // Only send page when explicitly provided — cursor-based callers omit it entirely\n if (page !== undefined) searchParams.set('page', String(page));\n searchParams.set('per_page', String(perPage));\n\n appendSourceParams(searchParams, {\n source,\n sourceValue: (source === 'categories' && categoryFilterIds(filters)) || sourceValue,\n keyword,\n });\n appendFilterParams(searchParams, filters);\n\n // Add filterable parameter\n if (filterable !== undefined) {\n searchParams.set('filterable', filterable ? '1' : '0');\n }\n\n // Add sort parameter\n if (sort) {\n searchParams.set('sort', sort);\n }\n\n // Add cursor for cursor-based pagination\n if (cursor) {\n searchParams.set('cursor', cursor);\n }\n\n // Make the request\n const options: Record<string, unknown> = {};\n if (signal) options.signal = signal;\n\n const response = await api\n .get(`products?${searchParams.toString()}`, options as any)\n .json<ProductsListResponse>();\n\n const items = response.data ?? [];\n rememberProductPreviews(items);\n\n return {\n items,\n next: response.cursor?.next ?? null,\n filters: response.filters,\n };\n },\n\n queries: {\n detail: (id: string) =>\n queryOptions({\n // Stock and availability are resolved per branch allocation — same as the list.\n queryKey: productDetailQueryKey(id),\n queryFn: () => product.find(id),\n // List-card product, if one was remembered. Not written as the detail\n // cache entry — `queryFn` still hits products/{id}/details.\n placeholderData: () => getProductPreview(id),\n }),\n tag: (id: string) =>\n queryOptions({\n queryKey: ['products', 'tag', id],\n queryFn: () => product.tag(id),\n }),\n list: (params: Omit<ProductsListParams, 'signal'>) =>\n queryOptions({\n // Scope (branch) varies product availability — key must include it.\n queryKey: ['products', 'list', params, { scope: getActiveScope() }],\n queryFn: ({ signal }) => product.list({ ...params, signal }),\n }),\n },\n};\n"]}
@@ -1,4 +1,4 @@
1
- import { api } from './chunk-YDSWLCOY.js';
1
+ import { api } from './chunk-BFA2U7P3.js';
2
2
  import { queryOptions } from '@tanstack/react-query';
3
3
 
4
4
  var apps = {
@@ -40,5 +40,5 @@ var apps = {
40
40
  };
41
41
 
42
42
  export { apps };
43
- //# sourceMappingURL=chunk-UZGP2KFA.js.map
44
- //# sourceMappingURL=chunk-UZGP2KFA.js.map
43
+ //# sourceMappingURL=chunk-6Z6BGS7P.js.map
44
+ //# sourceMappingURL=chunk-6Z6BGS7P.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/apps.ts"],"names":[],"mappings":";;;AAmCO,IAAM,IAAA,GAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKlB,UAAU,YAAmC;AAC3C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,eAAA,EAAiB,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CACtC,IAAA,EAA8B;AACjC,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,YAAkC;AAC1C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,wBAAA,EAA0B,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CAC/C,IAAA,EAAsC;AACzC,IAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,IAAQ,EAAC,EAAE;AAAA,EAClC,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,QAAA,EAAU,MACR,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,UAAU,CAAA;AAAA,MAC7B,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,EAAS;AAAA;AAAA,MAE7B,SAAA,EAAW,QAAA;AAAA;AAAA;AAAA;AAAA,MAIX,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,IAEH,QAAA,EAAU,MACR,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,UAAU,CAAA;AAAA,MAC7B,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,EAAS;AAAA;AAAA,MAE7B,SAAA,EAAW,QAAA;AAAA,MACX,KAAA,EAAO;AAAA,KACR;AAAA;AAEP","file":"chunk-UZGP2KFA.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\n\nexport interface AppSnippetRow {\n place: string;\n content: string;\n url?: string | null;\n /**\n * Raw snippet id, emitted as `data-snippet-id`. Present only on CDN rows — the\n * inline branch of the backend's snippet parser omits the key entirely.\n */\n id?: number;\n /** `{{customer.x}}` placeholders in `content` to substitute from SDK config `user.*` keys. */\n customer_parameters?: string[];\n}\n\nexport interface AppSnippet {\n service: string;\n app_id: string;\n /** Encoded app id (`getRouteKey()`): the scope id its snippets bind to via `data-scope-id`,\n * and its settings-bucket key. Absent on payloads predating the settings API. */\n id?: string;\n app_slug: string;\n status: string;\n snippets: AppSnippetRow[];\n}\n\n/**\n * Per-app public `app.*` buckets for CDN snippets, keyed by encoded app id (== `AppSnippet.id`,\n * the `Salla.appScope` scope id). One isolated bucket per app; reads within a scope are bare `app.*`.\n */\nexport interface AppSettings {\n apps: Record<string, Record<string, unknown>>;\n}\n\nexport const apps = {\n /**\n * Installed apps' snippets (scripts/HTML to inject). Timeout-bounded because it's awaited in\n * rootBeforeLoad (SSR/TTFB): a slow response degrades to no CDN tags, never stalls the page.\n */\n snippets: async (): Promise<AppSnippet[]> => {\n const { data } = await api\n .get('apps/snippets', { timeout: 2500 })\n .json<{ data?: AppSnippet[] }>();\n return data ?? [];\n },\n\n /**\n * Per-app public `app.*` buckets, keyed by encoded app id. Timeout-bounded (SSR-awaited):\n * a slow response degrades to empty buckets (fail-open), never strands injection.\n */\n settings: async (): Promise<AppSettings> => {\n const { data } = await api\n .get('apps/snippets/settings', { timeout: 2500 })\n .json<{ data?: Partial<AppSettings> }>();\n return { apps: data?.apps ?? {} };\n },\n\n queries: {\n snippets: () =>\n queryOptions({\n queryKey: ['apps', 'snippets'],\n queryFn: () => apps.snippets(),\n // Snippets are static per session; one fetch per page load is enough.\n staleTime: Infinity,\n // No retry: this is awaited in rootBeforeLoad, so the router's default `retry: 1` would\n // make the SSR wait 2 x the 2500ms timeout (plus backoff) before failing open. The\n // 2500ms timeout must be the whole budget; the client fallback query does the retrying.\n retry: 0,\n }),\n\n settings: () =>\n queryOptions({\n queryKey: ['apps', 'settings'],\n queryFn: () => apps.settings(),\n // Encoded app ids and their buckets are stable per page; one fetch is enough.\n staleTime: Infinity,\n retry: 0,\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/apps.ts"],"names":[],"mappings":";;;AAmCO,IAAM,IAAA,GAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKlB,UAAU,YAAmC;AAC3C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,eAAA,EAAiB,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CACtC,IAAA,EAA8B;AACjC,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,YAAkC;AAC1C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,wBAAA,EAA0B,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CAC/C,IAAA,EAAsC;AACzC,IAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,IAAQ,EAAC,EAAE;AAAA,EAClC,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,QAAA,EAAU,MACR,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,UAAU,CAAA;AAAA,MAC7B,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,EAAS;AAAA;AAAA,MAE7B,SAAA,EAAW,QAAA;AAAA;AAAA;AAAA;AAAA,MAIX,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,IAEH,QAAA,EAAU,MACR,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,UAAU,CAAA;AAAA,MAC7B,OAAA,EAAS,MAAM,IAAA,CAAK,QAAA,EAAS;AAAA;AAAA,MAE7B,SAAA,EAAW,QAAA;AAAA,MACX,KAAA,EAAO;AAAA,KACR;AAAA;AAEP","file":"chunk-6Z6BGS7P.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\n\nexport interface AppSnippetRow {\n place: string;\n content: string;\n url?: string | null;\n /**\n * Raw snippet id, emitted as `data-snippet-id`. Present only on CDN rows — the\n * inline branch of the backend's snippet parser omits the key entirely.\n */\n id?: number;\n /** `{{customer.x}}` placeholders in `content` to substitute from SDK config `user.*` keys. */\n customer_parameters?: string[];\n}\n\nexport interface AppSnippet {\n service: string;\n app_id: string;\n /** Encoded app id (`getRouteKey()`): the scope id its snippets bind to via `data-scope-id`,\n * and its settings-bucket key. Absent on payloads predating the settings API. */\n id?: string;\n app_slug: string;\n status: string;\n snippets: AppSnippetRow[];\n}\n\n/**\n * Per-app public `app.*` buckets for CDN snippets, keyed by encoded app id (== `AppSnippet.id`,\n * the `Salla.appScope` scope id). One isolated bucket per app; reads within a scope are bare `app.*`.\n */\nexport interface AppSettings {\n apps: Record<string, Record<string, unknown>>;\n}\n\nexport const apps = {\n /**\n * Installed apps' snippets (scripts/HTML to inject). Timeout-bounded because it's awaited in\n * rootBeforeLoad (SSR/TTFB): a slow response degrades to no CDN tags, never stalls the page.\n */\n snippets: async (): Promise<AppSnippet[]> => {\n const { data } = await api\n .get('apps/snippets', { timeout: 2500 })\n .json<{ data?: AppSnippet[] }>();\n return data ?? [];\n },\n\n /**\n * Per-app public `app.*` buckets, keyed by encoded app id. Timeout-bounded (SSR-awaited):\n * a slow response degrades to empty buckets (fail-open), never strands injection.\n */\n settings: async (): Promise<AppSettings> => {\n const { data } = await api\n .get('apps/snippets/settings', { timeout: 2500 })\n .json<{ data?: Partial<AppSettings> }>();\n return { apps: data?.apps ?? {} };\n },\n\n queries: {\n snippets: () =>\n queryOptions({\n queryKey: ['apps', 'snippets'],\n queryFn: () => apps.snippets(),\n // Snippets are static per session; one fetch per page load is enough.\n staleTime: Infinity,\n // No retry: this is awaited in rootBeforeLoad, so the router's default `retry: 1` would\n // make the SSR wait 2 x the 2500ms timeout (plus backoff) before failing open. The\n // 2500ms timeout must be the whole budget; the client fallback query does the retrying.\n retry: 0,\n }),\n\n settings: () =>\n queryOptions({\n queryKey: ['apps', 'settings'],\n queryFn: () => apps.settings(),\n // Encoded app ids and their buckets are stable per page; one fetch is enough.\n staleTime: Infinity,\n retry: 0,\n }),\n },\n};\n"]}
@@ -1,23 +1,23 @@
1
- import { Header } from './chunk-ZLLHL3NI.js';
2
- import { Footer } from './chunk-PTQVBPPN.js';
3
- import { resolveTwilightSdkUrl, TICKETING_SCRIPT_URL } from './chunk-W354TTIE.js';
4
- import { useDevSettingsOverrides } from './chunk-BR56OEPZ.js';
5
- import { apps } from './chunk-UZGP2KFA.js';
1
+ import { Header } from './chunk-G3VAJVY5.js';
2
+ import { Footer } from './chunk-VIR6L7KJ.js';
3
+ import { resolveTwilightSdkUrl, TICKETING_SCRIPT_URL } from './chunk-MVBMVM22.js';
4
+ import { useDevSettingsOverrides } from './chunk-FMSRB2TT.js';
5
+ import { apps } from './chunk-6Z6BGS7P.js';
6
6
  import { color } from './chunk-VVZNW5CB.js';
7
- import { applyThemeHookSlots, installAppScope } from './chunk-U6KJ7XBO.js';
8
- import { useLocation, useIsHome, NavigationInterceptor } from './chunk-UWDUMPL7.js';
9
- import { useUser } from './chunk-RBFLDI2Z.js';
7
+ import { applyThemeHookSlots, installAppScope } from './chunk-I7WSIN27.js';
8
+ import { useLocation, useIsHome, NavigationInterceptor } from './chunk-E5PEYI5I.js';
9
+ import { useUser } from './chunk-MJ7TL42D.js';
10
10
  import { DocumentClassProvider, useDocumentClass } from './chunk-JWXJPJBO.js';
11
11
  import { WidgetHead } from './chunk-V2ZDTY6H.js';
12
12
  import { HookSlot } from './chunk-5XDPAKF5.js';
13
13
  import { hookRegistry } from './chunk-GCPEMNSU.js';
14
- import { getActiveCurrency } from './chunk-YDSWLCOY.js';
14
+ import { getActiveCurrency } from './chunk-BFA2U7P3.js';
15
15
  import { useTranslation, I18nProvider } from './chunk-TYNZ5B2B.js';
16
- import { Toaster } from './chunk-OSSOU36J.js';
17
- import { isNativeApp } from './chunk-A4NN6C5B.js';
18
- import { whenSallaLoaded, whenSallaReady, onSallaEvent, getSallaSDK, syncSdkLocale } from './chunk-3NFVZJNI.js';
19
- import { AUTH_TOKEN_COOKIE_NAME, rememberDevStoreId, clearAuthTokenCookie, syncScopeCookie, escapeForInlineScript } from './chunk-GXZW6BJY.js';
20
- import { getTwilightContext, subscribeTwilight, updateTwilightContext, hasTwilightSettings } from './chunk-JNAJTCJD.js';
16
+ import { Toaster } from './chunk-WD576F4S.js';
17
+ import { isNativeApp } from './chunk-YYMKDBZV.js';
18
+ import { whenSallaLoaded, whenSallaReady, onSallaEvent, getSallaSDK, syncSdkLocale } from './chunk-X2JCU7GY.js';
19
+ import { AUTH_TOKEN_COOKIE_NAME, rememberDevStoreId, clearAuthTokenCookie, syncScopeCookie, escapeForInlineScript } from './chunk-POI4G5EA.js';
20
+ import { getTwilightContext, subscribeTwilight, updateTwilightContext, hasTwilightSettings } from './chunk-QRHXAKJ3.js';
21
21
  import { FALLBACK_LOCALE, getLanguageInfo } from './chunk-T72DAX7R.js';
22
22
  import { useTwilight, TwilightContext } from './chunk-DF6FBKDN.js';
23
23
  import React2, { lazy, Suspense, useEffect, useCallback, useMemo, useRef, useState, useSyncExternalStore, createElement } from 'react';
@@ -125,7 +125,7 @@ function ThemeDocumentSync({
125
125
  }
126
126
 
127
127
  // src/utils/engine-version.ts
128
- var ENGINE_VERSION = "1.0.108" ;
128
+ var ENGINE_VERSION = "1.0.110" ;
129
129
 
130
130
  // src/providers/twilight-init.ts
131
131
  function getSalla() {
@@ -336,13 +336,13 @@ function useNativeSpaWebview() {
336
336
  }
337
337
  var navigationSetups = {
338
338
  tanstack: lazy(
339
- () => import('./navigation-WASYQTFC.js').then((m) => ({ default: m.NavigationSetup }))
339
+ () => import('./navigation-S5EUYOVI.js').then((m) => ({ default: m.NavigationSetup }))
340
340
  ),
341
- nextjs: lazy(() => import('./navigation-LSRNHKGJ.js').then((m) => ({ default: m.NavigationSetup })))
341
+ nextjs: lazy(() => import('./navigation-NM4AO2OX.js').then((m) => ({ default: m.NavigationSetup })))
342
342
  };
343
343
  var routeDocumentSyncs = {
344
344
  tanstack: lazy(
345
- () => import('./document-class-B2MXKYAQ.js').then((m) => ({
345
+ () => import('./document-class-5BRFPS6J.js').then((m) => ({
346
346
  default: m.TanStackDocumentSync
347
347
  }))
348
348
  )
@@ -864,7 +864,7 @@ var LazySiftSnippet = lazy(
864
864
  () => import('./SiftSnippet-5FCU6TR6.js').then((m) => ({ default: m.SiftSnippet }))
865
865
  );
866
866
  var LazyStoreClosedNotification = lazy(
867
- () => import('./StoreClosedNotification-YMPBP56U.js').then((m) => ({
867
+ () => import('./StoreClosedNotification-Q4QPPYEH.js').then((m) => ({
868
868
  default: m.StoreClosedNotification
869
869
  }))
870
870
  );
@@ -1108,12 +1108,12 @@ function SallaSdkScripts({ settings }) {
1108
1108
  ] });
1109
1109
  }
1110
1110
  var LazyStoreClosedNotification2 = lazy(
1111
- () => import('./StoreClosedNotification-YMPBP56U.js').then((m) => ({
1111
+ () => import('./StoreClosedNotification-Q4QPPYEH.js').then((m) => ({
1112
1112
  default: m.StoreClosedNotification
1113
1113
  }))
1114
1114
  );
1115
1115
  var LazyMaintenancePage = lazy(
1116
- () => import('./MaintenancePage-Z34IQCUV.js').then((m) => ({ default: m.MaintenancePage }))
1116
+ () => import('./MaintenancePage-UBJ5Q3L5.js').then((m) => ({ default: m.MaintenancePage }))
1117
1117
  );
1118
1118
  var BAR = {
1119
1119
  position: "fixed",
@@ -1432,5 +1432,5 @@ function useStore() {
1432
1432
  }
1433
1433
 
1434
1434
  export { LazyMaintenancePage, LazyStoreClosedNotification2 as LazyStoreClosedNotification, MasterLayout, TwilightProvider, fastCheckoutScript, registerDefaultHooks, registerDocumentSync, routeDocumentSyncs, useBreadcrumbs, useDate, useGtm, useMoney, useNumber, useOpeningHours, usePageConfig, useStore };
1435
- //# sourceMappingURL=chunk-6UG4IVUF.js.map
1436
- //# sourceMappingURL=chunk-6UG4IVUF.js.map
1435
+ //# sourceMappingURL=chunk-72DGJN4Q.js.map
1436
+ //# sourceMappingURL=chunk-72DGJN4Q.js.map