@salla.sa/twilight-theme-engine 1.0.107 → 1.0.109

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 (264) hide show
  1. package/dist/{AddToCartForm-ROYGCSVX.js → AddToCartForm-ZIZKGYJR.js} +3 -3
  2. package/dist/{AddToCartForm-ROYGCSVX.js.map → AddToCartForm-ZIZKGYJR.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-V4QPVVWU.js → BlogAuthorPage-GLAYDKIX.js} +27 -27
  4. package/dist/{BlogAuthorPage-V4QPVVWU.js.map → BlogAuthorPage-GLAYDKIX.js.map} +1 -1
  5. package/dist/{BlogCategoryPage-BSM63G5Q.js → BlogCategoryPage-KPU6LYHK.js} +27 -27
  6. package/dist/{BlogCategoryPage-BSM63G5Q.js.map → BlogCategoryPage-KPU6LYHK.js.map} +1 -1
  7. package/dist/{BlogPage-4QXLITAA.js → BlogPage-VDDHOD33.js} +25 -25
  8. package/dist/{BlogPage-4QXLITAA.js.map → BlogPage-VDDHOD33.js.map} +1 -1
  9. package/dist/{BlogSinglePage-TRYJUPCB.js → BlogSinglePage-UWP5MFAS.js} +25 -25
  10. package/dist/{BlogSinglePage-TRYJUPCB.js.map → BlogSinglePage-UWP5MFAS.js.map} +1 -1
  11. package/dist/{BlogTagPage-2JKCTBIU.js → BlogTagPage-V3Z4AD4C.js} +27 -27
  12. package/dist/{BlogTagPage-2JKCTBIU.js.map → BlogTagPage-V3Z4AD4C.js.map} +1 -1
  13. package/dist/{BrandsPage-PGCDHGOI.js → BrandsPage-ARYKHCTB.js} +26 -26
  14. package/dist/{BrandsPage-PGCDHGOI.js.map → BrandsPage-ARYKHCTB.js.map} +1 -1
  15. package/dist/{Breadcrumb-ACO63JUO.js → Breadcrumb-XT2MP2ZW.js} +25 -25
  16. package/dist/{Breadcrumb-ACO63JUO.js.map → Breadcrumb-XT2MP2ZW.js.map} +1 -1
  17. package/dist/{CartItem-TYWGDMRV.js → CartItem-4VXVOKVF.js} +25 -25
  18. package/dist/{CartItem-TYWGDMRV.js.map → CartItem-4VXVOKVF.js.map} +1 -1
  19. package/dist/{CartSummary-AKDPJ4OY.js → CartSummary-K23PGOUL.js} +25 -25
  20. package/dist/{CartSummary-AKDPJ4OY.js.map → CartSummary-K23PGOUL.js.map} +1 -1
  21. package/dist/{Copyright-TOKRGLFM.js → Copyright-KBCQVD5Y.js} +3 -3
  22. package/dist/{Copyright-TOKRGLFM.js.map → Copyright-KBCQVD5Y.js.map} +1 -1
  23. package/dist/{CustomerLayout-WTD5QAR7.js → CustomerLayout-B77ZKB4X.js} +25 -25
  24. package/dist/{CustomerLayout-WTD5QAR7.js.map → CustomerLayout-B77ZKB4X.js.map} +1 -1
  25. package/dist/{Footer-SSNPHJ2G.js → Footer-L52M4T24.js} +4 -4
  26. package/dist/{Footer-SSNPHJ2G.js.map → Footer-L52M4T24.js.map} +1 -1
  27. package/dist/Header-QOAV23HD.js +22 -0
  28. package/dist/{Header-W6XMMZIA.js.map → Header-QOAV23HD.js.map} +1 -1
  29. package/dist/{LoyaltyPage-QJIAYRU4.js → LoyaltyPage-3OIZG2ZJ.js} +25 -25
  30. package/dist/{LoyaltyPage-QJIAYRU4.js.map → LoyaltyPage-3OIZG2ZJ.js.map} +1 -1
  31. package/dist/{LoyaltyPointsPage-A4QHYJXF.js → LoyaltyPointsPage-I3O3JA7Q.js} +9 -9
  32. package/dist/{LoyaltyPointsPage-A4QHYJXF.js.map → LoyaltyPointsPage-I3O3JA7Q.js.map} +1 -1
  33. package/dist/{MainMenu-HBN4SWXP.js → MainMenu-VIDYUQNX.js} +8 -8
  34. package/dist/{MainMenu-HBN4SWXP.js.map → MainMenu-VIDYUQNX.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-DTLAOTWI.js → MasterLayout-FY666JMR.js} +25 -25
  38. package/dist/{MasterLayout-DTLAOTWI.js.map → MasterLayout-FY666JMR.js.map} +1 -1
  39. package/dist/{MobileMenu-ZC5D4KGJ.js → MobileMenu-3ILQKCHA.js} +26 -26
  40. package/dist/{MobileMenu-ZC5D4KGJ.js.map → MobileMenu-3ILQKCHA.js.map} +1 -1
  41. package/dist/{NotificationsPage-TKJLPSGS.js → NotificationsPage-EYTBUS36.js} +25 -25
  42. package/dist/{NotificationsPage-TKJLPSGS.js.map → NotificationsPage-EYTBUS36.js.map} +1 -1
  43. package/dist/{OrderSinglePage-GT2E2CZN.js → OrderSinglePage-YHA5D2ZI.js} +26 -26
  44. package/dist/{OrderSinglePage-GT2E2CZN.js.map → OrderSinglePage-YHA5D2ZI.js.map} +1 -1
  45. package/dist/{OrdersPage-CBXEYWBH.js → OrdersPage-4A2QINDX.js} +25 -25
  46. package/dist/{OrdersPage-CBXEYWBH.js.map → OrdersPage-4A2QINDX.js.map} +1 -1
  47. package/dist/{PageSingle-K4W6RVAT.js → PageSingle-ED24MS2Z.js} +7 -7
  48. package/dist/{PageSingle-K4W6RVAT.js.map → PageSingle-ED24MS2Z.js.map} +1 -1
  49. package/dist/{ProductDetails-X2UNOW2P.js → ProductDetails-ZA5A66JW.js} +8 -8
  50. package/dist/{ProductDetails-X2UNOW2P.js.map → ProductDetails-ZA5A66JW.js.map} +1 -1
  51. package/dist/{ProfilePage-3AHOU5XQ.js → ProfilePage-ZTYHIDGE.js} +25 -25
  52. package/dist/{ProfilePage-3AHOU5XQ.js.map → ProfilePage-ZTYHIDGE.js.map} +1 -1
  53. package/dist/{ReviewsPage-R6DODVH6.js → ReviewsPage-LTEOFKHW.js} +3 -3
  54. package/dist/{ReviewsPage-R6DODVH6.js.map → ReviewsPage-LTEOFKHW.js.map} +1 -1
  55. package/dist/{SeoCartWidget-NJK3YIPC.js → SeoCartWidget-3O35VZZO.js} +25 -25
  56. package/dist/{SeoCartWidget-NJK3YIPC.js.map → SeoCartWidget-3O35VZZO.js.map} +1 -1
  57. package/dist/{SettingsPage-6STAABBW.js → SettingsPage-3VRJ3AYE.js} +25 -25
  58. package/dist/{SettingsPage-6STAABBW.js.map → SettingsPage-3VRJ3AYE.js.map} +1 -1
  59. package/dist/StoreClosedNotification-7KACKGVH.js +54 -0
  60. package/dist/{StoreClosedNotification-LLXVKVC7.js.map → StoreClosedNotification-7KACKGVH.js.map} +1 -1
  61. package/dist/{TestimonialsPage-SUBZSLPR.js → TestimonialsPage-LYJFX32D.js} +7 -7
  62. package/dist/{TestimonialsPage-SUBZSLPR.js.map → TestimonialsPage-LYJFX32D.js.map} +1 -1
  63. package/dist/{ThankYouPage-UA7EIVQ2.js → ThankYouPage-Z2S7MJ7J.js} +25 -25
  64. package/dist/{ThankYouPage-UA7EIVQ2.js.map → ThankYouPage-Z2S7MJ7J.js.map} +1 -1
  65. package/dist/{WalletPage-WSM62ZDH.js → WalletPage-EZ4RTLGE.js} +26 -26
  66. package/dist/{WalletPage-WSM62ZDH.js.map → WalletPage-EZ4RTLGE.js.map} +1 -1
  67. package/dist/{WishlistPage-XG3S4T5U.js → WishlistPage-V7Z6GWQI.js} +27 -27
  68. package/dist/{WishlistPage-XG3S4T5U.js.map → WishlistPage-V7Z6GWQI.js.map} +1 -1
  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-2RRZZYH4.js +14 -0
  93. package/dist/{chunk-BHGZ622P.js.map → chunk-2RRZZYH4.js.map} +1 -1
  94. package/dist/{chunk-2B74CKXM.js → chunk-3MTOUUC7.js} +4 -4
  95. package/dist/{chunk-2B74CKXM.js.map → chunk-3MTOUUC7.js.map} +1 -1
  96. package/dist/{chunk-UWDUMPL7.js → chunk-3QJCZSLR.js} +6 -6
  97. package/dist/{chunk-UWDUMPL7.js.map → chunk-3QJCZSLR.js.map} +1 -1
  98. package/dist/{chunk-VUWBGAET.js → chunk-3WMGAFWX.js} +4 -4
  99. package/dist/{chunk-VUWBGAET.js.map → chunk-3WMGAFWX.js.map} +1 -1
  100. package/dist/{chunk-BEMWHR4T.js → chunk-4CCCNO2Q.js} +3 -3
  101. package/dist/{chunk-BEMWHR4T.js.map → chunk-4CCCNO2Q.js.map} +1 -1
  102. package/dist/{chunk-HNSR4KLL.js → chunk-6V4SM23M.js} +3 -3
  103. package/dist/{chunk-HNSR4KLL.js.map → chunk-6V4SM23M.js.map} +1 -1
  104. package/dist/{chunk-UKLYL5LM.js → chunk-7JAOXOEW.js} +4 -4
  105. package/dist/{chunk-UKLYL5LM.js.map → chunk-7JAOXOEW.js.map} +1 -1
  106. package/dist/{chunk-ENC6POPF.js → chunk-B272JNRU.js} +4 -4
  107. package/dist/{chunk-ENC6POPF.js.map → chunk-B272JNRU.js.map} +1 -1
  108. package/dist/{chunk-KSS7OA3Q.js → chunk-C7CJZ5DK.js} +3 -3
  109. package/dist/{chunk-KSS7OA3Q.js.map → chunk-C7CJZ5DK.js.map} +1 -1
  110. package/dist/{chunk-NZBBYJID.js → chunk-CQ6J4FKU.js} +4 -4
  111. package/dist/{chunk-NZBBYJID.js.map → chunk-CQ6J4FKU.js.map} +1 -1
  112. package/dist/{chunk-U6KJ7XBO.js → chunk-GGATZRAY.js} +3 -3
  113. package/dist/{chunk-U6KJ7XBO.js.map → chunk-GGATZRAY.js.map} +1 -1
  114. package/dist/{chunk-UZGP2KFA.js → chunk-GIAXPCHD.js} +3 -3
  115. package/dist/{chunk-UZGP2KFA.js.map → chunk-GIAXPCHD.js.map} +1 -1
  116. package/dist/{chunk-QA4FBMFJ.js → chunk-HGA5D4LJ.js} +4 -4
  117. package/dist/{chunk-QA4FBMFJ.js.map → chunk-HGA5D4LJ.js.map} +1 -1
  118. package/dist/{chunk-BR56OEPZ.js → chunk-HSKRX3WR.js} +4 -4
  119. package/dist/{chunk-BR56OEPZ.js.map → chunk-HSKRX3WR.js.map} +1 -1
  120. package/dist/{chunk-F6XPGONG.js → chunk-HSXQUHZO.js} +5 -5
  121. package/dist/{chunk-F6XPGONG.js.map → chunk-HSXQUHZO.js.map} +1 -1
  122. package/dist/{chunk-KLYTTMXN.js → chunk-I2ZO57UV.js} +6 -6
  123. package/dist/{chunk-KLYTTMXN.js.map → chunk-I2ZO57UV.js.map} +1 -1
  124. package/dist/{chunk-6YI5J5ZN.js → chunk-IRLKZ3LB.js} +23 -23
  125. package/dist/{chunk-6YI5J5ZN.js.map → chunk-IRLKZ3LB.js.map} +1 -1
  126. package/dist/{chunk-OSSOU36J.js → chunk-IXFBHQ5P.js} +3 -3
  127. package/dist/{chunk-OSSOU36J.js.map → chunk-IXFBHQ5P.js.map} +1 -1
  128. package/dist/{chunk-SZ65XCSZ.js → chunk-KPQEPQ4L.js} +7 -7
  129. package/dist/{chunk-SZ65XCSZ.js.map → chunk-KPQEPQ4L.js.map} +1 -1
  130. package/dist/{chunk-3NFVZJNI.js → chunk-L6TSHT52.js} +3 -3
  131. package/dist/{chunk-3NFVZJNI.js.map → chunk-L6TSHT52.js.map} +1 -1
  132. package/dist/{chunk-T5VU67NQ.js → chunk-LG2UQKSH.js} +4 -4
  133. package/dist/{chunk-T5VU67NQ.js.map → chunk-LG2UQKSH.js.map} +1 -1
  134. package/dist/{chunk-EHX45KZG.js → chunk-LZZ6EESI.js} +3 -3
  135. package/dist/{chunk-EHX45KZG.js.map → chunk-LZZ6EESI.js.map} +1 -1
  136. package/dist/{chunk-2CL6AEO4.js → chunk-N5WT7UM3.js} +3 -3
  137. package/dist/{chunk-2CL6AEO4.js.map → chunk-N5WT7UM3.js.map} +1 -1
  138. package/dist/{chunk-OHUTM224.js → chunk-N6B4LPKS.js} +4 -4
  139. package/dist/{chunk-OHUTM224.js.map → chunk-N6B4LPKS.js.map} +1 -1
  140. package/dist/{chunk-RA6ZTHN6.js → chunk-N6JUOBYJ.js} +4 -4
  141. package/dist/{chunk-RA6ZTHN6.js.map → chunk-N6JUOBYJ.js.map} +1 -1
  142. package/dist/{chunk-QBIPTWOR.js → chunk-NEKHAKA7.js} +21 -17
  143. package/dist/chunk-NEKHAKA7.js.map +1 -0
  144. package/dist/{chunk-4PT5MXGR.js → chunk-NEPWW7KM.js} +4 -4
  145. package/dist/{chunk-4PT5MXGR.js.map → chunk-NEPWW7KM.js.map} +1 -1
  146. package/dist/{chunk-VCSFCUFT.js → chunk-P36CIH6E.js} +7 -7
  147. package/dist/{chunk-VCSFCUFT.js.map → chunk-P36CIH6E.js.map} +1 -1
  148. package/dist/{chunk-D7XWUD6T.js → chunk-PFMTPKZO.js} +4 -4
  149. package/dist/{chunk-D7XWUD6T.js.map → chunk-PFMTPKZO.js.map} +1 -1
  150. package/dist/{chunk-L4JI2AAL.js → chunk-QEPZPPLH.js} +4 -4
  151. package/dist/{chunk-L4JI2AAL.js.map → chunk-QEPZPPLH.js.map} +1 -1
  152. package/dist/{chunk-JNAJTCJD.js → chunk-QRHXAKJ3.js} +5 -3
  153. package/dist/chunk-QRHXAKJ3.js.map +1 -0
  154. package/dist/{chunk-L26XGP65.js → chunk-QZM4ZACO.js} +3 -3
  155. package/dist/{chunk-L26XGP65.js.map → chunk-QZM4ZACO.js.map} +1 -1
  156. package/dist/{chunk-Y464WYUT.js → chunk-RJ5HY6PN.js} +5 -5
  157. package/dist/{chunk-Y464WYUT.js.map → chunk-RJ5HY6PN.js.map} +1 -1
  158. package/dist/{chunk-ZI5XWXWG.js → chunk-SCL6EXHP.js} +3 -3
  159. package/dist/{chunk-ZI5XWXWG.js.map → chunk-SCL6EXHP.js.map} +1 -1
  160. package/dist/{chunk-SQXUWX4B.js → chunk-SGZ6TCHB.js} +5 -5
  161. package/dist/{chunk-SQXUWX4B.js.map → chunk-SGZ6TCHB.js.map} +1 -1
  162. package/dist/{chunk-W354TTIE.js → chunk-TOVC6CV7.js} +6 -6
  163. package/dist/{chunk-W354TTIE.js.map → chunk-TOVC6CV7.js.map} +1 -1
  164. package/dist/{chunk-YDSWLCOY.js → chunk-TTTI4W5F.js} +5 -5
  165. package/dist/{chunk-YDSWLCOY.js.map → chunk-TTTI4W5F.js.map} +1 -1
  166. package/dist/{chunk-TO6CJI2H.js → chunk-TUVDPELG.js} +8 -8
  167. package/dist/{chunk-TO6CJI2H.js.map → chunk-TUVDPELG.js.map} +1 -1
  168. package/dist/{chunk-TWUOIBO7.js → chunk-U46RGTYO.js} +3 -3
  169. package/dist/{chunk-TWUOIBO7.js.map → chunk-U46RGTYO.js.map} +1 -1
  170. package/dist/{chunk-2IW3JRWL.js → chunk-UCJNWQF2.js} +4 -4
  171. package/dist/{chunk-2IW3JRWL.js.map → chunk-UCJNWQF2.js.map} +1 -1
  172. package/dist/{chunk-LUFLN7WL.js → chunk-UEOXX7N2.js} +7 -7
  173. package/dist/{chunk-LUFLN7WL.js.map → chunk-UEOXX7N2.js.map} +1 -1
  174. package/dist/{chunk-YCHSWHTJ.js → chunk-UO4HPAP5.js} +8 -8
  175. package/dist/{chunk-YCHSWHTJ.js.map → chunk-UO4HPAP5.js.map} +1 -1
  176. package/dist/{chunk-SCRNQWZT.js → chunk-VDBDYFAL.js} +4 -4
  177. package/dist/{chunk-SCRNQWZT.js.map → chunk-VDBDYFAL.js.map} +1 -1
  178. package/dist/chunk-VM5Y62RM.js +182 -0
  179. package/dist/chunk-VM5Y62RM.js.map +1 -0
  180. package/dist/{chunk-ZVYJK6XQ.js → chunk-WAYZZVNX.js} +5 -5
  181. package/dist/{chunk-ZVYJK6XQ.js.map → chunk-WAYZZVNX.js.map} +1 -1
  182. package/dist/{chunk-BQ2MNEN7.js → chunk-WEN6FKY6.js} +3 -3
  183. package/dist/{chunk-BQ2MNEN7.js.map → chunk-WEN6FKY6.js.map} +1 -1
  184. package/dist/{chunk-24UCMWQB.js → chunk-WX2UWLMW.js} +3 -3
  185. package/dist/{chunk-24UCMWQB.js.map → chunk-WX2UWLMW.js.map} +1 -1
  186. package/dist/{chunk-IQA2UPXP.js → chunk-YDKPG3AP.js} +23 -13
  187. package/dist/chunk-YDKPG3AP.js.map +1 -0
  188. package/dist/{chunk-GXZW6BJY.js → chunk-YUI6R2PA.js} +3 -3
  189. package/dist/{chunk-GXZW6BJY.js.map → chunk-YUI6R2PA.js.map} +1 -1
  190. package/dist/{chunk-A4NN6C5B.js → chunk-YZDHDHSN.js} +3 -3
  191. package/dist/{chunk-A4NN6C5B.js.map → chunk-YZDHDHSN.js.map} +1 -1
  192. package/dist/{chunk-RBFLDI2Z.js → chunk-ZM4J5A4Z.js} +4 -4
  193. package/dist/{chunk-RBFLDI2Z.js.map → chunk-ZM4J5A4Z.js.map} +1 -1
  194. package/dist/components/cart/index.js +1 -1
  195. package/dist/components/common/index.js +1 -1
  196. package/dist/components/drawer/index.js +23 -23
  197. package/dist/components/home/FeaturedProductsStyle2.d.ts.map +1 -1
  198. package/dist/components/home/FixedProducts.d.ts.map +1 -1
  199. package/dist/components/home/index.js +27 -27
  200. package/dist/components/layout/index.js +7 -7
  201. package/dist/components/product/index.js +24 -24
  202. package/dist/components/store/index.js +25 -25
  203. package/dist/components/toast/index.js +5 -5
  204. package/dist/dev/editor/index.js +3 -3
  205. package/dist/dev/index.js +3 -3
  206. package/dist/document-class-2PMYG45N.js +29 -0
  207. package/dist/{document-class-O2LUUQTZ.js.map → document-class-2PMYG45N.js.map} +1 -1
  208. package/dist/hooks/index.js +23 -23
  209. package/dist/hooks/useComments.js +4 -4
  210. package/dist/hooks/useGtm.js +23 -23
  211. package/dist/hooks/useMoney.js +23 -23
  212. package/dist/hooks/useProduct.js +4 -4
  213. package/dist/hooks/useStore.js +23 -23
  214. package/dist/hooks/useUser.js +6 -6
  215. package/dist/hooks/useWishlist.js +4 -4
  216. package/dist/index.d.ts +1 -0
  217. package/dist/index.d.ts.map +1 -1
  218. package/dist/index.js +23 -23
  219. package/dist/native-app/index.js +4 -4
  220. package/dist/{navigation-LSRNHKGJ.js → navigation-3HNNCUGK.js} +8 -8
  221. package/dist/{navigation-LSRNHKGJ.js.map → navigation-3HNNCUGK.js.map} +1 -1
  222. package/dist/navigation-GF4ODD46.js +14 -0
  223. package/dist/{navigation-WASYQTFC.js.map → navigation-GF4ODD46.js.map} +1 -1
  224. package/dist/{not-found-WFK6JU2O.js → not-found-5YCYDSHS.js} +26 -26
  225. package/dist/{not-found-WFK6JU2O.js.map → not-found-5YCYDSHS.js.map} +1 -1
  226. package/dist/providers/index.js +23 -23
  227. package/dist/routes/account/orders.js +8 -8
  228. package/dist/routes/account.js +17 -17
  229. package/dist/routes/blog.js +12 -12
  230. package/dist/routes/brands.js +8 -8
  231. package/dist/routes/cart.js +31 -31
  232. package/dist/routes/home.js +28 -28
  233. package/dist/routes/index.js +7 -7
  234. package/dist/routes/loyalty.js +9 -9
  235. package/dist/routes/page.js +8 -8
  236. package/dist/routes/product-listing.js +29 -29
  237. package/dist/routes/product.js +27 -27
  238. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  239. package/dist/routes/seo-redirects.js +7 -7
  240. package/dist/routes/testimonials.js +3 -3
  241. package/dist/routes/thank-you.js +8 -8
  242. package/dist/skeleton.js +28 -28
  243. package/dist/{store-lookup-EW6ALPQF.js → store-lookup-TK4QCWNT.js} +12 -12
  244. package/dist/{store-lookup-EW6ALPQF.js.map → store-lookup-TK4QCWNT.js.map} +1 -1
  245. package/dist/tanstack.js +20 -20
  246. package/dist/utils/errors.d.ts +18 -1
  247. package/dist/utils/errors.d.ts.map +1 -1
  248. package/dist/utils/index.js +6 -6
  249. package/dist/vite/index.js +3 -3
  250. package/package.json +1 -1
  251. package/tailwind/components/home/FeaturedProductsStyle2.tsx.txt +8 -2
  252. package/tailwind/components/home/FixedProducts.tsx.txt +9 -2
  253. package/tailwind/routes/root/beforeLoad.ts.txt +8 -2
  254. package/dist/Header-W6XMMZIA.js +0 -22
  255. package/dist/MaintenancePage-Z34IQCUV.js +0 -7
  256. package/dist/StoreClosedNotification-LLXVKVC7.js +0 -54
  257. package/dist/chunk-BHGZ622P.js +0 -14
  258. package/dist/chunk-D42M66E4.js +0 -127
  259. package/dist/chunk-D42M66E4.js.map +0 -1
  260. package/dist/chunk-IQA2UPXP.js.map +0 -1
  261. package/dist/chunk-JNAJTCJD.js.map +0 -1
  262. package/dist/chunk-QBIPTWOR.js.map +0 -1
  263. package/dist/document-class-O2LUUQTZ.js +0 -29
  264. package/dist/navigation-WASYQTFC.js +0 -14
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tanstack/search.ts","../src/utils/maintenance.ts","../src/routes/root/beforeLoad.ts","../src/tanstack/store-base.ts","../src/tanstack/router.tsx","../src/tanstack/document-class.ts"],"names":["createTanStackRouter"],"mappings":"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","file":"chunk-NEKHAKA7.js","sourcesContent":["import { defaultStringifySearch } from '@tanstack/react-router';\n\nconst isList = ([key, value]: [string, unknown]) => key.endsWith('[]') && Array.isArray(value);\n\n/** The router's query serialiser, writing `[]` keys back as repeated keys, as `<salla-filters>` does. */\nexport function stringifySearch(search: Record<string, unknown>): string {\n const entries = Object.entries(search);\n const lists = entries.filter(isList) as [string, unknown[]][];\n if (!lists.length) return defaultStringifySearch(search);\n\n const rest = defaultStringifySearch(\n Object.fromEntries(entries.filter((entry) => !isList(entry)))\n );\n const repeated = lists.flatMap(([key, values]) =>\n values.map(\n (value) =>\n `${encodeURIComponent(key)}=${encodeURIComponent(typeof value === 'string' ? value : JSON.stringify(value))}`\n )\n );\n return `${rest || '?'}${rest ? '&' : ''}${repeated.join('&')}`;\n}\n","import type { StoreContext } from '../api/store';\nimport { extractTokenFromCookies } from './cookies';\n\n/**\n * Remembers that this browser is the merchant looking at their own closed store.\n *\n * The dashboard's \"view store\" link carries `?utm_source=dashboard&identifier=<store id>`\n * (`portal` for the partners portal). Twig's backend checks that once, keeps\n * `view-as: owner` in the PHP session and lets every later request through; this\n * cookie is that session entry. No `max-age`: a session cookie, as the PHP session\n * was, so closing the browser ends the owner view.\n *\n * The value is the store id the bypass was granted for, checked against the store\n * the settings answer about, so one store's cookie opens no other store.\n */\nexport const VIEW_AS_OWNER_COOKIE_NAME = 'salla_view_as';\n\nconst OWNER_SOURCES = ['dashboard', 'portal'];\n\n/** The id as the URL and the cookie spell it, or null when the settings name none. */\nfunction storeIdOf(settings: StoreContext | null | undefined): string | null {\n const id = settings?.store?.id;\n return id == null ? null : String(id);\n}\n\n/**\n * Whether `href` is the dashboard's link into the merchant's own store:\n * `utm_source` is `dashboard` or `portal`, and `identifier` is this store's id.\n * The backend's own rule, translated.\n */\nexport function ownerLinkMatches(href: string, settings: StoreContext | null | undefined): boolean {\n const storeId = storeIdOf(settings);\n if (!storeId) return false;\n let params: URLSearchParams;\n try {\n params = new URL(href, 'http://localhost').searchParams;\n } catch {\n return false;\n }\n const source = params.get('utm_source');\n return source != null && OWNER_SOURCES.includes(source) && params.get('identifier') === storeId;\n}\n\n/** Whether the cookie remembers an owner view of this store. */\nexport function ownerCookieMatches(\n cookieHeader: string | null,\n settings: StoreContext | null | undefined\n): boolean {\n const storeId = storeIdOf(settings);\n return !!storeId && extractTokenFromCookies(cookieHeader, VIEW_AS_OWNER_COOKIE_NAME) === storeId;\n}\n\n/**\n * Whether this visitor gets the maintenance page instead of the store.\n *\n * True only when the settings say the store is closed and nothing lets the visitor\n * through: neither an owner view (the link or the cookie) nor the theme editor's\n * preview, which the backend also always lets in.\n */\nexport function showsMaintenancePage(\n settings: StoreContext | null | undefined,\n viewAsOwner: boolean\n): boolean {\n return settings?.maintenance === true && !viewAsOwner && settings.theme?.mode !== 'preview';\n}\n","import type { QueryClient } from '@tanstack/react-query';\nimport { redirect } from '@tanstack/react-router';\nimport { createIsomorphicFn } from '@tanstack/react-start';\nimport {\n getCookie,\n getRequestHeader,\n getRequestUrl,\n setCookie,\n} from '@tanstack/react-start/server';\nimport type { StoreContext } from '../../api/store';\nimport { store as storeApi } from '../../api/store';\nimport { apps, type AppSnippet, type AppSettings } from '../../api/apps';\nimport { translations } from '../../api/translations';\nimport { advertisement } from '../../api/advertisement';\nimport { FALLBACK_LOCALE, getLanguageInfo } from '../../providers/locale-constants';\nimport { createI18nInstance } from '../../providers/i18n-factory';\nimport type { TwilightLocation } from '../../twilight/context';\nimport { getTwilightContext, updateTwilightContext } from '../../twilight/context';\nimport {\n AUTH_TOKEN_COOKIE_NAME,\n extractScopeFromCookies,\n extractScopeFromUrl,\n extractTokenFromCookies,\n resolveRequestScope,\n sameScope,\n SCOPE_COOKIE_MAX_AGE,\n SCOPE_COOKIE_NAME,\n syncScopeCookie,\n type ActiveScope,\n} from '../../utils/cookies';\nimport { syncSdkLocale, syncSdkThemeVersion } from '../../utils/sdk-helpers';\nimport { SettingsError } from '../../utils/errors';\nimport { resolveStoreBaseRedirect } from '../../utils/store-identity';\nimport {\n ownerCookieMatches,\n ownerLinkMatches,\n showsMaintenancePage,\n VIEW_AS_OWNER_COOKIE_NAME,\n} from '../../utils/maintenance';\n\n// Reads the `token` cookie from the incoming request on the SERVER. twilightMiddleware\n// extracts the same cookie into a custom ALS, but that ALS does NOT propagate to the\n// route's beforeLoad / React SSR render (they run in a different async scope), so the\n// token must be read again here from the framework's own request context. On the client\n// this is a no-op (the cookie is read from document.cookie below instead). The server\n// import is stripped from the client bundle by createIsomorphicFn.\nconst readServerCookieToken = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getCookie(AUTH_TOKEN_COOKIE_NAME) ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => null);\n\n/**\n * The scope to write to the `scope` cookie for this request, or null to leave the cookie\n * as it is.\n *\n * Only for a market a `?scope=` URL switched to, and only when the settings were answered\n * for it: the API falls back to another market when it does not accept the requested one,\n * and Twig keeps the previous choice then too, rather than recording one the page is not\n * showing. Its type is the one the settings answered with: a URL names only the id, and\n * the store-wide type is assumed until the answer says otherwise (a store browsing by\n * branch or city), so later requests send the type the API matches against.\n */\nexport function scopeCookieUpdate(\n url: string,\n cookieHeader: string | null,\n settings: StoreContext\n): ActiveScope | null {\n if (!extractScopeFromUrl(url)) return null;\n const scope = resolveRequestScope(url, cookieHeader);\n const answered = settings.store?.scope;\n if (!scope || answered?.id == null || String(answered.id) !== scope.id) return null;\n const typed = answered.type ? { ...scope, type: answered.type } : scope;\n return sameScope(extractScopeFromCookies(cookieHeader), typed) ? null : typed;\n}\n\n/**\n * Gives the request's scope the type its settings answered with, for the rest of this\n * render, and files the settings and ads under the key the corrected scope makes, so the browser\n * — which reads the corrected scope from the cookie (see {@link scopeCookieUpdate}) — finds\n * them dehydrated instead of fetching them again. The entry under the assumed type's key\n * is removed, so the page carries them once. Server-only; a no-op when the type\n * already matches or the settings answered another scope.\n */\nexport function alignRequestScopeType(queryClient: QueryClient, settings: StoreContext): void {\n let scope: ActiveScope | null;\n try {\n scope = getTwilightContext().scope;\n } catch {\n return;\n }\n const answered = settings.store?.scope;\n if (!scope || !answered?.type || String(answered.id) !== scope.id) return;\n if (answered.type === scope.type) return;\n const assumedKey = storeApi.queries.settings().queryKey;\n const assumedAdsKey = advertisement.queries.list().queryKey;\n updateTwilightContext({ scope: { ...scope, type: answered.type } });\n queryClient.setQueryData(storeApi.queries.settings().queryKey, settings);\n // Moved, not copied: both would be dehydrated, sending the settings twice.\n queryClient.removeQueries({ queryKey: assumedKey, exact: true });\n const ads = queryClient.getQueryData(assumedAdsKey);\n if (ads) queryClient.setQueryData(advertisement.queries.list().queryKey, ads);\n queryClient.removeQueries({ queryKey: assumedAdsKey, exact: true });\n}\n\n/**\n * Writes {@link scopeCookieUpdate} to the response. Read from the request itself rather\n * than the middleware's context, for the same reason as {@link readServerCookieToken}.\n * Server-only.\n */\nexport const persistRequestScope = createIsomorphicFn()\n .server((settings: StoreContext): void => {\n let scope: ActiveScope | null;\n try {\n scope = scopeCookieUpdate(\n String(getRequestUrl()),\n getRequestHeader('cookie') ?? null,\n settings\n );\n } catch {\n // Outside a request (prerender): there is no response to write to.\n return;\n }\n if (!scope) return;\n setCookie(SCOPE_COOKIE_NAME, JSON.stringify(scope), {\n path: '/',\n maxAge: SCOPE_COOKIE_MAX_AGE,\n sameSite: 'lax',\n });\n })\n .client((): void => {});\n\n/** The request's cookie header: the framework's on the server, the document's in the browser. */\nconst requestCookies = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getRequestHeader('cookie') ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => (typeof document !== 'undefined' ? document.cookie : null));\n\n/** Remembers the owner view for the rest of this browser session; see {@link VIEW_AS_OWNER_COOKIE_NAME}. */\nconst rememberOwnerView = createIsomorphicFn()\n .server((storeId: string): void => {\n try {\n setCookie(VIEW_AS_OWNER_COOKIE_NAME, storeId, { path: '/', sameSite: 'lax' });\n } catch {\n // Outside a request (prerender): there is no response to write to.\n }\n })\n .client((storeId: string): void => {\n document.cookie = `${VIEW_AS_OWNER_COOKIE_NAME}=${storeId}; path=/; SameSite=Lax`;\n });\n\n/**\n * Whether this visitor sees the maintenance page instead of the store, deciding and\n * remembering the merchant's owner view on the way.\n *\n * Twig's backend lets the merchant into their closed store when the dashboard's link\n * brings them (`?utm_source=dashboard&identifier=<store id>`), and keeps that in the\n * session. Here the link grants a session cookie, and the cookie or the link is the\n * owner view. A customer gets the maintenance page, and `twilightMiddleware` turns the\n * render into a 503 (see `withMaintenanceStatus`).\n */\nexport function resolveMaintenance(href: string, settings: StoreContext): boolean {\n const fromLink = ownerLinkMatches(href, settings);\n const storeId = settings.store?.id;\n if (fromLink && storeId != null) rememberOwnerView(String(storeId));\n const viewAsOwner = fromLink || ownerCookieMatches(requestCookies(), settings);\n return showsMaintenancePage(settings, viewAsOwner);\n}\n\n/** On the server, once the settings are in: {@link alignRequestScopeType}, then {@link persistRequestScope}. */\nfunction settleRequestScope(queryClient: QueryClient, settings: StoreContext): void {\n if (typeof window !== 'undefined') return;\n alignRequestScopeType(queryClient, settings);\n persistRequestScope(settings);\n}\n\nexport interface BeforeLoadResult {\n settings: StoreContext;\n locale: string;\n dir: 'ltr' | 'rtl';\n authToken: string | null;\n /** Installed apps' snippets, threaded through the beforeLoad context (and recovered on the\n * client via ensureTwilightContextFromMatches) so AppsSnippets can render CDN tags in SSR. */\n appsSnippets?: AppSnippet[];\n /** Per-app public `app.*` buckets, threaded the same way so rootHead can install the\n * `Salla.appScope` factory inline in the SSR head. */\n appsSettings?: AppSettings;\n /** This visitor sees the maintenance page, not the store; see {@link resolveMaintenance}. */\n maintenance: boolean;\n}\n\n/**\n * The platform's copy for `locale`, with this merchant's own wording over it.\n *\n * Returns the platform's copy untouched — and makes no request — unless the\n * settings say this language has overrides. That gate is the whole reason this\n * is affordable: the object 404s for most stores, uncached, on the critical\n * path of an SSR render.\n *\n * The entry is found by ISO code rather than by index or key. The API sends\n * `languages` as an object keyed by **upper-case** ISO, and `storeApi` converts\n * it to an array on the way through (`languagesToArray`), so neither the\n * upper-case key nor a position is available here — and matching case-sensitively\n * on `code` would be a lookup that misses silently, leaving the flag absent and\n * the feature simply never running.\n *\n * Nothing about this is fatal. A failed override read leaves the platform's\n * copy in place, which is a storefront in the words Salla ships rather than a\n * storefront that did not render.\n */\nasync function withMerchantTranslations(\n queryClient: QueryClient,\n settings: StoreContext,\n locale: string,\n common: Awaited<ReturnType<typeof translations.get>>\n): Promise<Awaited<ReturnType<typeof translations.get>>> {\n const wanted = locale.toLowerCase();\n const language = settings.languages?.find(\n (entry) => (entry.iso_code ?? entry.code)?.toLowerCase() === wanted\n );\n const storeId = settings.store?.id;\n\n if (!language?.has_custom_translations || !storeId) return common;\n\n try {\n const overrides = await queryClient.ensureQueryData(\n translations.queries.byStore(storeId, locale)\n );\n\n return translations.merge(common, overrides, locale);\n } catch (error) {\n console.warn('[salla] merchant translations could not be read; using the platform copy', error);\n return common;\n }\n}\n\nexport async function rootBeforeLoad(ctx: {\n params: Record<string, string>;\n location: TwilightLocation;\n context: {\n queryClient: QueryClient;\n setLocation?: (location: Partial<TwilightLocation>) => void;\n };\n serverContext?: {\n authToken?: string | null;\n };\n}): Promise<BeforeLoadResult> {\n const locale = ctx.params.locale || FALLBACK_LOCALE;\n const { dir } = getLanguageInfo(locale);\n\n if (ctx.context.setLocation) {\n ctx.context.setLocation(ctx.location);\n }\n\n // Set locale in context before any API calls so interceptor uses correct locale\n updateTwilightContext({ locale });\n\n // Re-assert the locale on the Salla SDK on every navigation. The SDK's axios\n // accept-language header drifts off the route locale (navigator.language default,\n // account-language override on profile fetch — see syncSdkLocale), which makes\n // SDK API calls (e.g. the cart's salla.api.cart.details) return wrong-locale data.\n syncSdkLocale(locale);\n\n // Mirror the SDK's selected branch into the `scope` cookie. The SDK persists the\n // selection in localStorage ONLY, so the server — which can only see cookies —\n // would otherwise compute scope=null for every visitor who picked a branch, and\n // the dehydrated settings query (keyed on the scope) would never match on the\n // client. No-op on the server and while the SDK storage API is still hydrating.\n syncScopeCookie();\n\n // Kept until the rest have settled, as a missing answer always was, then thrown:\n // it says why the store did not load.\n let settingsFailure: unknown;\n const [settingsResult, translationsResult, snippetsResult, appSettingsResult] = await Promise.all(\n [\n ctx.context.queryClient.ensureQueryData(storeApi.queries.settings()).catch((error): null => {\n settingsFailure = error;\n return null;\n }),\n ctx.context.queryClient.ensureQueryData(translations.queries.byLocale(locale)),\n // Snippets → SSR CDN <script> tags (AppsSnippets.ssrCdnScripts). Non-fatal + logged:\n // on failure AppsSnippets falls back to its own client-side query for the same data,\n // so the tags render a paint later instead of being lost for the page load.\n ctx.context.queryClient.ensureQueryData(apps.queries.snippets()).catch((error): undefined => {\n console.warn('[salla] apps/snippets prefetch failed; rendering no CDN snippet tags', error);\n return undefined;\n }),\n // Buckets → rootHead installs `Salla.appScope` inline in the SSR head (before any snippet\n // onReady runs). Non-fatal + logged: the head installs the factory either way, and the\n // client query seeds the buckets into that install once it resolves.\n ctx.context.queryClient.ensureQueryData(apps.queries.settings()).catch((error): undefined => {\n console.warn(\n '[salla] apps/snippets/settings prefetch failed; appScope buckets unseeded',\n error\n );\n return undefined;\n }),\n // Ads → the header's announcement bar renders on the server, so it no longer pushes the\n // page down when it arrives. Non-fatal: the bar then loads on the client, as before.\n ctx.context.queryClient\n .ensureQueryData(advertisement.queries.list())\n .catch((error): undefined => {\n console.warn('[salla] advertisements prefetch failed; the ad bar loads late', error);\n return undefined;\n }),\n ]\n );\n\n if (!settingsResult) {\n throw settingsFailure instanceof SettingsError ? settingsFailure : new SettingsError();\n }\n\n // Settings answered for another market name another theme version; the SDK only\n // read its `s-version-id` at init — see syncSdkThemeVersion.\n syncSdkThemeVersion(settingsResult.headers);\n\n settleRequestScope(ctx.context.queryClient, settingsResult);\n\n // On a host where the store is the root of every URL, a page has one address:\n // `/<username>/…`. A request that found its store some other way (`?storeId=`,\n // the preview cookie, `VITE_STORE_DOMAIN`) is sent there now that the settings\n // say what the username is. A full load rather than a client navigation, because\n // the router handling this request was built without that root.\n const storeBaseHref = resolveStoreBaseRedirect(settingsResult.store?.username, ctx.location.href);\n if (storeBaseHref) {\n throw redirect({ href: storeBaseHref, reloadDocument: true, replace: true });\n }\n\n const maintenance = resolveMaintenance(ctx.location.href, settingsResult);\n\n // The merchant's own wording, laid over the platform's — but only when the\n // settings say this language has any.\n //\n // Sequenced after the `Promise.all` on purpose: the object is keyed by\n // `settings.store.id`, which the settings query is what produces, so this\n // cannot join the batch above. The cost of a second round trip is why it is\n // gated rather than always fetched — see `api/translations.ts` for the two\n // corrections that shape led to.\n const messages = await withMerchantTranslations(\n ctx.context.queryClient,\n settingsResult,\n locale,\n translationsResult\n );\n\n // Create i18n instance with loaded translations\n const i18n = createI18nInstance(locale, messages ?? undefined);\n\n // Resolve authToken with fallback chain:\n // 1. SSR context (from middleware extracting cookies on server)\n // 2. The twilight context token. On the SERVER this is the token twilightMiddleware\n // extracted from the `token` cookie into the request ALS — reading it here is\n // essential, otherwise this loader's updateTwilightContext() below would\n // overwrite the middleware's token with null and every SSR render (e.g. the\n // account hub) would be unauthenticated. On the CLIENT it's the clientStore\n // token from hydration or a previous navigation.\n // 3. The `token` cookie read directly — client fallback when clientStore is empty\n // and salla.storage hasn't hydrated yet.\n // 4. Salla SDK storage (salla.storage.get('token'))\n let existingToken: string | null = null;\n try {\n existingToken = getTwilightContext().authToken;\n } catch {\n // No request context (e.g. server call outside the middleware ALS) — fall through.\n existingToken = null;\n }\n const cookieToken =\n typeof document !== 'undefined'\n ? extractTokenFromCookies(document.cookie, AUTH_TOKEN_COOKIE_NAME)\n : null;\n const sallaToken =\n typeof window !== 'undefined' && typeof window.salla?.storage?.get === 'function'\n ? (window.salla.storage.get(AUTH_TOKEN_COOKIE_NAME) as string | null)\n : null;\n const serverCookieToken = readServerCookieToken();\n const authToken =\n ctx.serverContext?.authToken ??\n serverCookieToken ??\n existingToken ??\n cookieToken ??\n sallaToken ??\n null;\n\n updateTwilightContext({\n queryClient: ctx.context.queryClient,\n settings: settingsResult,\n locale,\n location: ctx.location,\n i18n,\n authToken,\n appsSnippets: snippetsResult,\n appsSettings: appSettingsResult,\n maintenance,\n });\n\n return {\n settings: settingsResult,\n locale,\n dir,\n authToken,\n appsSnippets: snippetsResult,\n appsSettings: appSettingsResult,\n maintenance,\n };\n}\n","/**\n * @fileoverview The store segment, carried by the router instead of the route tree.\n *\n * TanStack Router rewrites every location it reads and every one it writes:\n * `input` runs before a URL is matched, and `output` before an href is rendered,\n * pushed to history or sent as a redirect's `Location`. So on a host where the\n * store is the root, the route tree stays `/{-$locale}/cart` and\n * `<Link to=\"/cart\">` renders `/mtgr-alaatr-2/cart` by itself.\n *\n * Why not the router's `basepath`: TanStack Start overwrites it from the build on\n * both sides (`router.update({ basepath })` per request on the server, and in\n * `hydrateStart` on the client). `rewrite` is a separate option that the router\n * composes with that basepath, so it survives. Server functions are dispatched on\n * the raw URL before the router runs, and assets are root-absolute, so neither\n * moves. See `docs/store-base-path.md`.\n */\nimport type { LocationRewrite } from '@tanstack/react-router';\nimport { prefixStoreBase, stripStoreBase } from '../utils/store-base';\n\n/**\n * A rewrite that serves the application from `/<base>`, or from `/<locale>/<base>`\n * when `followsLocale` (a Salla shared host, `/ar/dev-x/cart`).\n */\nexport function storeBaseRewrite(base: string, followsLocale = false): LocationRewrite {\n return {\n input: ({ url }) => {\n url.pathname = stripStoreBase(url.pathname, base, followsLocale);\n return url;\n },\n output: ({ url }) => {\n url.pathname = prefixStoreBase(url.pathname, base, followsLocale);\n return url;\n },\n };\n}\n","import type { ReactNode } from 'react';\nimport { lazy, Suspense } from 'react';\nimport {\n createRouter as createTanStackRouter,\n createRootRouteWithContext,\n} from '@tanstack/react-router';\nimport type { RouterHistory } from '@tanstack/react-router';\nimport { QueryClient } from '@tanstack/react-query';\nimport { shouldDehydrateQuery } from '../api/product';\nimport { PageSkeleton } from '@salla.sa/twilight-components-react/skeletons';\nimport { setHeadAdapter } from '../utils/head';\nimport { tanstackHeadAdapter } from './head';\nimport { stringifySearch } from './search';\nimport {\n updateTwilightContext,\n type PageContext,\n type TwilightLocation,\n} from '../twilight/context';\nimport type { Product } from '../types';\nimport { dispatchProductViewed, dispatchRouteChanged } from '../utils/sdk-events';\nimport { rootBeforeLoad, type BeforeLoadResult } from '../routes/root/beforeLoad';\nimport { rootHead } from '../routes/root/head';\nimport { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query';\nimport type { AnyRouter } from '@tanstack/react-router';\nimport { RouteId, type RouteIdType } from '../router/route-ids';\nimport { UnauthorizedError, NotFoundError, RedirectError } from '../providers/NavigationProvider';\nimport { ErrorPage } from '../components/common/ErrorPage';\nimport type { StoreContext } from '../api/store';\nimport type { AppSnippet, AppSettings } from '../api/apps';\nimport { createI18nInstance } from '../providers/i18n-factory';\nimport { messagesForLocale } from '../api/messages';\nimport { resolveStoreBase, resolveStoreBaseFollowsLocale } from '../utils/store-identity';\nimport { storeBaseRewrite } from './store-base';\n\n/**\n * Initial router context passed from createRouter to beforeLoad.\n */\nexport interface RouterInitialContext {\n queryClient: QueryClient;\n setLocation: (_location: Partial<TwilightLocation>) => void;\n}\n\n/**\n * TanStack Router ID Mapping\n *\n * Maps TanStack's auto-generated path-based route IDs to semantic RouteId constants.\n * This mapping is TanStack-specific because different frameworks generate route IDs differently:\n *\n * - TanStack: Uses file path as ID (e.g., '/{-$locale}/cart')\n * - Next.js: Uses file path without locale (e.g., '/cart')\n *\n * The mapping enables hooks like useIsHome(), useIsProduct() to work consistently\n * across frameworks while each framework has its own ID generation strategy.\n */\nexport const TANSTACK_ROUTE_ID_MAP: Record<string, RouteIdType> = {\n '/{-$locale}/': RouteId.INDEX,\n '/{-$locale}/cart': RouteId.CART,\n '/{-$locale}/search': RouteId.SEARCH,\n\n '/{-$locale}/latest-products': RouteId.PRODUCT_INDEX_LATEST,\n '/{-$locale}/most-sales-products': RouteId.PRODUCT_INDEX_SALES,\n '/{-$locale}/offers': RouteId.PRODUCT_INDEX_OFFERS,\n '/{-$locale}/products': RouteId.PRODUCT_INDEX,\n\n '/{-$locale}/$slug/c{$id}': RouteId.PRODUCT_INDEX,\n '/{-$locale}/$slug/p{$id}': RouteId.PRODUCT_SINGLE,\n '/{-$locale}/$slug/brand-{$id}': RouteId.BRANDS_SINGLE,\n '/{-$locale}/$slug/tag-{$id}': RouteId.PRODUCT_INDEX_TAG,\n '/{-$locale}/$slug/page-{$id}': RouteId.PAGE_SINGLE,\n\n '/{-$locale}/blog': RouteId.BLOG_INDEX,\n '/{-$locale}/blog/$slug/a-{$id}': RouteId.BLOG_SINGLE,\n '/{-$locale}/blog/$slug/c-{$id}': RouteId.BLOG_INDEX_CATEGORY,\n '/{-$locale}/blog/$slug/tag-{$id}': RouteId.BLOG_INDEX_TAG,\n '/{-$locale}/blog/author/$id': RouteId.BLOG_INDEX_AUTHOR,\n\n '/{-$locale}/brands': RouteId.BRANDS_INDEX,\n '/{-$locale}/brands/$id': RouteId.BRANDS_SINGLE,\n '/{-$locale}/tags/$id': RouteId.PRODUCT_INDEX_TAG,\n\n '/{-$locale}/profile': RouteId.CUSTOMER_PROFILE,\n '/{-$locale}/wishlist': RouteId.CUSTOMER_WISHLIST,\n '/{-$locale}/wallet': RouteId.CUSTOMER_WALLET,\n '/{-$locale}/notifications': RouteId.CUSTOMER_NOTIFICATIONS,\n '/{-$locale}/settings': RouteId.CUSTOMER_SETTINGS,\n '/{-$locale}/orders': RouteId.CUSTOMER_ORDERS_INDEX,\n '/{-$locale}/order/$id': RouteId.CUSTOMER_ORDERS_SINGLE,\n '/{-$locale}/pending-orders': RouteId.CUSTOMER_ORDERS_INDEX_PENDING,\n '/{-$locale}/account/pending_orders': RouteId.CUSTOMER_ORDERS_INDEX_PENDING,\n '/{-$locale}/account/rating': RouteId.CUSTOMER_ORDERS_INDEX,\n\n '/{-$locale}/logout': RouteId.LOGOUT,\n '/{-$locale}/loyalty': RouteId.LOYALTY,\n '/{-$locale}/loyalty_points': RouteId.CUSTOMER_LOYALTY_POINTS,\n '/{-$locale}/testimonials': RouteId.TESTIMONIALS,\n '/{-$locale}/reviews': RouteId.REVIEWS,\n '/{-$locale}/thankyou/$orderId': RouteId.THANK_YOU,\n};\n\n/**\n * Resolves a TanStack route ID to a semantic RouteId constant.\n * Falls back to the original ID if no mapping exists.\n * @internal Exported for testing\n */\nexport function resolveRouteId(tanstackId: string): string {\n return TANSTACK_ROUTE_ID_MAP[tanstackId] ?? tanstackId;\n}\n\n// Lazy load NotFoundPage for code splitting\nconst LazyNotFoundPage = lazy(() =>\n import('../routes/not-found').then((m) => ({ default: m.NotFoundPage }))\n);\n\n/**\n * Error component shown when the root route fails to load.\n * This renders a minimal HTML page with error details.\n */\nfunction StoreUnavailablePage() {\n return (\n <>\n <div\n style={{\n position: 'fixed',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: '#f9fafb',\n }}\n >\n <div style={{ textAlign: 'center', padding: '2rem' }}>\n <h1 style={{ fontSize: '1.5rem', marginBottom: '0.5rem' }}>\n Store is temporarily unavailable\n </h1>\n <p style={{ color: '#6b7280' }}>\n We&apos;re having trouble loading the store. Please try again in a moment.\n </p>\n <button\n type=\"button\"\n onClick={() => window.location.reload()}\n style={{\n marginTop: '1rem',\n padding: '0.75rem 1.5rem',\n fontSize: '1rem',\n border: 'none',\n borderRadius: '0.5rem',\n background: '#111827',\n color: '#fff',\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n </div>\n </div>\n </>\n );\n}\n\nfunction RootErrorComponent({ error: _error }: { error: Error }) {\n return (\n <html lang=\"ar\" dir=\"rtl\">\n <head>\n <meta charSet=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Store Unavailable</title>\n </head>\n <body style={{ margin: 0, fontFamily: 'sans-serif' }}>\n <StoreUnavailablePage />\n </body>\n </html>\n );\n}\n\n/**\n * Creates the root route pre-configured with RouterInitialContext.\n * beforeLoad will fetch settings/translations, loader returns serializable data.\n *\n * @example\n * ```ts\n * export const Route = createTwilightRootRoute()({ shellComponent });\n * ```\n */\nexport function createTwilightRootRoute() {\n const factory = createRootRouteWithContext<RouterInitialContext>();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TanStack Router factory expects `any` for spread options\n return (options: any) =>\n factory({\n beforeLoad: rootBeforeLoad,\n head: rootHead,\n errorComponent: RootErrorComponent,\n ...options,\n });\n}\n\n/**\n * Default error component for route-level errors.\n */\nexport function DefaultErrorComponent({ error }: { error: unknown }) {\n if (error instanceof RedirectError) {\n return null;\n }\n\n if (error instanceof NotFoundError) {\n return <ErrorPage code={404} message={error.message} />;\n }\n\n if (error instanceof UnauthorizedError) {\n return <ErrorPage code={401} message={error.message} showAction={false} />;\n }\n\n const message =\n error instanceof Error\n ? error.message\n : error &&\n typeof error === 'object' &&\n 'message' in error &&\n typeof error.message === 'string'\n ? error.message\n : undefined;\n\n if (error && typeof error === 'object' && 'response' in error) {\n return <ErrorPage code={400} message={message} />;\n }\n\n return <ErrorPage code={500} message={message} />;\n}\n\n/**\n * SSR integration for Twilight context — mirrors TanStack Query's\n * `setupRouterSsrQueryIntegration` pattern.\n *\n * On the **server**: wraps `router.options.dehydrate` to include twilight\n * context data (settings, locale, location, authToken) alongside the router state.\n *\n * On the **client**: wraps `router.options.hydrate` to populate the module-level\n * store from the root match's `__beforeLoadContext` BEFORE head functions re-run.\n * TanStack's `hydrate()` calls `router.options.hydrate()` at line 114 of\n * `ssr-client.ts`, right before it re-evaluates head functions (line 120+).\n * By populating the store here, `getTwilightContext().settings` is available\n * to `rootHead()` and all child head functions during client hydration.\n */\nfunction setupTwilightSsrIntegration(router: AnyRouter, queryClient: QueryClient): void {\n if (typeof window === 'undefined') {\n // Server: also populate twilightCtx from root match context on dehydrate\n return;\n }\n\n // Client: hook into router.options.hydrate to populate the module store\n // from the root match's __beforeLoadContext (set by rootBeforeLoad on the server)\n const ogHydrate = router.options.hydrate;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n router.options.hydrate = async (dehydratedData: any) => {\n await ogHydrate?.(dehydratedData);\n hydrateTwilightContext(router, queryClient);\n };\n}\n\nfunction warnHydrationBail(reason: string): void {\n // Silent failure here is what blanks the storefront: every head function that\n // runs next reads `getTwilightContext().settings`, which throws when the store\n // is empty. `ensureTwilightContextFromMatches` recovers at the point of use,\n // but the bail still signals a regression worth seeing in dev.\n if (import.meta.env?.DEV) {\n console.warn(`[Twilight] Could not hydrate twilight context: ${reason}`);\n }\n}\n\nfunction routerLocation(router: AnyRouter): TwilightLocation | undefined {\n const loc = router.state?.location;\n if (!loc) return undefined;\n return {\n href: loc.href,\n pathname: loc.pathname,\n search: loc.search as Record<string, unknown>,\n searchStr: loc.searchStr,\n state: loc.state as unknown as Record<string, unknown>,\n hash: loc.hash,\n };\n}\n\nfunction hydrateTwilightContext(router: AnyRouter, queryClient: QueryClient): void {\n const location = routerLocation(router);\n // A direct load can hydrate before its matches exist.\n if (location) updateTwilightContext({ location });\n\n const rootMatch = router.state?.matches?.[0];\n if (!rootMatch) {\n warnHydrationBail('no root match in router state');\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const beforeLoadCtx = (rootMatch as any).__beforeLoadContext as BeforeLoadResult | undefined;\n const matchCtx = rootMatch.context as Record<string, unknown> | undefined;\n\n const settings = (beforeLoadCtx?.settings ?? matchCtx?.settings) as StoreContext | undefined;\n const locale = (beforeLoadCtx?.locale ?? matchCtx?.locale) as string | undefined;\n const authToken = (beforeLoadCtx?.authToken ?? matchCtx?.authToken) as string | null;\n // Recover snippets here too: this is the primary hydration pass and populates settings, so the\n // best-effort ensureTwilightContextFromMatches fallback then short-circuits — if we skipped\n // appsSnippets here it would never reach the client store, and AppsSnippets' SSR-rendered CDN\n // tags would mismatch on hydration.\n const appsSnippets =\n beforeLoadCtx?.appsSnippets ?? (matchCtx?.appsSnippets as AppSnippet[] | undefined);\n // Recover appScope buckets too (like appsSnippets): this primary pass populates settings, so the\n // ensure-context fallback short-circuits — keep the client store in parity for head/install.\n const appsSettings =\n beforeLoadCtx?.appsSettings ?? (matchCtx?.appsSettings as AppSettings | undefined);\n // The maintenance decision too, for the same parity: the server rendered the maintenance\n // page from it, and the provider reads it on the client.\n const maintenance = (beforeLoadCtx?.maintenance ?? matchCtx?.maintenance) === true;\n\n if (!settings || !locale) {\n warnHydrationBail(\n `root match carried no ${!settings ? 'settings' : 'locale'} (beforeLoadContext and context both empty)`\n );\n return;\n }\n\n // Composed by the shared helper rather than read straight off one key.\n // There are two entries now — the platform's copy and this merchant's — and\n // reading only the first is how the server rendered the merchant's wording\n // and hydration replaced it with Salla's (Greptile's P1 on #366).\n const i18n = createI18nInstance(locale, messagesForLocale(queryClient, locale));\n\n const matches = router.state?.matches;\n const page = matches?.reduceRight(\n (found, m) => found ?? ((m as any).loaderData?.page ? (m as any).loaderData.page : null),\n null as any\n );\n\n // Resolve routeId on the initial load too — `onResolved` only fires on later\n // navigations, so without this the store keeps the empty default until the\n // first SPA navigation (breaks useRouteId/useIsHome on first paint/refresh).\n const leafMatch = matches?.[matches.length - 1];\n const routeId = leafMatch?.routeId ? resolveRouteId(leafMatch.routeId as string) : undefined;\n\n updateTwilightContext({\n queryClient,\n settings,\n locale,\n i18n,\n authToken,\n location,\n page,\n routeId,\n appsSnippets,\n appsSettings,\n maintenance,\n });\n}\n\ninterface PageLoaderData {\n page?: PageContext;\n product?: Product;\n}\n\n/** The navigation that last reported a product view: onLoad and onRendered both sync each one. */\nlet lastProductView: string | undefined;\n\n/** Publishes the deepest match's loader `page` to the twilight context and `salla.config`. */\nfunction syncPageFromMatches(router: AnyRouter): void {\n const matches = router.state?.matches;\n if (!matches) return;\n const data = matches.reduceRight<PageLoaderData | null>((found, m) => {\n const loaderData = (m as { loaderData?: PageLoaderData }).loaderData;\n return found ?? (loaderData?.page ? loaderData : null);\n }, null);\n const page = data?.page;\n if (!page) return;\n updateTwilightContext({ page });\n const sdkPage = {\n ...page,\n url: page.url ?? router.state.location.pathname + router.state.location.searchStr,\n };\n const push = () => window.salla?.config?.set?.('page', sdkPage);\n // The SDK script can run after hydration; it must have the page before it is ready.\n if (window.salla?.config?.set) push();\n else window.addEventListener('salla::created', push, { once: true });\n\n const view = router.state.location.state?.key ?? router.state.location.href;\n if (page.slug !== RouteId.PRODUCT_SINGLE || !data.product) {\n lastProductView = undefined;\n } else if (view !== lastProductView) {\n lastProductView = view;\n dispatchProductViewed(data.product);\n }\n}\n\n/**\n * Options for creating the TanStack Router instance.\n */\nexport interface CreateRouterOptions {\n defaultPendingComponent?: (() => ReactNode) | false;\n defaultPendingMs?: number;\n defaultPendingMinMs?: number;\n defaultStaleTime?: number;\n history?: RouterHistory;\n}\n\n/**\n * Creates and configures the TanStack Router instance for the Twilight theme.\n *\n * This router is pre-configured with:\n * - Route tree generated by the TanStack Router plugin\n * - Intent-based preload for better performance\n * - Scroll restoration for better UX\n * - Locale-aware default NotFoundPage (redirects `/cart` → `/ar/cart`)\n * - Trailing slash normalization for consistent URL handling\n * - Page skeleton shown during route transitions (via `defaultPendingComponent`)\n * - SSR query integration for Cloudflare compatibility\n *\n * @param routeTree - The generated route tree from the consuming project\n * @param options - Optional overrides for pending component behavior\n * @returns Configured TanStack Router instance\n */\nexport function createRouter(routeTree: any, options?: CreateRouterOptions) {\n setHeadAdapter(tanstackHeadAdapter);\n\n const {\n defaultPendingComponent: pendingOpt,\n defaultPendingMs = 100,\n defaultPendingMinMs = 200,\n defaultStaleTime = Infinity,\n history,\n } = options ?? {};\n\n const pendingComponent =\n pendingOpt === false ? undefined : (pendingOpt ?? (() => <PageSkeleton />));\n\n const queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 60_000,\n gcTime: 5 * 60_000,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n mutations: {\n retry: 0,\n },\n dehydrate: {\n shouldDehydrateQuery,\n },\n },\n });\n\n // Store queryClient in the holder for access by loaders via getTwilightContext()\n updateTwilightContext({ queryClient });\n\n // On a host that serves many stores, the store is a segment of every URL: the\n // first one on the preview host, the one after the locale on a Salla shared\n // host. The router carries it instead of the route tree: it is stripped before\n // matching and added to every href the router builds. Decided per request on\n // the server, and taken from what SSR published in the browser.\n const storeBase = resolveStoreBase();\n\n const router = createTanStackRouter({\n routeTree,\n ...(history ? { history } : {}),\n ...(storeBase ? { rewrite: storeBaseRewrite(storeBase, resolveStoreBaseFollowsLocale()) } : {}),\n context: {\n queryClient,\n setLocation: (location: Partial<TwilightLocation>) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n updateTwilightContext({ location } as any);\n },\n },\n defaultPreload: 'intent',\n scrollRestoration: true,\n scrollRestorationBehavior: 'instant',\n trailingSlash: 'never',\n stringifySearch,\n defaultStaleTime,\n defaultNotFoundComponent: () => (\n <Suspense fallback={<PageSkeleton />}>\n <LazyNotFoundPage />\n </Suspense>\n ),\n defaultPendingComponent: pendingComponent,\n defaultPendingMs,\n defaultPendingMinMs,\n defaultErrorComponent: DefaultErrorComponent,\n });\n\n // Setup SSR query integration (native, with incremental streaming)\n setupRouterSsrQueryIntegration({ router, queryClient });\n\n // Setup Twilight SSR integration — populates the module store from\n // dehydrated match context BEFORE head functions re-run on the client.\n // This mirrors how setupRouterSsrQueryIntegration hydrates QueryClient.\n setupTwilightSsrIntegration(router, queryClient);\n\n // Subscribe to navigation events to sync location and routeId\n function syncNavigationState() {\n const state = router?.state;\n if (!state?.location) return;\n\n const loc = state.location;\n updateTwilightContext({\n location: {\n href: loc.href,\n pathname: loc.pathname,\n search: loc.search as Record<string, unknown>,\n searchStr: loc.searchStr,\n state: loc.state as unknown as Record<string, unknown>,\n hash: loc.hash,\n },\n });\n\n const matches = state.matches;\n const leafMatch = matches[matches.length - 1];\n if (leafMatch?.routeId) {\n const semanticId = resolveRouteId(leafMatch.routeId as string);\n updateTwilightContext({ routeId: semanticId });\n }\n\n const rootMatch = state.matches[0];\n if (rootMatch?.context) {\n const ctx = rootMatch.context as BeforeLoadResult;\n if (ctx?.settings) {\n updateTwilightContext({ settings: ctx.settings, locale: ctx.locale });\n }\n }\n }\n\n // Extract page from matches as soon as loaders complete (before components mount),\n // so useTwilightInit's useEffect sees page data when it calls sdk.init().\n router.subscribe('onLoad', () => syncPageFromMatches(router));\n // A direct load resolves through hydration, which emits no onLoad; its first render does emit onRendered.\n router.subscribe('onRendered', () => syncPageFromMatches(router));\n\n // Sync location, routeId, and settings after navigation fully resolves\n router.subscribe('onResolved', () => {\n syncNavigationState();\n dispatchRouteChanged();\n });\n\n return router;\n}\n\ndeclare module '@tanstack/react-router' {\n interface Register {\n router: ReturnType<typeof createRouter>;\n }\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Required by TanStack Router module augmentation pattern\n interface RouterContext extends RouterInitialContext {}\n}\n","import { useRouterState } from '@tanstack/react-router';\nimport {\n mergeElementAttrs,\n toReactProps,\n type DocumentElementDescriptor,\n} from '../utils/document-class';\nimport { useDocumentClass } from '../hooks/useDocumentClass';\nimport { updateTwilightContext, type PageContext } from '../twilight/context';\nimport { resolveRouteId } from './router';\n\n// ============================================================================\n// Route → body class map (mirrors PHP Route2Class::generateClassString)\n// Keyed by TanStack Router route ID (the path passed to createFileRoute).\n// null = intentionally classless (e.g. root layout routes).\n// ============================================================================\n\nconst ROUTE_CLASS_MAP: Record<string, string | null> = {\n '/{-$locale}/': 'index',\n '/{-$locale}/cart': 'cart',\n '/{-$locale}/$slug/c{$id}': 'product-index',\n '/{-$locale}/offers': 'product-index-offers',\n '/{-$locale}/products': 'product-index',\n '/{-$locale}/latest-products': 'product-index-latest',\n '/{-$locale}/most-sales-products': 'product-index-sales',\n '/{-$locale}/search': 'product-index-search',\n '/{-$locale}/$slug/tag-{$id}': 'product-index-tag',\n '/{-$locale}/tags/$id': 'product-index-tag',\n '/{-$locale}/$slug/p{$id}': 'product-single',\n '/{-$locale}/$slug/page-{$id}': 'page-single',\n '/{-$locale}/page/$slug': 'page-single',\n '/{-$locale}/p/$slug': 'page-single',\n '/{-$locale}/thankyou/$orderId': 'thank-you',\n '/{-$locale}/orders': 'customer-orders-index',\n '/{-$locale}/pending-orders': 'customer-orders-index-pending', // redirect to /account/orders?status=pending\n '/{-$locale}/account/pending_orders': 'customer-orders-index-pending',\n '/{-$locale}/account/rating': 'customer-orders-index', // redirect to /account/orders\n '/{-$locale}/order/$id': 'customer-orders-single',\n '/{-$locale}/profile': 'customer-profile',\n '/{-$locale}/wallet': 'customer-wallet',\n '/{-$locale}/wishlist': 'customer-wishlist',\n '/{-$locale}/notifications': 'customer-notifications',\n '/{-$locale}/testimonials': 'testimonials',\n '/{-$locale}/reviews': 'reviews',\n '/{-$locale}/brands': 'brands-index',\n '/{-$locale}/brands/$id': 'brands-single',\n '/{-$locale}/$slug/brand-{$id}': 'brands-single',\n '/{-$locale}/blog': 'blog-index',\n '/{-$locale}/blog/$slug/a-{$id}': 'blog-single',\n '/{-$locale}/blog/$slug/c-{$id}': 'blog-index-category',\n '/{-$locale}/blog/$slug/tag-{$id}': 'blog-index-tag',\n '/{-$locale}/blog/author/$id': 'blog-index-author',\n '/{-$locale}/loyalty': 'loyalty',\n '/{-$locale}/loyalty_points': 'customer-loyalty-points',\n};\n\n/** `/products?source=` keeps the Twig class of the old listing URL. */\nconst PRODUCTS_SOURCE_CLASS: Record<string, string> = {\n latest: 'product-index-latest',\n sales: 'product-index-sales',\n offers: 'product-index-offers',\n};\n\nfunction routeClassOf(matches: Array<{ routeId: string; search?: unknown }>): string | null {\n for (let i = matches.length - 1; i >= 0; i--) {\n const { routeId, search } = matches[i];\n if (routeId === '/{-$locale}/products') {\n const source = (search as { source?: unknown } | undefined)?.source;\n return typeof source === 'string' && Object.hasOwn(PRODUCTS_SOURCE_CLASS, source)\n ? PRODUCTS_SOURCE_CLASS[source]\n : 'product-index';\n }\n if (routeId in ROUTE_CLASS_MAP) return ROUTE_CLASS_MAP[routeId];\n }\n return null;\n}\n\n// ============================================================================\n// RouteDocumentSync — resolves body class from active route ID at runtime.\n// ============================================================================\n\n/**\n * Applies the per-route body class by looking up the deepest active route ID\n * in the built-in route→class map.\n *\n * For custom routes not in the built-in map, use `useDocumentClass` directly\n * inside your route component.\n *\n * Note: This will throw if rendered outside a TanStack Router context.\n * Use TanStackDocumentSync for safe usage inside TwilightProvider.\n */\nexport function RouteDocumentSync(): null {\n const matches = useRouterState({ select: (s) => s.matches });\n\n const routeClass = routeClassOf(matches);\n\n useDocumentClass(routeClass ? { body: { class: routeClass } } : {});\n return null;\n}\n\n/**\n * Safe version of RouteDocumentSync for use in TwilightProvider.\n * Handles being rendered outside a TanStack Router context gracefully.\n * Uses a wrapper component pattern to conditionally render hooks.\n */\nexport function TanStackDocumentSync(): null {\n const matches = useRouterState({ select: (s) => s.matches }) || [];\n\n // On the server routeId is never synced (onResolved is client-only), so useIsHome()\n // etc. disagree with the client and cause hydration mismatches. Sync it here — this\n // renders before the layout. Client already has it from onResolved.\n if (typeof window === 'undefined') {\n const leaf = matches[matches.length - 1];\n if (leaf?.routeId) {\n updateTwilightContext({ routeId: resolveRouteId(leaf.routeId as string) });\n }\n // The deepest loader's page, which the client syncs on load (`syncPageFromMatches`).\n const page = matches.reduceRight<PageContext | undefined>(\n (found, match) => found ?? (match.loaderData as { page?: PageContext } | undefined)?.page,\n undefined\n );\n if (page) updateTwilightContext({ page });\n }\n\n const routeClass = routeClassOf(matches);\n\n useDocumentClass(routeClass ? { body: { class: routeClass } } : {});\n return null;\n}\n\n// ============================================================================\n// Type augmentation — extend TanStack Router's staticData type\n// ============================================================================\n\ndeclare module '@tanstack/react-router' {\n interface StaticDataRouteOption {\n documentAttrs?: DocumentElementDescriptor;\n }\n}\n\nexport interface TanstackRouteStaticData {\n documentAttrs?: DocumentElementDescriptor;\n}\n\n// ============================================================================\n// useTanstackDocumentAttrs — for TanStack Start SSR root layouts\n// ============================================================================\n\n/**\n * Read and merge `<body>` / `<html>` attributes from all currently active\n * route matches (via `staticData.documentAttrs`).\n *\n * Returns React-ready prop objects ready to spread onto `<html>` and `<body>`.\n */\nexport function useTanstackDocumentAttrs(): {\n bodyAttrs: Record<string, string>;\n htmlAttrs: Record<string, string>;\n} {\n const matches = useRouterState({ select: (s) => s.matches });\n\n const bodyDescriptors = matches.map(\n (m) => (m.staticData as TanstackRouteStaticData | undefined)?.documentAttrs?.body ?? {}\n );\n const htmlDescriptors = matches.map(\n (m) => (m.staticData as TanstackRouteStaticData | undefined)?.documentAttrs?.html ?? {}\n );\n\n return {\n bodyAttrs: toReactProps(mergeElementAttrs(bodyDescriptors)),\n htmlAttrs: toReactProps(mergeElementAttrs(htmlDescriptors)),\n };\n}\n\n/**\n * Pure adapter: converts a `DocumentElementDescriptor` to React-ready props.\n */\nexport function tanstackDocumentAdapter(descriptor: DocumentElementDescriptor): {\n bodyAttrs: Record<string, string>;\n htmlAttrs: Record<string, string>;\n} {\n return {\n bodyAttrs: toReactProps(mergeElementAttrs([descriptor.body ?? {}])),\n htmlAttrs: toReactProps(mergeElementAttrs([descriptor.html ?? {}])),\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { getActiveScope, api } from './chunk-YDSWLCOY.js';
2
- import { getTwilightContext } from './chunk-JNAJTCJD.js';
1
+ import { getActiveScope, api } from './chunk-TTTI4W5F.js';
2
+ import { getTwilightContext } from './chunk-QRHXAKJ3.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  function advertisementsFor(ads, pageSlug) {
@@ -25,5 +25,5 @@ var advertisement = {
25
25
  };
26
26
 
27
27
  export { advertisement, advertisementsFor };
28
- //# sourceMappingURL=chunk-4PT5MXGR.js.map
29
- //# sourceMappingURL=chunk-4PT5MXGR.js.map
28
+ //# sourceMappingURL=chunk-NEPWW7KM.js.map
29
+ //# sourceMappingURL=chunk-NEPWW7KM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/advertisement.ts"],"names":[],"mappings":";;;;AAkBO,SAAS,iBAAA,CACd,KACA,QAAA,EACiB;AACjB,EAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACT,CAAC,EAAA,KACC,KAAA,CAAM,QAAQ,EAAA,CAAG,KAAK,MACrB,EAAA,CAAG,KAAA,CAAM,QAAA,CAAS,KAAK,KAAM,CAAC,CAAC,YAAY,EAAA,CAAG,KAAA,CAAM,SAAS,QAAQ,CAAA;AAAA,GAC1E;AACF;AAEO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,MAAM,YAAsC;AAE1C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,gBAAA,EAAkB,EAAE,OAAA,EAAS,GAAA,EAAM,CAAA,CACvC,IAAA,EAAiC;AACpC,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,OAAO,EAAC;AAAA,EACvC,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,MACJ,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,gBAAA,EAAkB,kBAAA,EAAmB,CAAE,QAAQ,EAAE,KAAA,EAAO,cAAA,EAAe,EAAG,CAAA;AAAA,MACrF,OAAA,EAAS,MAAM,aAAA,CAAc,IAAA,EAAK;AAAA,MAClC,SAAA,EAAW,QAAA;AAAA;AAAA,MAEX,KAAA,EAAO;AAAA,KACR;AAAA;AAEP","file":"chunk-4PT5MXGR.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport { getTwilightContext } from '../twilight/context';\n\n/** A merchant's announcement bar, as `GET advertisements` returns it. */\nexport interface Advertisement {\n id: number;\n title?: string;\n description?: string;\n icon?: string | null;\n url?: string | null;\n target?: string | null;\n colors?: { bg?: string; text?: string };\n /** Page slugs the ad shows on (`salla.config` `page.slug`), or `all`. */\n pages?: string[];\n}\n\n/** The ads a page shows: the rule the API applies to `?page=`, run on the full list. */\nexport function advertisementsFor(\n ads: readonly Advertisement[],\n pageSlug: string | null | undefined\n): Advertisement[] {\n return ads.filter(\n (ad) =>\n Array.isArray(ad.pages) &&\n (ad.pages.includes('all') || (!!pageSlug && ad.pages.includes(pageSlug)))\n );\n}\n\nexport const advertisement = {\n /** Every active ad, unfiltered: one request serves all pages, filtered with `advertisementsFor`. */\n list: async (): Promise<Advertisement[]> => {\n // Short timeout: it is fetched with the store settings on every server render.\n const { data } = await api\n .get('advertisements', { timeout: 3000 })\n .json<{ data?: Advertisement[] }>();\n return Array.isArray(data) ? data : [];\n },\n\n queries: {\n list: () =>\n queryOptions({\n queryKey: ['advertisements', getTwilightContext().locale, { scope: getActiveScope() }],\n queryFn: () => advertisement.list(),\n staleTime: Infinity,\n // Awaited in rootBeforeLoad: a retry would double the 3s budget. `PageAdvertisements` retries.\n retry: 0,\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/advertisement.ts"],"names":[],"mappings":";;;;AAkBO,SAAS,iBAAA,CACd,KACA,QAAA,EACiB;AACjB,EAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACT,CAAC,EAAA,KACC,KAAA,CAAM,QAAQ,EAAA,CAAG,KAAK,MACrB,EAAA,CAAG,KAAA,CAAM,QAAA,CAAS,KAAK,KAAM,CAAC,CAAC,YAAY,EAAA,CAAG,KAAA,CAAM,SAAS,QAAQ,CAAA;AAAA,GAC1E;AACF;AAEO,IAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,MAAM,YAAsC;AAE1C,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CACpB,GAAA,CAAI,gBAAA,EAAkB,EAAE,OAAA,EAAS,GAAA,EAAM,CAAA,CACvC,IAAA,EAAiC;AACpC,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,OAAO,EAAC;AAAA,EACvC,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,MACJ,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,gBAAA,EAAkB,kBAAA,EAAmB,CAAE,QAAQ,EAAE,KAAA,EAAO,cAAA,EAAe,EAAG,CAAA;AAAA,MACrF,OAAA,EAAS,MAAM,aAAA,CAAc,IAAA,EAAK;AAAA,MAClC,SAAA,EAAW,QAAA;AAAA;AAAA,MAEX,KAAA,EAAO;AAAA,KACR;AAAA;AAEP","file":"chunk-NEPWW7KM.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport { getTwilightContext } from '../twilight/context';\n\n/** A merchant's announcement bar, as `GET advertisements` returns it. */\nexport interface Advertisement {\n id: number;\n title?: string;\n description?: string;\n icon?: string | null;\n url?: string | null;\n target?: string | null;\n colors?: { bg?: string; text?: string };\n /** Page slugs the ad shows on (`salla.config` `page.slug`), or `all`. */\n pages?: string[];\n}\n\n/** The ads a page shows: the rule the API applies to `?page=`, run on the full list. */\nexport function advertisementsFor(\n ads: readonly Advertisement[],\n pageSlug: string | null | undefined\n): Advertisement[] {\n return ads.filter(\n (ad) =>\n Array.isArray(ad.pages) &&\n (ad.pages.includes('all') || (!!pageSlug && ad.pages.includes(pageSlug)))\n );\n}\n\nexport const advertisement = {\n /** Every active ad, unfiltered: one request serves all pages, filtered with `advertisementsFor`. */\n list: async (): Promise<Advertisement[]> => {\n // Short timeout: it is fetched with the store settings on every server render.\n const { data } = await api\n .get('advertisements', { timeout: 3000 })\n .json<{ data?: Advertisement[] }>();\n return Array.isArray(data) ? data : [];\n },\n\n queries: {\n list: () =>\n queryOptions({\n queryKey: ['advertisements', getTwilightContext().locale, { scope: getActiveScope() }],\n queryFn: () => advertisement.list(),\n staleTime: Infinity,\n // Awaited in rootBeforeLoad: a retry would double the 3s budget. `PageAdvertisements` retries.\n retry: 0,\n }),\n },\n};\n"]}
@@ -1,21 +1,21 @@
1
1
  import { lazy } from 'react';
2
2
 
3
3
  // src/components/layout/lazy.ts
4
- var LazyHeader = lazy(() => import('./Header-W6XMMZIA.js').then((m) => ({ default: m.Header })));
5
- var LazyFooter = lazy(() => import('./Footer-SSNPHJ2G.js').then((m) => ({ default: m.Footer })));
4
+ var LazyHeader = lazy(() => import('./Header-QOAV23HD.js').then((m) => ({ default: m.Header })));
5
+ var LazyFooter = lazy(() => import('./Footer-L52M4T24.js').then((m) => ({ default: m.Footer })));
6
6
  var LazyCopyright = lazy(
7
- () => import('./Copyright-TOKRGLFM.js').then((m) => ({ default: m.Copyright }))
7
+ () => import('./Copyright-KBCQVD5Y.js').then((m) => ({ default: m.Copyright }))
8
8
  );
9
9
  var LazyMasterLayout = lazy(
10
- () => import('./MasterLayout-DTLAOTWI.js').then((m) => ({ default: m.MasterLayout }))
10
+ () => import('./MasterLayout-FY666JMR.js').then((m) => ({ default: m.MasterLayout }))
11
11
  );
12
12
  var LazyWidgetHead = lazy(
13
13
  () => import('./WidgetHead-BCRIXIJQ.js').then((m) => ({ default: m.WidgetHead }))
14
14
  );
15
15
  var LazyCustomerLayout = lazy(
16
- () => import('./CustomerLayout-WTD5QAR7.js').then((m) => ({ default: m.CustomerLayout }))
16
+ () => import('./CustomerLayout-B77ZKB4X.js').then((m) => ({ default: m.CustomerLayout }))
17
17
  );
18
18
 
19
19
  export { LazyCopyright, LazyCustomerLayout, LazyFooter, LazyHeader, LazyMasterLayout, LazyWidgetHead };
20
- //# sourceMappingURL=chunk-VCSFCUFT.js.map
21
- //# sourceMappingURL=chunk-VCSFCUFT.js.map
20
+ //# sourceMappingURL=chunk-P36CIH6E.js.map
21
+ //# sourceMappingURL=chunk-P36CIH6E.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/layout/lazy.ts"],"names":[],"mappings":";;;AAMO,IAAM,UAAA,GAAa,IAAA,CAAK,MAAM,OAAO,sBAAU,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,GAAS,CAAC;AAErF,IAAM,UAAA,GAAa,IAAA,CAAK,MAAM,OAAO,sBAAU,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,GAAS,CAAC;AAErF,IAAM,aAAA,GAAgB,IAAA;AAAA,EAAK,MAChC,OAAO,yBAAa,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,SAAA,EAAU,CAAE;AAC9D;AAEO,IAAM,gBAAA,GAAmB,IAAA;AAAA,EAAK,MACnC,OAAO,4BAAgB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,YAAA,EAAa,CAAE;AACpE;AAEO,IAAM,cAAA,GAAiB,IAAA;AAAA,EAAK,MACjC,OAAO,0BAAc,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,UAAA,EAAW,CAAE;AAChE;AAEO,IAAM,kBAAA,GAAqB,IAAA;AAAA,EAAK,MACrC,OAAO,8BAAkB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,cAAA,EAAe,CAAE;AACxE","file":"chunk-VCSFCUFT.js","sourcesContent":["import { lazy } from 'react';\n\n/**\n * Lazy-loaded layout components\n * Use these for code-splitting layout sections\n */\nexport const LazyHeader = lazy(() => import('./Header').then((m) => ({ default: m.Header })));\n\nexport const LazyFooter = lazy(() => import('./Footer').then((m) => ({ default: m.Footer })));\n\nexport const LazyCopyright = lazy(() =>\n import('./Copyright').then((m) => ({ default: m.Copyright }))\n);\n\nexport const LazyMasterLayout = lazy(() =>\n import('./MasterLayout').then((m) => ({ default: m.MasterLayout }))\n);\n\nexport const LazyWidgetHead = lazy(() =>\n import('./WidgetHead').then((m) => ({ default: m.WidgetHead }))\n);\n\nexport const LazyCustomerLayout = lazy(() =>\n import('./CustomerLayout').then((m) => ({ default: m.CustomerLayout }))\n);\n"]}
1
+ {"version":3,"sources":["../src/components/layout/lazy.ts"],"names":[],"mappings":";;;AAMO,IAAM,UAAA,GAAa,IAAA,CAAK,MAAM,OAAO,sBAAU,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,GAAS,CAAC;AAErF,IAAM,UAAA,GAAa,IAAA,CAAK,MAAM,OAAO,sBAAU,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,GAAS,CAAC;AAErF,IAAM,aAAA,GAAgB,IAAA;AAAA,EAAK,MAChC,OAAO,yBAAa,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,SAAA,EAAU,CAAE;AAC9D;AAEO,IAAM,gBAAA,GAAmB,IAAA;AAAA,EAAK,MACnC,OAAO,4BAAgB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,YAAA,EAAa,CAAE;AACpE;AAEO,IAAM,cAAA,GAAiB,IAAA;AAAA,EAAK,MACjC,OAAO,0BAAc,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,UAAA,EAAW,CAAE;AAChE;AAEO,IAAM,kBAAA,GAAqB,IAAA;AAAA,EAAK,MACrC,OAAO,8BAAkB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,cAAA,EAAe,CAAE;AACxE","file":"chunk-P36CIH6E.js","sourcesContent":["import { lazy } from 'react';\n\n/**\n * Lazy-loaded layout components\n * Use these for code-splitting layout sections\n */\nexport const LazyHeader = lazy(() => import('./Header').then((m) => ({ default: m.Header })));\n\nexport const LazyFooter = lazy(() => import('./Footer').then((m) => ({ default: m.Footer })));\n\nexport const LazyCopyright = lazy(() =>\n import('./Copyright').then((m) => ({ default: m.Copyright }))\n);\n\nexport const LazyMasterLayout = lazy(() =>\n import('./MasterLayout').then((m) => ({ default: m.MasterLayout }))\n);\n\nexport const LazyWidgetHead = lazy(() =>\n import('./WidgetHead').then((m) => ({ default: m.WidgetHead }))\n);\n\nexport const LazyCustomerLayout = lazy(() =>\n import('./CustomerLayout').then((m) => ({ default: m.CustomerLayout }))\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-TTTI4W5F.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-PFMTPKZO.js.map
130
+ //# sourceMappingURL=chunk-PFMTPKZO.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":"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","file":"chunk-PFMTPKZO.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,5 +1,5 @@
1
- import { api } from './chunk-YDSWLCOY.js';
2
- import { getTwilightContext } from './chunk-JNAJTCJD.js';
1
+ import { api } from './chunk-TTTI4W5F.js';
2
+ import { getTwilightContext } from './chunk-QRHXAKJ3.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  var menu = {
@@ -23,5 +23,5 @@ var menu = {
23
23
  };
24
24
 
25
25
  export { menu };
26
- //# sourceMappingURL=chunk-L4JI2AAL.js.map
27
- //# sourceMappingURL=chunk-L4JI2AAL.js.map
26
+ //# sourceMappingURL=chunk-QEPZPPLH.js.map
27
+ //# sourceMappingURL=chunk-QEPZPPLH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/menu.ts"],"names":[],"mappings":";;;;AAKO,IAAM,IAAA,GAAO;AAAA,EAClB,QAAQ,YAAiC;AACvC,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,kBAAA,EAAmB;AACtC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAA,CAAE,CAAA,CAAE,IAAA,EAA2B;AACzF,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,QAAQ,YAAiC;AACvC,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,kBAAA,EAAmB;AACtC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAA,CAAE,CAAA,CAAE,IAAA,EAA2B;AACzF,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,MACN,YAAA,CAAa;AAAA,MACX,UAAU,CAAC,OAAA,EAAS,QAAA,EAAU,kBAAA,GAAqB,MAAM,CAAA;AAAA,MACzD,OAAA,EAAS,MAAM,IAAA,CAAK,MAAA,EAAO;AAAA,MAC3B,SAAA,EAAW,IAAI,EAAA,GAAK;AAAA,KACrB;AAAA;AAEP","file":"chunk-L4JI2AAL.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\nimport { getTwilightContext } from '../twilight/context';\nimport type { MenuItem } from '../types';\n\nexport const menu = {\n header: async (): Promise<MenuItem[]> => {\n const { locale } = getTwilightContext();\n const { data } = await api.get(`menus/header?lang=${locale}`).json<{ data: MenuItem[] }>();\n return data || [];\n },\n\n footer: async (): Promise<MenuItem[]> => {\n const { locale } = getTwilightContext();\n const { data } = await api.get(`menus/footer?lang=${locale}`).json<{ data: MenuItem[] }>();\n return data || [];\n },\n\n queries: {\n header: () =>\n queryOptions({\n queryKey: ['menus', 'header', getTwilightContext().locale],\n queryFn: () => menu.header(),\n staleTime: 5 * 60 * 1000,\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/menu.ts"],"names":[],"mappings":";;;;AAKO,IAAM,IAAA,GAAO;AAAA,EAClB,QAAQ,YAAiC;AACvC,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,kBAAA,EAAmB;AACtC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAA,CAAE,CAAA,CAAE,IAAA,EAA2B;AACzF,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,QAAQ,YAAiC;AACvC,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,kBAAA,EAAmB;AACtC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,kBAAA,EAAqB,MAAM,CAAA,CAAE,CAAA,CAAE,IAAA,EAA2B;AACzF,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,MACN,YAAA,CAAa;AAAA,MACX,UAAU,CAAC,OAAA,EAAS,QAAA,EAAU,kBAAA,GAAqB,MAAM,CAAA;AAAA,MACzD,OAAA,EAAS,MAAM,IAAA,CAAK,MAAA,EAAO;AAAA,MAC3B,SAAA,EAAW,IAAI,EAAA,GAAK;AAAA,KACrB;AAAA;AAEP","file":"chunk-QEPZPPLH.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\nimport { getTwilightContext } from '../twilight/context';\nimport type { MenuItem } from '../types';\n\nexport const menu = {\n header: async (): Promise<MenuItem[]> => {\n const { locale } = getTwilightContext();\n const { data } = await api.get(`menus/header?lang=${locale}`).json<{ data: MenuItem[] }>();\n return data || [];\n },\n\n footer: async (): Promise<MenuItem[]> => {\n const { locale } = getTwilightContext();\n const { data } = await api.get(`menus/footer?lang=${locale}`).json<{ data: MenuItem[] }>();\n return data || [];\n },\n\n queries: {\n header: () =>\n queryOptions({\n queryKey: ['menus', 'header', getTwilightContext().locale],\n queryFn: () => menu.header(),\n staleTime: 5 * 60 * 1000,\n }),\n },\n};\n"]}
@@ -47,9 +47,11 @@ function composeMessages(common, overrides, locale) {
47
47
 
48
48
  // src/utils/errors.ts
49
49
  var SettingsError = class extends Error {
50
- constructor(message) {
50
+ constructor(message, details) {
51
51
  super(message ?? "Store settings could not be loaded.");
52
52
  this.name = "SettingsError";
53
+ this.reason = details?.reason;
54
+ this.status = details?.status;
53
55
  }
54
56
  };
55
57
  function createI18nInstance(locale, translations, themeTranslations) {
@@ -306,5 +308,5 @@ function getTwilightContext() {
306
308
  }
307
309
 
308
310
  export { SettingsError, composeMessages, createI18nInstance, getRequestStore, getTwilightContext, hasTwilightSettings, isPlainObject, messagesForLocale, runWithTwilightContext, storeTranslationsQueryKey, subscribeTwilight, translationsQueryKey, updateTwilightContext };
309
- //# sourceMappingURL=chunk-JNAJTCJD.js.map
310
- //# sourceMappingURL=chunk-JNAJTCJD.js.map
311
+ //# sourceMappingURL=chunk-QRHXAKJ3.js.map
312
+ //# sourceMappingURL=chunk-QRHXAKJ3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/translations-key.ts","../src/api/messages.ts","../src/utils/errors.ts","../src/providers/i18n-factory.ts","../src/twilight/context.ts"],"names":[],"mappings":"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","file":"chunk-QRHXAKJ3.js","sourcesContent":["/**\n * @fileoverview The translations query key, on its own, importing nothing.\n *\n * Three places read the cached translations — `rootBeforeLoad`, the hydration\n * path in `tanstack/router.tsx`, and the lazy `i18n` accessor in\n * `twilight/context.ts` — and all three have to agree on the key or the\n * hydrated page misses the entry it was just handed and refetches. One\n * definition is the only way to keep that true.\n *\n * It lives here rather than in `api/translations.ts`, where it would naturally\n * sit, because **`twilight/context.ts` cannot afford that module's imports**.\n * `api/translations` pulls in `api/client`, which pulls in `ky`; `context.ts`\n * is imported directly by tests that mock `ky`, and adding that edge made six\n * of them stop being mocked and start issuing real requests to `api.salla.dev`\n * (`tests/routes/rootBeforeLoad.test.ts`, bisected to exactly this import). A\n * leaf module with no imports of its own cannot do that to anyone.\n */\n\n/**\n * @param locale is part of the key because each file on the CDN holds one\n * language. The global file this replaced carried every language and was\n * sliced after the cache, so a key without the locale was correct then and is\n * a wrong-language bug now: `/ar` → `/en` would reuse the Arabic entry.\n */\nexport function translationsQueryKey(locale: string): [string, string] {\n return ['translations', locale];\n}\n\n/**\n * The merchant's own wording for one store and one language.\n *\n * Separate from {@link translationsQueryKey} rather than folded into it,\n * because the two files have different lifetimes and different audiences: the\n * platform's copy is the same object for every store on the CDN, and this one\n * is a single merchant's overrides. Keeping them apart means a store with no\n * overrides never invalidates, refetches or dehydrates anything on its account.\n *\n * @param storeId is `settings.store.id` — the Optimus-encoded numeric id, which\n * is what names the object. It is safe in a key even though the locale-only key\n * deliberately avoids naming a store: that warning is about a store *resolved\n * from the request*, which differs between server and client. This one is read\n * out of the settings payload, so both sides compute it from the same\n * dehydrated data and agree.\n */\nexport function storeTranslationsQueryKey(\n storeId: string | number,\n locale: string\n): [string, string, string] {\n return ['translations', String(storeId), locale];\n}\n","/**\n * @fileoverview Composing one language's messages out of the query cache.\n *\n * **There are three places that build an i18n instance**, and they have to\n * agree on more than the key: `rootBeforeLoad`, the hydration path in\n * `tanstack/router.tsx`, and the lazy `i18n` accessor in `twilight/context.ts`.\n * When the platform's copy was the only source, agreeing on\n * `translationsQueryKey` was enough. It is not any more — a merchant's own\n * wording is a second cache entry, and a reader that knows about one and not\n * the other renders different text from the page beside it.\n *\n * That is exactly what shipped in #366: the server rendered the merchant's\n * words and hydration replaced them with the platform's, because only\n * `rootBeforeLoad` had been taught to merge. Greptile caught it. This module is\n * the single answer to \"what are the messages for this locale\", so the next\n * source cannot be added to one reader and forgotten in two.\n *\n * It lives beside `translations-key.ts` and imports nothing at runtime for the\n * same reason that file does: `twilight/context.ts` cannot afford\n * `api/translations`, which pulls in `api/client` and therefore `ky`, and tests\n * that mock `ky` stop being mocked the moment that edge exists.\n */\nimport type { QueryClient } from '@tanstack/react-query';\nimport { translationsQueryKey } from './translations-key';\nimport type { TranslationMessages } from '../providers/I18nProvider';\n\nexport type Messages = Record<string, unknown>;\n\nexport function isPlainObject(value: unknown): value is Messages {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * `overrides` laid over `base`, one leaf at a time.\n *\n * Recursive rather than a spread, because both files are nested by group\n * (`common.errors.500`) and a top-level spread would make a merchant who\n * overrode one string inside `common` lose every other string in it. The\n * merchant's value wins at the leaf, and a group they never touched is left\n * exactly as the platform sent it.\n *\n * A type conflict — one side an object where the other is a string — resolves\n * to the merchant's value. It is the more specific of the two and there is no\n * sensible way to merge a string into a group; the alternative, keeping the\n * platform's, would mean a merchant's edit silently doing nothing.\n */\nexport function mergeMessages(base: Messages, overrides: Messages): Messages {\n const merged: Messages = { ...base };\n\n for (const [key, value] of Object.entries(overrides)) {\n const existing = merged[key];\n merged[key] =\n isPlainObject(existing) && isPlainObject(value) ? mergeMessages(existing, value) : value;\n }\n\n return merged;\n}\n\n/**\n * This store's overrides for `locale`, if any were fetched into the cache.\n *\n * Found by **shape** rather than by asking the settings for a store id, and\n * that is deliberate: the two readers that were missing the merge have a\n * `queryClient` and a locale between them and nothing else, and reaching for\n * `api/store` from `twilight/context.ts` would drag `ky` in through the back\n * door. One document serves one store — a request naming a different one is\n * redirected with `reloadDocument` — so at most one such entry per locale\n * exists, and matching `['translations', <anything>, <locale>]` cannot pick up\n * somebody else's.\n */\nfunction cachedOverrides(queryClient: QueryClient, locale: string): Messages | undefined {\n const entries = queryClient.getQueriesData<Messages>({ queryKey: ['translations'] });\n\n for (const [key, data] of entries) {\n if (key.length === 3 && key[2] === locale && isPlainObject(data)) {\n return data;\n }\n }\n\n return undefined;\n}\n\n/**\n * The messages for `locale`: the platform's copy with this merchant's over it.\n *\n * Reads only — whoever wants the merchant's file in the cache has to have put\n * it there, which `rootBeforeLoad` does and only when the settings say there is\n * one. A reader that runs without it simply gets the platform's copy, which is\n * the same thing it got before any of this existed.\n */\nexport function messagesForLocale(\n queryClient: QueryClient | undefined,\n locale: string\n): TranslationMessages | undefined {\n const common = queryClient?.getQueryData<TranslationMessages>(translationsQueryKey(locale));\n const overrides = queryClient ? cachedOverrides(queryClient, locale) : undefined;\n\n return composeMessages(common, overrides, locale);\n}\n\n/**\n * The same composition from values rather than from the cache.\n *\n * `rootBeforeLoad` has both in hand already — it just awaited them — so it\n * composes directly instead of reading back what it put in.\n */\nexport function composeMessages(\n common: TranslationMessages | null | undefined,\n overrides: Messages | null | undefined,\n locale: string\n): TranslationMessages | undefined {\n if (!overrides || Object.keys(overrides).length === 0) return common ?? undefined;\n\n const base = common?.[`${locale}.trans`];\n\n return {\n [`${locale}.trans`]: mergeMessages(isPlainObject(base) ? base : {}, overrides) as Record<\n string,\n string\n >,\n };\n}\n","/**\n * Why a store's settings did not load:\n * - `no-store`: nothing named a store for this request;\n * - `timeout`: the Salla API did not answer in time;\n * - `http`: it answered with an error status;\n * - `network`: no answer arrived at all;\n * - `empty`: it answered without settings.\n */\nexport type SettingsErrorReason = 'no-store' | 'timeout' | 'http' | 'network' | 'empty';\n\nexport interface SettingsErrorDetails {\n reason?: SettingsErrorReason;\n /** The API's status, when `reason` is `'http'`. */\n status?: number;\n}\n\nexport class SettingsError extends Error {\n /** Absent when nothing said why, e.g. `getTwilightContext().settings` read before they loaded. */\n readonly reason?: SettingsErrorReason;\n readonly status?: number;\n\n constructor(message?: string, details?: SettingsErrorDetails) {\n super(message ?? 'Store settings could not be loaded.');\n this.name = 'SettingsError';\n this.reason = details?.reason;\n this.status = details?.status;\n }\n}\n","import { createInstance, type i18n as I18nInstance } from 'i18next';\nimport { initReactI18next } from 'react-i18next';\n\nexport type TranslationMessages = Record<string, Record<string, string>>;\n\n/**\n * Creates a new i18next instance for the given locale.\n *\n * @param locale - Active locale code, e.g. `'ar'`\n * @param translations - App translations from the Salla API (store-specific)\n * @param themeTranslations - Bundled theme translations (static defaults)\n */\nexport function createI18nInstance(\n locale: string,\n translations?: TranslationMessages,\n themeTranslations?: TranslationMessages\n): I18nInstance {\n const instance = createInstance();\n const transKey = `${locale}.trans`;\n\n instance.use(initReactI18next).init({\n lng: locale,\n fallbackLng: locale,\n ns: ['app', 'theme'],\n defaultNS: 'app',\n fallbackNS: 'theme',\n resources: {\n [locale]: {\n app: translations?.[transKey] ?? {},\n theme: themeTranslations?.[transKey] ?? {},\n },\n },\n interpolation: { escapeValue: false },\n react: { useSuspense: false },\n keySeparator: '.',\n nsSeparator: false,\n });\n\n return instance;\n}\n\n/**\n * Creates i18n instance for testing\n * @param locale - Locale code (default: 'ar')\n * @param translations - Optional translations\n */\nexport function createTestI18n(locale = 'ar', translations?: TranslationMessages): I18nInstance {\n return createI18nInstance(locale, translations);\n}\n","import type { QueryClient } from '@tanstack/react-query';\nimport type { i18n } from 'i18next';\nimport type { StoreContext } from '../api/store';\nimport type { AppSnippet, AppSettings } from '../api/apps';\nimport { FALLBACK_LOCALE, getLanguageInfo } from '../providers/locale-constants';\nimport { createI18nInstance } from '../providers/i18n-factory';\nimport { messagesForLocale } from '../api/messages';\nimport { SettingsError } from '../utils/errors';\nimport type { ActiveScope } from '../utils/cookies';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TwilightLocation<TSearch = Record<string, unknown>> {\n href: string;\n pathname: string;\n search: TSearch;\n searchStr: string;\n state: Record<string, unknown>;\n hash: string;\n}\n\nexport interface PageContext {\n slug: string;\n id?: string | number;\n title: string;\n url?: string;\n parent?: { id: string | number; name: string; url: string } | null;\n breadcrumbs?: { name: string; url: string }[];\n}\n\nexport interface TwilightContext {\n queryClient: QueryClient;\n settings: StoreContext;\n locale: string;\n routeId: string;\n location: TwilightLocation;\n authToken: string | null;\n /**\n * The selected market and, once bullet delivery confirmed one, its branch\n * allocation — the full object the SDK sends as `s-scope-*` headers. Seeded from\n * the `scope` cookie on the server; see {@link ActiveScope}.\n */\n scope: ActiveScope | null;\n /** `scope.id`, kept for callers that only need the market. */\n scopeId: string | null;\n /**\n * Which store this request is for, when something other than the hostname says\n * so — the `?storeId=` a preview was opened with, or the cookie remembering it.\n *\n * Null on a live storefront, where the hostname is the answer and there is\n * nothing to carry. See {@link resolveRequestStoreId}.\n */\n storeId: string | null;\n /**\n * Which store the first segment of this request's path named, on a host where\n * the store is the root of every URL: `mtgr-alaatr-2` for\n * `https://preview.salla.design/mtgr-alaatr-2/cart`.\n *\n * Null whenever something else named the store, and on every merchant domain.\n * See {@link resolveRequestStoreBase}.\n */\n storeBase: string | null;\n /**\n * Where {@link storeBase} sits in this request's paths: behind the locale on a\n * Salla shared host (`/ar/dev-x/cart`, named by the dispatcher), in front of it\n * everywhere else. See {@link resolveAddressedStore}.\n */\n storeBaseFollowsLocale: boolean;\n /**\n * Which version of the theme's settings this request asked for — the\n * `?versionId=` an editor preview or a local dev session was opened with, or\n * the cookie remembering it.\n *\n * Null on an ordinary storefront visit, which is the common case: nothing\n * named a version, so the store's live one is what the API answers with. See\n * {@link resolveRequestVersionId}.\n */\n versionId: string | null;\n /**\n * The host this request arrived on, captured server-side.\n *\n * A theme worker is deployed with no vars and no bindings, so the request is\n * the only thing that knows which storefront it is serving. On the client this\n * is `window.location.host`; on the server nothing else has it.\n */\n requestHost: string | null;\n /** The native app's `s-app-*` headers when the request came from its webview; see {@link readNativeAppHeaders}. */\n nativeAppHeaders: Record<string, string> | null;\n i18n: i18n;\n dir: 'ltr' | 'rtl';\n page?: PageContext;\n /** Installed apps' snippets, fetched in rootBeforeLoad so AppsSnippets can render CDN\n * <script> tags during SSR (React Query isn't dehydrated here, so useQuery has no SSR data). */\n appsSnippets?: AppSnippet[];\n /** Per-app public `app.*` buckets, fetched in rootBeforeLoad so rootHead can install the\n * `Salla.appScope` factory inline at parse time — ahead of the snippets' onReady callbacks. */\n appsSettings?: AppSettings;\n /**\n * This visitor sees the maintenance page, not the store. Decided in rootBeforeLoad\n * from `settings.maintenance` and the merchant's owner view; see `utils/maintenance`.\n */\n maintenance: boolean;\n extras?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Internal Store\n// ============================================================================\n\nconst DEFAULT_LOCATION: TwilightLocation = {\n href: '',\n pathname: '',\n search: {},\n searchStr: '',\n state: {},\n hash: '',\n};\n\ninterface ContextData {\n queryClient: QueryClient;\n settings: StoreContext | null;\n locale: string;\n routeId: string;\n location: TwilightLocation;\n authToken: string | null;\n scope: ActiveScope | null;\n storeId: string | null;\n storeBase: string | null;\n storeBaseFollowsLocale: boolean;\n versionId: string | null;\n requestHost: string | null;\n nativeAppHeaders: Record<string, string> | null;\n i18n?: i18n;\n page?: PageContext;\n appsSnippets?: AppSnippet[];\n appsSettings?: AppSettings;\n maintenance: boolean;\n extras?: Record<string, unknown>;\n}\n\nconst DEFAULT_DATA: ContextData = {\n queryClient: null as unknown as QueryClient,\n settings: null,\n locale: FALLBACK_LOCALE,\n routeId: '',\n location: { ...DEFAULT_LOCATION },\n authToken: null,\n scope: null,\n storeId: null,\n storeBase: null,\n storeBaseFollowsLocale: false,\n versionId: null,\n requestHost: null,\n nativeAppHeaders: null,\n i18n: undefined,\n page: undefined,\n maintenance: false,\n};\n\n// ============================================================================\n// Storage: AsyncLocalStorage (server) or module-level store (client)\n// ============================================================================\n\ntype AsyncLocalStore<T> = { getStore(): T | undefined; run(val: T, fn: () => unknown): unknown };\n\n// Initialize ALS at module load time for SSR — no race condition\ntype AsyncHooks = { AsyncLocalStorage: new <T>() => AsyncLocalStore<T> };\n\n// workerd has no global `require`, so a bundled `require()` throws there; it does have\n// `process.getBuiltinModule` (so does Node >= 20.16), which keeps this out of the browser bundle.\nfunction loadAsyncHooks(): AsyncHooks | null {\n const proc = (globalThis as { process?: { getBuiltinModule?: (id: string) => unknown } }).process;\n try {\n const builtin = proc?.getBuiltinModule?.('node:async_hooks') as AsyncHooks | undefined;\n if (builtin?.AsyncLocalStorage) return builtin;\n } catch {\n /* fall through to require */\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require('node:async_hooks') as AsyncHooks;\n } catch {\n return null;\n }\n}\n\nconst isServer = typeof window === 'undefined';\n// One instance per isolate, so a re-evaluated or duplicated copy of this module (dev\n// reloads, src next to dist) reads the scope the request middleware opened.\nconst ALS_KEY = Symbol.for('salla.twilight.context.als');\nlet _als: AsyncLocalStore<ContextData> | null = null;\nif (isServer) {\n const registry = globalThis as { [ALS_KEY]?: AsyncLocalStore<ContextData> };\n const hooks = registry[ALS_KEY] ? null : loadAsyncHooks();\n if (hooks) registry[ALS_KEY] = new hooks.AsyncLocalStorage<ContextData>();\n _als = registry[ALS_KEY] ?? null;\n}\n\n// Without request isolation every request would share `clientStore`: one visitor's\n// auth token and store settings rendered into another's page.\nfunction assertRequestIsolation(): void {\n if (isServer && !_als) {\n throw new Error(\n '[Twilight] AsyncLocalStorage is unavailable; refusing to share request state.'\n );\n }\n}\n\n// The browser's store, shared by every copy of this module on the page like the ALS above,\n// so a loader in one copy reads the location and token the router wrote through another.\nconst CLIENT_KEY = Symbol.for('salla.twilight.context.client');\nconst clientRegistry = globalThis as {\n [CLIENT_KEY]?: { store: ContextData; listeners: Set<() => void> };\n};\nconst clientShared = (clientRegistry[CLIENT_KEY] ??= {\n store: { ...DEFAULT_DATA },\n listeners: new Set<() => void>(),\n});\nconst clientStore: ContextData = clientShared.store;\n\nfunction getTwilightStore(): ContextData {\n assertRequestIsolation();\n if (_als) {\n const store = _als.getStore();\n if (!store)\n throw new Error('[Twilight] No request context. Wrap with runWithTwilightContext().');\n return store;\n }\n return clientStore;\n}\n\nfunction writableStore(): ContextData {\n if (_als) {\n const store = _als.getStore();\n if (store) return store;\n }\n return clientStore;\n}\n\nfunction mergeIntoStore(store: ContextData, partial: Partial<TwilightContext>): void {\n if ('queryClient' in partial && partial.queryClient) store.queryClient = partial.queryClient;\n if ('settings' in partial && partial.settings != null) store.settings = partial.settings;\n if ('locale' in partial && partial.locale != null) store.locale = partial.locale;\n if ('routeId' in partial && partial.routeId != null) store.routeId = partial.routeId;\n if ('location' in partial && partial.location != null)\n store.location = { ...store.location, ...partial.location };\n if ('authToken' in partial && partial.authToken !== undefined)\n store.authToken = partial.authToken ?? null;\n if ('scope' in partial && partial.scope !== undefined) store.scope = partial.scope ?? null;\n else if ('scopeId' in partial && partial.scopeId !== undefined)\n store.scope = partial.scopeId == null ? null : { id: partial.scopeId };\n if ('storeId' in partial && partial.storeId !== undefined)\n store.storeId = partial.storeId ?? null;\n if ('storeBase' in partial && partial.storeBase !== undefined)\n store.storeBase = partial.storeBase ?? null;\n if ('storeBaseFollowsLocale' in partial && partial.storeBaseFollowsLocale !== undefined)\n store.storeBaseFollowsLocale = partial.storeBaseFollowsLocale === true;\n if ('versionId' in partial && partial.versionId !== undefined)\n store.versionId = partial.versionId ?? null;\n if ('requestHost' in partial && partial.requestHost !== undefined)\n store.requestHost = partial.requestHost ?? null;\n if ('nativeAppHeaders' in partial && partial.nativeAppHeaders !== undefined)\n store.nativeAppHeaders = partial.nativeAppHeaders ?? null;\n if ('i18n' in partial && partial.i18n != null) store.i18n = partial.i18n;\n if ('page' in partial) store.page = partial.page;\n if ('appsSnippets' in partial) store.appsSnippets = partial.appsSnippets;\n if ('appsSettings' in partial) store.appsSettings = partial.appsSettings;\n if ('maintenance' in partial) store.maintenance = partial.maintenance === true;\n if ('extras' in partial) store.extras = partial.extras;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport function runWithTwilightContext<T>(partial: Partial<TwilightContext>, fn: () => T): T {\n assertRequestIsolation();\n if (_als) {\n const data: ContextData = { ...DEFAULT_DATA };\n mergeIntoStore(data, partial);\n return _als.run(data, fn) as T;\n }\n mergeIntoStore(clientStore, partial);\n return fn();\n}\n\n// Client-only subscription so React consumers (useRouteId/useIsHome/…) re-render\n// when navigation mutates the module store. Mirrors hooks/useWishlist.ts.\nconst listeners = clientShared.listeners;\n\nexport function subscribeTwilight(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function updateTwilightContext(partial: Partial<TwilightContext>): void {\n mergeIntoStore(getTwilightStore(), partial);\n // Server uses AsyncLocalStorage and has no React subscribers; notify on client only.\n if (typeof window !== 'undefined') {\n for (const listener of listeners) listener();\n }\n}\n\n/**\n * Whether store settings are available, without throwing.\n *\n * `getTwilightContext().settings` throws a `SettingsError` when the store is\n * empty, which is fatal inside a head function during hydration. Callers that\n * need to *test* availability must use this instead of a try/catch around the\n * getter. Returns false when there is no request context at all (server-side\n * calls outside `runWithTwilightContext`).\n */\nexport function hasTwilightSettings(): boolean {\n try {\n return getTwilightStore().settings != null;\n } catch {\n return false;\n }\n}\n\n/** What a request addressed, as opposed to what it is. */\nexport interface RequestAddressing {\n storeId: string | null;\n storeBase: string | null;\n storeBaseFollowsLocale: boolean;\n versionId: string | null;\n requestHost: string | null;\n}\n\n/**\n * What this request named and the host it arrived on, without throwing.\n *\n * Separate from {@link getTwilightContext} because store identity is read while\n * deciding *what to fetch* — before there is a context worth having — and on the\n * server outside a request the getter throws. A caller asking \"which store?\" has\n * a sane answer for \"none named\"; it has none for an exception.\n *\n * The version rides along rather than getting an accessor of its own: it is read\n * at the same moment, for the same reason, and by the same callers, and a second\n * copy of this try/catch would be a second thing to remember to widen.\n */\nexport function getRequestStore(): RequestAddressing {\n try {\n const data = getTwilightStore();\n return {\n storeId: data.storeId,\n storeBase: data.storeBase,\n storeBaseFollowsLocale: data.storeBaseFollowsLocale,\n versionId: data.versionId,\n requestHost: data.requestHost,\n };\n } catch {\n return {\n storeId: null,\n storeBase: null,\n storeBaseFollowsLocale: false,\n versionId: null,\n requestHost: null,\n };\n }\n}\n\nexport function getTwilightContext(): TwilightContext {\n const data = getTwilightStore();\n return {\n get queryClient() {\n return data.queryClient;\n },\n get settings() {\n if (!data.settings) throw new SettingsError();\n return data.settings;\n },\n get locale() {\n return data.locale;\n },\n get routeId() {\n return data.routeId;\n },\n get location() {\n return data.location;\n },\n get authToken() {\n return data.authToken;\n },\n get scope() {\n return data.scope;\n },\n get scopeId() {\n return data.scope?.id ?? null;\n },\n get storeId() {\n return data.storeId;\n },\n get storeBase() {\n return data.storeBase;\n },\n get storeBaseFollowsLocale() {\n return data.storeBaseFollowsLocale;\n },\n get versionId() {\n return data.versionId;\n },\n get requestHost() {\n return data.requestHost;\n },\n get nativeAppHeaders() {\n return data.nativeAppHeaders;\n },\n get i18n() {\n if (!data.i18n) {\n // Composed the same way as `rootBeforeLoad` and the hydration path —\n // the platform's copy with this merchant's over it. See\n // `api/messages.ts`: this accessor reading one entry while the others\n // read two is precisely the drift that module exists to stop.\n data.i18n = createI18nInstance(\n data.locale,\n messagesForLocale(data.queryClient, data.locale)\n );\n }\n return data.i18n;\n },\n get dir() {\n return getLanguageInfo(data.locale).dir;\n },\n get page() {\n return data.page;\n },\n get appsSnippets() {\n return data.appsSnippets;\n },\n get appsSettings() {\n return data.appsSettings;\n },\n get maintenance() {\n return data.maintenance;\n },\n get extras() {\n return data.extras;\n },\n };\n}\n\n/** @internal Reset store for testing */\nexport function resetForTesting(): void {\n Object.assign(writableStore(), { ...DEFAULT_DATA });\n}\n"]}
@@ -4,7 +4,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  export { BlogSkeleton, BreadcrumbSkeleton, CustomerLayoutSkeleton, CustomerPageSkeleton, PageSkeleton, ProductCardSkeleton, ProductDetailSkeleton, ProductGridSkeleton, SkeletonPulse } from '@salla.sa/twilight-components-react';
5
5
 
6
6
  var LazyBreadcrumb = lazy(
7
- () => import('./Breadcrumb-ACO63JUO.js').then((m) => ({ default: m.Breadcrumb }))
7
+ () => import('./Breadcrumb-XT2MP2ZW.js').then((m) => ({ default: m.Breadcrumb }))
8
8
  );
9
9
  var LazyNoContent = lazy(
10
10
  () => import('./NoContent-63TMCPGY.js').then((m) => ({ default: m.NoContent }))
@@ -153,5 +153,5 @@ function DeferredData({ promise, fallback, children }) {
153
153
  }
154
154
 
155
155
  export { DeferredData, Image, LazyBreadcrumb, LazyCurrencySymbol, LazyErrorPage, LazyNoContent, LazyRenderWhenVisible, resolveDeferred };
156
- //# sourceMappingURL=chunk-L26XGP65.js.map
157
- //# sourceMappingURL=chunk-L26XGP65.js.map
156
+ //# sourceMappingURL=chunk-QZM4ZACO.js.map
157
+ //# sourceMappingURL=chunk-QZM4ZACO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/common/lazy.ts","../src/components/common/Image.tsx","../src/components/common/DeferredData.tsx"],"names":["Image","memo","DeferredRenderer","jsx"],"mappings":";;;;;AASO,IAAM,cAAA,GAAiB,IAAA;AAAA,EAAK,MACjC,OAAO,0BAAc,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,UAAA,EAAW,CAAE;AAChE;AAEO,IAAM,aAAA,GAAgB,IAAA;AAAA,EAAK,MAChC,OAAO,yBAAa,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,SAAA,EAAU,CAAE;AAC9D;AAEO,IAAM,qBAAA,GAAwB,IAAA;AAAA,EAAK,MACxC,OAAO,iCAAqB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,iBAAA,EAAkB,CAAE;AAC9E;AAEO,IAAM,kBAAA,GAAqB,IAAA;AAAA,EAAK,MACrC,OAAO,8BAAkB,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,cAAA,EAAe,CAAE;AACxE;AAEO,IAAM,aAAA,GAAgB,IAAA;AAAA,EAAK,MAChC,OAAO,yBAAa,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,MAAO,EAAE,OAAA,EAAS,CAAA,CAAE,SAAA,EAAU,CAAE;AAC9D;ACSO,IAAM,KAAA,GAAQ,IAAA,CAAK,SAASA,MAAAA,CAAM;AAAA,EACvC,GAAA;AAAA,EACA,GAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,WAAA;AAAA,EACA,SAAA,GAAY,OAAA;AAAA,EACZ,SAAA;AAAA,EACA,gBAAA,GAAmB,GAAA;AAAA,EACnB,SAAA,GAAY,KAAA;AAAA,EACZ,SAAA,GAAY,EAAA;AAAA,EACZ,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAe;AACb,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAEjB,EAAA,MAAM,kBACJ,UAAA,KAAe,YAAA,EAAc,SAAS,iBAAA,CAAkB,GAAA,EAAK,YAAY,CAAA,GAAI,MAAA,CAAA;AAC/E,EAAA,MAAM,wBACJ,YAAA,EAAc,MAAA,IAAU,YAAY,iBAAA,CAAkB,SAAA,EAAW,YAAY,CAAA,GAAI,MAAA;AACnF,EAAA,MAAM,WAAW,YAAA,EAAc,MAAA,GAC3B,KAAA,IAAS,IAAA,IAAQ,aAAa,QAAA,CAAS,MAAA,CAAO,KAAK,CAAC,IAClD,MAAA,CAAO,KAAK,CAAA,GACZ,YAAA,CAAa,CAAC,CAAA,GAChB,KAAA;AAEJ,EAAA,MAAM,UAAA,GAAa,kBAAkB,EAAE,KAAA,EAAO,UAAS,GAAI,EAAE,KAAA,EAAO,QAAA,EAAU,MAAA,EAAO;AAErF,EAAA,MAAM,YAAA,GAAe,cAAA,CAAe,GAAA,EAAK,UAAU,CAAA;AACnD,EAAA,MAAM,kBAAA,GAAqB,cAAA,CAAe,SAAA,EAAW,UAAU,CAAA;AAE/D,EAAA,MAAM,cAAA,GAAiB,UAAU,SAAS,CAAA,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,CAAC,SAAA,EAAW,cAAc,EAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAEvE,EAAA,MAAM,YAAA,GAA0D,QAAA,GAC5D,EAAE,OAAA,EAAS,SAAkB,aAAA,EAAe,MAAA,EAAiB,QAAA,EAAU,MAAA,EAAgB,GACvF,EAAE,OAAA,EAAS,MAAA,EAAiB,UAAU,OAAA,EAAiB;AAE3D,EAAA,MAAM,UAAA,GAAa,CAAC,SAAA,IAAa,CAAC,CAAC,WAAA;AAEnC,EAAA,MAAM,GAAA,mBACJ,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,YAAA;AAAA,MACL,GAAA;AAAA,MACA,SAAA,EAAW,UAAA;AAAA,MACX,KAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA,EAAQ,eAAA;AAAA,MAER,KAAA,EAAO,aAAa,MAAA,GAAY,KAAA;AAAA,MAC/B,GAAG,YAAA;AAAA,MACH,GAAG;AAAA;AAAA,GACN;AAGF,EAAA,MAAM,UAAA,GAAa,kBAAA,mBACjB,IAAA,CAAC,SAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,eAAe,gBAAgB,CAAA,GAAA,CAAA;AAAA,QACtC,QAAQ,qBAAA,IAAyB,kBAAA;AAAA,QACjC,KAAA,EAAO,wBAAwB,KAAA,GAAQ;AAAA;AAAA,KACzC;AAAA,IACC;AAAA,GAAA,EACH,CAAA,GAEA,GAAA;AAGF,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0BAAA,EAA2B,KAAA,EAAO,EAAE,WAAA,EAAa,GAAG,KAAA,EAAM,EACtE,QAAA,EAAA,UAAA,EACH,CAAA;AAEJ,CAAC;AC9GD,IAAM,YAAA,mBAAe,MAAA,CAAO,GAAA,CAAI,mBAAmB,CAAA;AAYnD,IAAM,eAAe,OAAO,OAAA,KAAY,WAAA,mBAAc,IAAI,SAAQ,GAAI,IAAA;AAEtE,SAAS,MAAS,OAAA,EAAyC;AACzD,EAAA,MAAM,QAAA,GAAY,QAA+B,YAAY,CAAA;AAC7D,EAAA,IAAI,UAAU,OAAO,OAAA;AAErB,EAAA,MAAM,KAAA,GAA0B,EAAE,MAAA,EAAQ,SAAA,EAAU;AAEpD,EAAA,MAAM,QAAA,GAAW,OAAA;AACjB,EAAA,QAAA,CAAS,YAAY,CAAA,GAAI,KAAA;AAEzB,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAC,KAAA,KAAU;AACT,MAAA,KAAA,CAAM,MAAA,GAAS,SAAA;AACf,MAAA,KAAA,CAAM,KAAA,GAAQ,KAAA;AAAA,IAChB,CAAA;AAAA,IACA,CAAC,KAAA,KAAU;AACT,MAAA,KAAA,CAAM,MAAA,GAAS,OAAA;AACf,MAAA,KAAA,CAAM,KAAA,GAAQ,KAAA;AAAA,IAChB;AAAA,GACF;AAEA,EAAA,OAAO,QAAA;AACT;AAEA,IAAM,gBAAA,GAAmBC,IAAAA,CAAK,SAASC,iBAAAA,CAAoB;AAAA,EACzD,OAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,KAAA,GAAQ,QAAQ,YAAY,CAAA;AAElC,EAAA,IAAI,KAAA,EAAO,WAAW,SAAA,EAAW;AAC/B,IAAA,OAAO,QAAA,CAAS,MAAM,KAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,IAAI,KAAA,EAAO,WAAW,OAAA,EAAS;AAC7B,IAAA,MAAM,KAAA,CAAM,KAAA;AAAA,EACd;AAEA,EAAA,MAAM,IAAA,GAAO,IAAI,OAAO,CAAA;AACxB,EAAA,OAAO,SAAS,IAAI,CAAA;AACtB,CAAC,CAAA;AAED,SAAS,gBAAA,CAAoB;AAAA,EAC3B,OAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,KAAA,GAAQ,QAAQ,YAAY,CAAA;AAClC,EAAA,IAAI,KAAA,EAAO,WAAW,SAAA,EAAW;AAC/B,IAAA,OAAO,QAAA,CAAS,MAAM,KAAM,CAAA;AAAA,EAC9B;AACA,EAAA,uBAAOC,GAAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,QAAA,EAAS,CAAA;AACrB;AAEO,SAAS,gBACd,cAAA,EAC4B;AAC5B,EAAA,IAAI,cAAA,IAAkB,IAAA,IAAQ,EAAE,cAAA,YAA0B,UAAU,OAAO,cAAA;AAC3E,EAAA,MAAM,QAAA,GAAW,MAAM,cAAc,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQ,SAAS,YAAY,CAAA;AACnC,EAAA,IAAI,KAAA,EAAO,MAAA,KAAW,SAAA,EAAW,OAAO,KAAA,CAAM,KAAA;AAC9C,EAAA,OAAO,cAAA;AACT;AAEO,SAAS,YAAA,CAAgB,EAAE,OAAA,EAAS,QAAA,EAAU,UAAS,EAAyB;AACrF,EAAA,IAAI,EAAE,mBAAmB,OAAA,CAAA,EAAU;AACjC,IAAA,OAAO,SAAS,OAAO,CAAA;AAAA,EACzB;AAEA,EAAA,IAAI,YAAA,IAAgB,OAAA,YAAmB,OAAA,EAAS,YAAA,CAAa,IAAI,OAAO,CAAA;AAExE,EAAA,MAAM,QAAA,GAAW,MAAM,OAAO,CAAA;AAC9B,EAAA,MAAM,KAAA,GAAQ,SAAS,YAAY,CAAA;AAEnC,EAAA,IAAI,KAAA,EAAO,WAAW,SAAA,EAAW;AAC/B,IAAA,OAAO,QAAA,CAAS,MAAM,KAAM,CAAA;AAAA,EAC9B;AAEA,EAAA,IAAI,KAAA,EAAO,WAAW,OAAA,EAAS;AAC7B,IAAA,MAAM,KAAA,CAAM,KAAA;AAAA,EACd;AAEA,EAAA,uBACEA,GAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,0BACEA,GAAAA,CAAC,oBAAiB,OAAA,EAAS,QAAA,EAAU,UAClC,QAAA,EACH,CAAA;AAAA,MAGF,QAAA,kBAAAA,GAAAA,CAAC,gBAAA,EAAA,EAAiB,OAAA,EAAS,UAAW,QAAA,EAAS;AAAA;AAAA,GACjD;AAEJ","file":"chunk-L26XGP65.js","sourcesContent":["import { lazy } from 'react';\n\n/**\n * Lazy-loaded common components\n * Use these for code-splitting non-critical components\n *\n * NOTE: Skeleton components are sourced from @salla.sa/twilight-components-react\n * because they must render instantly during route transitions.\n */\nexport const LazyBreadcrumb = lazy(() =>\n import('./Breadcrumb').then((m) => ({ default: m.Breadcrumb }))\n);\n\nexport const LazyNoContent = lazy(() =>\n import('./NoContent').then((m) => ({ default: m.NoContent }))\n);\n\nexport const LazyRenderWhenVisible = lazy(() =>\n import('./RenderWhenVisible').then((m) => ({ default: m.RenderWhenVisible }))\n);\n\nexport const LazyCurrencySymbol = lazy(() =>\n import('./CurrencySymbol').then((m) => ({ default: m.CurrencySymbol }))\n);\n\nexport const LazyErrorPage = lazy(() =>\n import('./ErrorPage').then((m) => ({ default: m.ErrorPage }))\n);\n","import { memo } from 'react';\nimport { getCdnImageSrcSet, getCdnImageUrl } from '../../utils/cdn-image';\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL */\n src?: string;\n /** Alt text for accessibility */\n alt: string;\n /** Whether this image is above the fold / LCP candidate */\n priority?: boolean;\n /** Aspect ratio for CLS prevention (e.g. \"16/9\", \"1/1\", \"4/3\") */\n aspectRatio?: string;\n /** Object fit mode */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';\n /** Mobile image source for <picture> element */\n mobileSrc?: string;\n /** Mobile breakpoint for <source> media query (default: 768px) */\n mobileBreakpoint?: number;\n /** Skip the wrapper div */\n noWrapper?: boolean;\n /**\n * CDN widths for a density `srcset`. Pass `sizes` so the browser picks a\n * candidate close to the displayed CSS size.\n */\n srcSetWidths?: readonly number[];\n}\n\n/**\n * Optimized Image component with native browser lazy loading.\n *\n * - Uses `loading=\"lazy\"` + `decoding=\"async\"` by default for below-the-fold images.\n * - Uses `loading=\"eager\"` + `fetchPriority=\"high\"` for priority (above-the-fold / LCP) images.\n * - Supports responsive `<picture>` with mobile source.\n * - Provides `aspectRatio` for CLS prevention.\n * - When `srcSetWidths` + `sizes` are set, emits a sized CDN `srcset`.\n */\nexport const Image = memo(function Image({\n src,\n alt,\n priority = false,\n aspectRatio,\n objectFit = 'cover',\n mobileSrc,\n mobileBreakpoint = 768,\n noWrapper = false,\n className = '',\n style,\n width,\n height,\n sizes,\n srcSet: srcSetProp,\n srcSetWidths,\n ...rest\n}: ImageProps) {\n if (!src) return null;\n\n const generatedSrcSet =\n srcSetProp || (srcSetWidths?.length ? getCdnImageSrcSet(src, srcSetWidths) : undefined);\n const generatedMobileSrcSet =\n srcSetWidths?.length && mobileSrc ? getCdnImageSrcSet(mobileSrc, srcSetWidths) : undefined;\n const cdnWidth = srcSetWidths?.length\n ? width != null && srcSetWidths.includes(Number(width))\n ? Number(width)\n : srcSetWidths[0]\n : width;\n // Width-only CDN URLs so `src` matches a srcset candidate for preload.\n const cdnOptions = generatedSrcSet ? { width: cdnWidth } : { width: cdnWidth, height };\n\n const optimizedSrc = getCdnImageUrl(src, cdnOptions);\n const optimizedMobileSrc = getCdnImageUrl(mobileSrc, cdnOptions);\n\n const objectFitClass = `object-${objectFit}`;\n const imgClasses = [className, objectFitClass].filter(Boolean).join(' ');\n\n const loadingProps: React.ImgHTMLAttributes<HTMLImageElement> = priority\n ? { loading: 'eager' as const, fetchPriority: 'high' as const, decoding: 'sync' as const }\n : { loading: 'lazy' as const, decoding: 'async' as const };\n\n const hasWrapper = !noWrapper && !!aspectRatio;\n\n const img = (\n <img\n src={optimizedSrc}\n alt={alt}\n className={imgClasses}\n width={width}\n height={height}\n sizes={sizes}\n srcSet={generatedSrcSet}\n // With a wrapper, `style` goes to the wrapper; otherwise it must land on the <img>.\n style={hasWrapper ? undefined : style}\n {...loadingProps}\n {...rest}\n />\n );\n\n const imgElement = optimizedMobileSrc ? (\n <picture>\n <source\n media={`(max-width: ${mobileBreakpoint}px)`}\n srcSet={generatedMobileSrcSet || optimizedMobileSrc}\n sizes={generatedMobileSrcSet ? sizes : undefined}\n />\n {img}\n </picture>\n ) : (\n img\n );\n\n if (!hasWrapper) {\n return imgElement;\n }\n\n return (\n <div className=\"relative overflow-hidden\" style={{ aspectRatio, ...style }}>\n {imgElement}\n </div>\n );\n});\n","import { Suspense, memo, use, type ReactNode } from 'react';\n\nexport interface DeferredDataProps<T> {\n promise: Promise<T> | T;\n fallback: ReactNode;\n children: (data: T) => ReactNode;\n}\n\nconst DEFERRED_KEY = Symbol.for('twilight.deferred');\n\ninterface DeferredState<T> {\n status: 'pending' | 'success' | 'error';\n value?: T;\n error?: unknown;\n}\n\nexport interface DeferredPromise<T> extends Promise<T> {\n [DEFERRED_KEY]?: DeferredState<T>;\n}\n\nconst seenPromises = typeof WeakSet !== 'undefined' ? new WeakSet() : null;\n\nfunction defer<T>(promise: Promise<T>): DeferredPromise<T> {\n const existing = (promise as DeferredPromise<T>)[DEFERRED_KEY];\n if (existing) return promise as DeferredPromise<T>;\n\n const state: DeferredState<T> = { status: 'pending' };\n\n const deferred = promise as DeferredPromise<T>;\n deferred[DEFERRED_KEY] = state;\n\n promise.then(\n (value) => {\n state.status = 'success';\n state.value = value;\n },\n (error) => {\n state.status = 'error';\n state.error = error;\n }\n );\n\n return deferred;\n}\n\nconst DeferredRenderer = memo(function DeferredRenderer<T>({\n promise,\n children,\n}: {\n promise: DeferredPromise<T>;\n children: (data: T) => ReactNode;\n}) {\n const state = promise[DEFERRED_KEY];\n\n if (state?.status === 'success') {\n return children(state.value!);\n }\n\n if (state?.status === 'error') {\n throw state.error;\n }\n\n const data = use(promise);\n return children(data);\n}) as <T>(props: { promise: DeferredPromise<T>; children: (data: T) => ReactNode }) => ReactNode;\n\nfunction DeferredFallback<T>({\n promise,\n fallback,\n children,\n}: {\n promise: DeferredPromise<T>;\n fallback: ReactNode;\n children: (data: T) => ReactNode;\n}) {\n const state = promise[DEFERRED_KEY];\n if (state?.status === 'success') {\n return children(state.value!);\n }\n return <>{fallback}</>;\n}\n\nexport function resolveDeferred<T>(\n promiseOrValue: Promise<T> | T | undefined\n): T | Promise<T> | undefined {\n if (promiseOrValue == null || !(promiseOrValue instanceof Promise)) return promiseOrValue;\n const deferred = defer(promiseOrValue);\n const state = deferred[DEFERRED_KEY];\n if (state?.status === 'success') return state.value as T;\n return promiseOrValue;\n}\n\nexport function DeferredData<T>({ promise, fallback, children }: DeferredDataProps<T>) {\n if (!(promise instanceof Promise)) {\n return children(promise);\n }\n\n if (seenPromises && promise instanceof Promise) seenPromises.add(promise);\n\n const deferred = defer(promise);\n const state = deferred[DEFERRED_KEY];\n\n if (state?.status === 'success') {\n return children(state.value!);\n }\n\n if (state?.status === 'error') {\n throw state.error;\n }\n\n return (\n <Suspense\n fallback={\n <DeferredFallback promise={deferred} fallback={fallback}>\n {children}\n </DeferredFallback>\n }\n >\n <DeferredRenderer promise={deferred}>{children}</DeferredRenderer>\n </Suspense>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/common/lazy.ts","../src/components/common/Image.tsx","../src/components/common/DeferredData.tsx"],"names":["Image","memo","DeferredRenderer","jsx"],"mappings":"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","file":"chunk-QZM4ZACO.js","sourcesContent":["import { lazy } from 'react';\n\n/**\n * Lazy-loaded common components\n * Use these for code-splitting non-critical components\n *\n * NOTE: Skeleton components are sourced from @salla.sa/twilight-components-react\n * because they must render instantly during route transitions.\n */\nexport const LazyBreadcrumb = lazy(() =>\n import('./Breadcrumb').then((m) => ({ default: m.Breadcrumb }))\n);\n\nexport const LazyNoContent = lazy(() =>\n import('./NoContent').then((m) => ({ default: m.NoContent }))\n);\n\nexport const LazyRenderWhenVisible = lazy(() =>\n import('./RenderWhenVisible').then((m) => ({ default: m.RenderWhenVisible }))\n);\n\nexport const LazyCurrencySymbol = lazy(() =>\n import('./CurrencySymbol').then((m) => ({ default: m.CurrencySymbol }))\n);\n\nexport const LazyErrorPage = lazy(() =>\n import('./ErrorPage').then((m) => ({ default: m.ErrorPage }))\n);\n","import { memo } from 'react';\nimport { getCdnImageSrcSet, getCdnImageUrl } from '../../utils/cdn-image';\n\nexport interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n /** Image source URL */\n src?: string;\n /** Alt text for accessibility */\n alt: string;\n /** Whether this image is above the fold / LCP candidate */\n priority?: boolean;\n /** Aspect ratio for CLS prevention (e.g. \"16/9\", \"1/1\", \"4/3\") */\n aspectRatio?: string;\n /** Object fit mode */\n objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';\n /** Mobile image source for <picture> element */\n mobileSrc?: string;\n /** Mobile breakpoint for <source> media query (default: 768px) */\n mobileBreakpoint?: number;\n /** Skip the wrapper div */\n noWrapper?: boolean;\n /**\n * CDN widths for a density `srcset`. Pass `sizes` so the browser picks a\n * candidate close to the displayed CSS size.\n */\n srcSetWidths?: readonly number[];\n}\n\n/**\n * Optimized Image component with native browser lazy loading.\n *\n * - Uses `loading=\"lazy\"` + `decoding=\"async\"` by default for below-the-fold images.\n * - Uses `loading=\"eager\"` + `fetchPriority=\"high\"` for priority (above-the-fold / LCP) images.\n * - Supports responsive `<picture>` with mobile source.\n * - Provides `aspectRatio` for CLS prevention.\n * - When `srcSetWidths` + `sizes` are set, emits a sized CDN `srcset`.\n */\nexport const Image = memo(function Image({\n src,\n alt,\n priority = false,\n aspectRatio,\n objectFit = 'cover',\n mobileSrc,\n mobileBreakpoint = 768,\n noWrapper = false,\n className = '',\n style,\n width,\n height,\n sizes,\n srcSet: srcSetProp,\n srcSetWidths,\n ...rest\n}: ImageProps) {\n if (!src) return null;\n\n const generatedSrcSet =\n srcSetProp || (srcSetWidths?.length ? getCdnImageSrcSet(src, srcSetWidths) : undefined);\n const generatedMobileSrcSet =\n srcSetWidths?.length && mobileSrc ? getCdnImageSrcSet(mobileSrc, srcSetWidths) : undefined;\n const cdnWidth = srcSetWidths?.length\n ? width != null && srcSetWidths.includes(Number(width))\n ? Number(width)\n : srcSetWidths[0]\n : width;\n // Width-only CDN URLs so `src` matches a srcset candidate for preload.\n const cdnOptions = generatedSrcSet ? { width: cdnWidth } : { width: cdnWidth, height };\n\n const optimizedSrc = getCdnImageUrl(src, cdnOptions);\n const optimizedMobileSrc = getCdnImageUrl(mobileSrc, cdnOptions);\n\n const objectFitClass = `object-${objectFit}`;\n const imgClasses = [className, objectFitClass].filter(Boolean).join(' ');\n\n const loadingProps: React.ImgHTMLAttributes<HTMLImageElement> = priority\n ? { loading: 'eager' as const, fetchPriority: 'high' as const, decoding: 'sync' as const }\n : { loading: 'lazy' as const, decoding: 'async' as const };\n\n const hasWrapper = !noWrapper && !!aspectRatio;\n\n const img = (\n <img\n src={optimizedSrc}\n alt={alt}\n className={imgClasses}\n width={width}\n height={height}\n sizes={sizes}\n srcSet={generatedSrcSet}\n // With a wrapper, `style` goes to the wrapper; otherwise it must land on the <img>.\n style={hasWrapper ? undefined : style}\n {...loadingProps}\n {...rest}\n />\n );\n\n const imgElement = optimizedMobileSrc ? (\n <picture>\n <source\n media={`(max-width: ${mobileBreakpoint}px)`}\n srcSet={generatedMobileSrcSet || optimizedMobileSrc}\n sizes={generatedMobileSrcSet ? sizes : undefined}\n />\n {img}\n </picture>\n ) : (\n img\n );\n\n if (!hasWrapper) {\n return imgElement;\n }\n\n return (\n <div className=\"relative overflow-hidden\" style={{ aspectRatio, ...style }}>\n {imgElement}\n </div>\n );\n});\n","import { Suspense, memo, use, type ReactNode } from 'react';\n\nexport interface DeferredDataProps<T> {\n promise: Promise<T> | T;\n fallback: ReactNode;\n children: (data: T) => ReactNode;\n}\n\nconst DEFERRED_KEY = Symbol.for('twilight.deferred');\n\ninterface DeferredState<T> {\n status: 'pending' | 'success' | 'error';\n value?: T;\n error?: unknown;\n}\n\nexport interface DeferredPromise<T> extends Promise<T> {\n [DEFERRED_KEY]?: DeferredState<T>;\n}\n\nconst seenPromises = typeof WeakSet !== 'undefined' ? new WeakSet() : null;\n\nfunction defer<T>(promise: Promise<T>): DeferredPromise<T> {\n const existing = (promise as DeferredPromise<T>)[DEFERRED_KEY];\n if (existing) return promise as DeferredPromise<T>;\n\n const state: DeferredState<T> = { status: 'pending' };\n\n const deferred = promise as DeferredPromise<T>;\n deferred[DEFERRED_KEY] = state;\n\n promise.then(\n (value) => {\n state.status = 'success';\n state.value = value;\n },\n (error) => {\n state.status = 'error';\n state.error = error;\n }\n );\n\n return deferred;\n}\n\nconst DeferredRenderer = memo(function DeferredRenderer<T>({\n promise,\n children,\n}: {\n promise: DeferredPromise<T>;\n children: (data: T) => ReactNode;\n}) {\n const state = promise[DEFERRED_KEY];\n\n if (state?.status === 'success') {\n return children(state.value!);\n }\n\n if (state?.status === 'error') {\n throw state.error;\n }\n\n const data = use(promise);\n return children(data);\n}) as <T>(props: { promise: DeferredPromise<T>; children: (data: T) => ReactNode }) => ReactNode;\n\nfunction DeferredFallback<T>({\n promise,\n fallback,\n children,\n}: {\n promise: DeferredPromise<T>;\n fallback: ReactNode;\n children: (data: T) => ReactNode;\n}) {\n const state = promise[DEFERRED_KEY];\n if (state?.status === 'success') {\n return children(state.value!);\n }\n return <>{fallback}</>;\n}\n\nexport function resolveDeferred<T>(\n promiseOrValue: Promise<T> | T | undefined\n): T | Promise<T> | undefined {\n if (promiseOrValue == null || !(promiseOrValue instanceof Promise)) return promiseOrValue;\n const deferred = defer(promiseOrValue);\n const state = deferred[DEFERRED_KEY];\n if (state?.status === 'success') return state.value as T;\n return promiseOrValue;\n}\n\nexport function DeferredData<T>({ promise, fallback, children }: DeferredDataProps<T>) {\n if (!(promise instanceof Promise)) {\n return children(promise);\n }\n\n if (seenPromises && promise instanceof Promise) seenPromises.add(promise);\n\n const deferred = defer(promise);\n const state = deferred[DEFERRED_KEY];\n\n if (state?.status === 'success') {\n return children(state.value!);\n }\n\n if (state?.status === 'error') {\n throw state.error;\n }\n\n return (\n <Suspense\n fallback={\n <DeferredFallback promise={deferred} fallback={fallback}>\n {children}\n </DeferredFallback>\n }\n >\n <DeferredRenderer promise={deferred}>{children}</DeferredRenderer>\n </Suspense>\n );\n}\n"]}