@salla.sa/twilight-theme-engine 1.0.68 → 1.0.70

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-TX36PDIE.js → AddToCartForm-RVJDH34Q.js} +3 -3
  2. package/dist/{AddToCartForm-TX36PDIE.js.map → AddToCartForm-RVJDH34Q.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-AT6YYDG4.js → BlogAuthorPage-HRUKRVXC.js} +21 -21
  4. package/dist/{BlogAuthorPage-AT6YYDG4.js.map → BlogAuthorPage-HRUKRVXC.js.map} +1 -1
  5. package/dist/{BlogCategoryPage-ELPLV67S.js → BlogCategoryPage-X2BB6FPW.js} +21 -21
  6. package/dist/{BlogCategoryPage-ELPLV67S.js.map → BlogCategoryPage-X2BB6FPW.js.map} +1 -1
  7. package/dist/{BlogPage-RO3U4OTI.js → BlogPage-LMN2BBLX.js} +19 -19
  8. package/dist/{BlogPage-RO3U4OTI.js.map → BlogPage-LMN2BBLX.js.map} +1 -1
  9. package/dist/{BlogSinglePage-HSRVLJYE.js → BlogSinglePage-D46SPQTX.js} +19 -19
  10. package/dist/{BlogSinglePage-HSRVLJYE.js.map → BlogSinglePage-D46SPQTX.js.map} +1 -1
  11. package/dist/{BlogTagPage-KLCLNP2Q.js → BlogTagPage-WEJAPD5G.js} +21 -21
  12. package/dist/{BlogTagPage-KLCLNP2Q.js.map → BlogTagPage-WEJAPD5G.js.map} +1 -1
  13. package/dist/{BrandsPage-C2TTKTMV.js → BrandsPage-4M2DWNN3.js} +20 -20
  14. package/dist/{BrandsPage-C2TTKTMV.js.map → BrandsPage-4M2DWNN3.js.map} +1 -1
  15. package/dist/{Breadcrumb-MLWGLXJZ.js → Breadcrumb-74NZ4CAI.js} +19 -19
  16. package/dist/{Breadcrumb-MLWGLXJZ.js.map → Breadcrumb-74NZ4CAI.js.map} +1 -1
  17. package/dist/{CartItem-5JKJ3AD6.js → CartItem-AIGCVTNA.js} +19 -19
  18. package/dist/{CartItem-5JKJ3AD6.js.map → CartItem-AIGCVTNA.js.map} +1 -1
  19. package/dist/{CartSummary-ZNBVWC2P.js → CartSummary-ONAQNID6.js} +19 -19
  20. package/dist/{CartSummary-ZNBVWC2P.js.map → CartSummary-ONAQNID6.js.map} +1 -1
  21. package/dist/{Copyright-LBUY2AJJ.js → Copyright-M3Y6AW2X.js} +4 -4
  22. package/dist/{Copyright-LBUY2AJJ.js.map → Copyright-M3Y6AW2X.js.map} +1 -1
  23. package/dist/{CustomerLayout-YDJQYMQI.js → CustomerLayout-HXVLROR7.js} +19 -19
  24. package/dist/{CustomerLayout-YDJQYMQI.js.map → CustomerLayout-HXVLROR7.js.map} +1 -1
  25. package/dist/{Footer-X46MKKA5.js → Footer-VJXKRENW.js} +19 -19
  26. package/dist/{Footer-X46MKKA5.js.map → Footer-VJXKRENW.js.map} +1 -1
  27. package/dist/{Header-YK5QFAO7.js → Header-2BEJOO3R.js} +8 -8
  28. package/dist/{Header-YK5QFAO7.js.map → Header-2BEJOO3R.js.map} +1 -1
  29. package/dist/{LoyaltyPage-RM3WQLVC.js → LoyaltyPage-IGSNMPPU.js} +19 -19
  30. package/dist/{LoyaltyPage-RM3WQLVC.js.map → LoyaltyPage-IGSNMPPU.js.map} +1 -1
  31. package/dist/{LoyaltyPointsPage-AN7VC3AF.js → LoyaltyPointsPage-Z3GWZVHU.js} +3 -3
  32. package/dist/{LoyaltyPointsPage-AN7VC3AF.js.map → LoyaltyPointsPage-Z3GWZVHU.js.map} +1 -1
  33. package/dist/{MainMenu-ETIJZLKV.js → MainMenu-BUG3VS7Y.js} +9 -10
  34. package/dist/MainMenu-BUG3VS7Y.js.map +1 -0
  35. package/dist/{MasterLayout-QSYGLVJD.js → MasterLayout-XOMOFH26.js} +19 -19
  36. package/dist/{MasterLayout-QSYGLVJD.js.map → MasterLayout-XOMOFH26.js.map} +1 -1
  37. package/dist/{MobileMenu-V624P4XH.js → MobileMenu-U5Y43SK2.js} +20 -20
  38. package/dist/{MobileMenu-V624P4XH.js.map → MobileMenu-U5Y43SK2.js.map} +1 -1
  39. package/dist/{NotificationsPage-MAN7PINP.js → NotificationsPage-WOW7R5EL.js} +19 -19
  40. package/dist/{NotificationsPage-MAN7PINP.js.map → NotificationsPage-WOW7R5EL.js.map} +1 -1
  41. package/dist/{OrderSinglePage-43FJCEPN.js → OrderSinglePage-SFZEAMAG.js} +20 -20
  42. package/dist/{OrderSinglePage-43FJCEPN.js.map → OrderSinglePage-SFZEAMAG.js.map} +1 -1
  43. package/dist/{OrdersPage-TW3VH6EN.js → OrdersPage-2KWKJZAM.js} +19 -19
  44. package/dist/{OrdersPage-TW3VH6EN.js.map → OrdersPage-2KWKJZAM.js.map} +1 -1
  45. package/dist/{PageSingle-AX7M6XH3.js → PageSingle-D4UTD6XX.js} +8 -9
  46. package/dist/PageSingle-D4UTD6XX.js.map +1 -0
  47. package/dist/{ProductDetails-4ABLVN5Z.js → ProductDetails-53UVIHR3.js} +4 -4
  48. package/dist/{ProductDetails-4ABLVN5Z.js.map → ProductDetails-53UVIHR3.js.map} +1 -1
  49. package/dist/{ProfilePage-ACF2CGYH.js → ProfilePage-WZQJBMP3.js} +19 -19
  50. package/dist/{ProfilePage-ACF2CGYH.js.map → ProfilePage-WZQJBMP3.js.map} +1 -1
  51. package/dist/{SeoCartWidget-AFJRAXWF.js → SeoCartWidget-EZD6YRUG.js} +19 -19
  52. package/dist/{SeoCartWidget-AFJRAXWF.js.map → SeoCartWidget-EZD6YRUG.js.map} +1 -1
  53. package/dist/{SettingsPage-FYFH4QLC.js → SettingsPage-4GTH7FJS.js} +19 -19
  54. package/dist/{SettingsPage-FYFH4QLC.js.map → SettingsPage-4GTH7FJS.js.map} +1 -1
  55. package/dist/{StoreClosedNotification-PPQFOIW3.js → StoreClosedNotification-SUKGXBTP.js} +20 -20
  56. package/dist/{StoreClosedNotification-PPQFOIW3.js.map → StoreClosedNotification-SUKGXBTP.js.map} +1 -1
  57. package/dist/{TestimonialsPage-Q5UIOYG6.js → TestimonialsPage-YKXSTNWR.js} +8 -9
  58. package/dist/TestimonialsPage-YKXSTNWR.js.map +1 -0
  59. package/dist/{ThankYouPage-FKM3DCWO.js → ThankYouPage-CMMQ3JFO.js} +19 -19
  60. package/dist/{ThankYouPage-FKM3DCWO.js.map → ThankYouPage-CMMQ3JFO.js.map} +1 -1
  61. package/dist/{WalletPage-WI7DXCGJ.js → WalletPage-LK6XXNHY.js} +20 -20
  62. package/dist/{WalletPage-WI7DXCGJ.js.map → WalletPage-LK6XXNHY.js.map} +1 -1
  63. package/dist/{WishlistPage-G5Z2W5QD.js → WishlistPage-FAEXGOAH.js} +21 -21
  64. package/dist/{WishlistPage-G5Z2W5QD.js.map → WishlistPage-FAEXGOAH.js.map} +1 -1
  65. package/dist/api/apps.js +4 -5
  66. package/dist/api/brands.js +5 -6
  67. package/dist/api/cart.js +5 -6
  68. package/dist/api/category.js +5 -6
  69. package/dist/api/client.d.ts.map +1 -1
  70. package/dist/api/client.js +3 -4
  71. package/dist/api/home.d.ts +9 -3
  72. package/dist/api/home.d.ts.map +1 -1
  73. package/dist/api/home.js +4 -5
  74. package/dist/api/loyalty.js +5 -6
  75. package/dist/api/menu.js +4 -5
  76. package/dist/api/notification.js +4 -5
  77. package/dist/api/order.js +5 -6
  78. package/dist/api/page.js +5 -6
  79. package/dist/api/product.js +5 -6
  80. package/dist/api/profile.js +3 -4
  81. package/dist/api/profile.js.map +1 -1
  82. package/dist/api/store.d.ts +6 -0
  83. package/dist/api/store.d.ts.map +1 -1
  84. package/dist/api/store.js +4 -5
  85. package/dist/api/translations.js +4 -5
  86. package/dist/api/user.js +4 -5
  87. package/dist/api/wishlist.js +6 -7
  88. package/dist/chunk-3IHFA2X5.js +33 -0
  89. package/dist/chunk-3IHFA2X5.js.map +1 -0
  90. package/dist/{chunk-NTIGQYSN.js → chunk-4YHSQSM6.js} +8 -7
  91. package/dist/chunk-4YHSQSM6.js.map +1 -0
  92. package/dist/{chunk-B2OHRXRD.js → chunk-5H4NIOTY.js} +4 -4
  93. package/dist/{chunk-B2OHRXRD.js.map → chunk-5H4NIOTY.js.map} +1 -1
  94. package/dist/{chunk-TY3XJOIQ.js → chunk-5HOD4BKK.js} +5 -4
  95. package/dist/chunk-5HOD4BKK.js.map +1 -0
  96. package/dist/{chunk-OFRV3WKR.js → chunk-5ZTYXQ7T.js} +5 -5
  97. package/dist/{chunk-OFRV3WKR.js.map → chunk-5ZTYXQ7T.js.map} +1 -1
  98. package/dist/{chunk-ITHU2R5C.js → chunk-6YIAULAP.js} +9 -8
  99. package/dist/chunk-6YIAULAP.js.map +1 -0
  100. package/dist/{chunk-L2DRHH4E.js → chunk-7BGEGHAI.js} +3 -3
  101. package/dist/{chunk-L2DRHH4E.js.map → chunk-7BGEGHAI.js.map} +1 -1
  102. package/dist/{chunk-DISOIXUL.js → chunk-7N52RMEY.js} +43 -18
  103. package/dist/chunk-7N52RMEY.js.map +1 -0
  104. package/dist/{chunk-Y7NC2NDA.js → chunk-7PYHB3PP.js} +4 -4
  105. package/dist/{chunk-Y7NC2NDA.js.map → chunk-7PYHB3PP.js.map} +1 -1
  106. package/dist/{chunk-I4XPOEQY.js → chunk-7W7SLN5M.js} +4 -4
  107. package/dist/{chunk-I4XPOEQY.js.map → chunk-7W7SLN5M.js.map} +1 -1
  108. package/dist/{chunk-ETPOZJHG.js → chunk-A32NANNC.js} +3 -3
  109. package/dist/{chunk-ETPOZJHG.js.map → chunk-A32NANNC.js.map} +1 -1
  110. package/dist/chunk-AMEU3DNR.js +14 -0
  111. package/dist/{chunk-EI52BZFN.js.map → chunk-AMEU3DNR.js.map} +1 -1
  112. package/dist/{chunk-CTLTXDHH.js → chunk-BAOBHXU5.js} +6 -6
  113. package/dist/{chunk-CTLTXDHH.js.map → chunk-BAOBHXU5.js.map} +1 -1
  114. package/dist/{chunk-ELS6I3O2.js → chunk-BMVQEOBM.js} +4 -4
  115. package/dist/{chunk-ELS6I3O2.js.map → chunk-BMVQEOBM.js.map} +1 -1
  116. package/dist/{chunk-E43ALK3R.js → chunk-DIVEHHMD.js} +3 -3
  117. package/dist/{chunk-E43ALK3R.js.map → chunk-DIVEHHMD.js.map} +1 -1
  118. package/dist/{chunk-G2VNDZID.js → chunk-DY5WGKDX.js} +4 -4
  119. package/dist/{chunk-G2VNDZID.js.map → chunk-DY5WGKDX.js.map} +1 -1
  120. package/dist/{chunk-XCYIGCUN.js → chunk-E7PYHBCX.js} +4 -4
  121. package/dist/{chunk-XCYIGCUN.js.map → chunk-E7PYHBCX.js.map} +1 -1
  122. package/dist/{chunk-KCCU3S5F.js → chunk-EJK33TNK.js} +13 -13
  123. package/dist/chunk-EJK33TNK.js.map +1 -0
  124. package/dist/{chunk-DZT26OCM.js → chunk-FGROIU3Y.js} +3 -3
  125. package/dist/{chunk-DZT26OCM.js.map → chunk-FGROIU3Y.js.map} +1 -1
  126. package/dist/{chunk-XBW7EHBA.js → chunk-GTG22RZG.js} +3 -3
  127. package/dist/{chunk-XBW7EHBA.js.map → chunk-GTG22RZG.js.map} +1 -1
  128. package/dist/{chunk-K6SNUM3L.js → chunk-H2DXJCJP.js} +4 -4
  129. package/dist/{chunk-K6SNUM3L.js.map → chunk-H2DXJCJP.js.map} +1 -1
  130. package/dist/{chunk-2XGQSJKH.js → chunk-HBTIZWT2.js} +3 -3
  131. package/dist/{chunk-2XGQSJKH.js.map → chunk-HBTIZWT2.js.map} +1 -1
  132. package/dist/{chunk-J2YKHDMH.js → chunk-I26VPNDP.js} +3 -3
  133. package/dist/{chunk-J2YKHDMH.js.map → chunk-I26VPNDP.js.map} +1 -1
  134. package/dist/chunk-J427UFSZ.js +186 -0
  135. package/dist/chunk-J427UFSZ.js.map +1 -0
  136. package/dist/{chunk-SR4OTLTJ.js → chunk-LPQFTXBB.js} +9 -3
  137. package/dist/chunk-LPQFTXBB.js.map +1 -0
  138. package/dist/{chunk-SVPXQCOA.js → chunk-MISI3T6V.js} +4 -3
  139. package/dist/chunk-MISI3T6V.js.map +1 -0
  140. package/dist/{chunk-TRZAQSHU.js → chunk-MSUGP566.js} +4 -4
  141. package/dist/{chunk-TRZAQSHU.js.map → chunk-MSUGP566.js.map} +1 -1
  142. package/dist/{chunk-VAMIJGCU.js → chunk-N3BSUMD7.js} +3 -3
  143. package/dist/{chunk-VAMIJGCU.js.map → chunk-N3BSUMD7.js.map} +1 -1
  144. package/dist/{chunk-4YQQVUXS.js → chunk-NFE2H5JE.js} +5 -5
  145. package/dist/{chunk-4YQQVUXS.js.map → chunk-NFE2H5JE.js.map} +1 -1
  146. package/dist/{chunk-H7BCB2HO.js → chunk-OGVUFMLX.js} +3 -3
  147. package/dist/{chunk-H7BCB2HO.js.map → chunk-OGVUFMLX.js.map} +1 -1
  148. package/dist/{chunk-2IYOHSQN.js → chunk-P6EOXGUE.js} +4 -4
  149. package/dist/{chunk-2IYOHSQN.js.map → chunk-P6EOXGUE.js.map} +1 -1
  150. package/dist/{chunk-EBFYRFMI.js → chunk-PPU6MI3G.js} +7 -7
  151. package/dist/{chunk-EBFYRFMI.js.map → chunk-PPU6MI3G.js.map} +1 -1
  152. package/dist/{chunk-TYLKNVQA.js → chunk-QVJDYSCT.js} +89 -4
  153. package/dist/chunk-QVJDYSCT.js.map +1 -0
  154. package/dist/{chunk-4YWBXQV5.js → chunk-R5MZV6KW.js} +4 -4
  155. package/dist/{chunk-4YWBXQV5.js.map → chunk-R5MZV6KW.js.map} +1 -1
  156. package/dist/{chunk-SSPAMQRV.js → chunk-SDIQHTDG.js} +4 -4
  157. package/dist/{chunk-SSPAMQRV.js.map → chunk-SDIQHTDG.js.map} +1 -1
  158. package/dist/{chunk-E2XHLK5O.js → chunk-USN5NHJ5.js} +3 -3
  159. package/dist/{chunk-E2XHLK5O.js.map → chunk-USN5NHJ5.js.map} +1 -1
  160. package/dist/{chunk-FBOSUTNC.js → chunk-UZUHDKKD.js} +4 -4
  161. package/dist/{chunk-FBOSUTNC.js.map → chunk-UZUHDKKD.js.map} +1 -1
  162. package/dist/{chunk-J5DXKBVJ.js → chunk-VLONFUZM.js} +7 -7
  163. package/dist/{chunk-J5DXKBVJ.js.map → chunk-VLONFUZM.js.map} +1 -1
  164. package/dist/{chunk-AH6KEBKX.js → chunk-VVAV3DJL.js} +6 -6
  165. package/dist/{chunk-AH6KEBKX.js.map → chunk-VVAV3DJL.js.map} +1 -1
  166. package/dist/{chunk-IKUDCH7Q.js → chunk-VX2T7JCB.js} +10 -9
  167. package/dist/chunk-VX2T7JCB.js.map +1 -0
  168. package/dist/{chunk-NCTG4ZTU.js → chunk-VYJDRAWX.js} +3 -3
  169. package/dist/{chunk-NCTG4ZTU.js.map → chunk-VYJDRAWX.js.map} +1 -1
  170. package/dist/components/cart/index.js +1 -1
  171. package/dist/components/common/index.js +1 -1
  172. package/dist/components/drawer/index.js +17 -17
  173. package/dist/components/home/index.js +21 -21
  174. package/dist/components/layout/index.js +1 -1
  175. package/dist/components/product/ProductGallery.d.ts.map +1 -1
  176. package/dist/components/product/index.js +18 -18
  177. package/dist/components/store/index.js +19 -19
  178. package/dist/components/toast/Toaster.d.ts.map +1 -1
  179. package/dist/components/toast/index.js +6 -1
  180. package/dist/components/toast/index.js.map +1 -1
  181. package/dist/components/tracking/index.js +1 -1
  182. package/dist/document-class-APAX4M7D.js +25 -0
  183. package/dist/{document-class-P33S4CA7.js.map → document-class-APAX4M7D.js.map} +1 -1
  184. package/dist/hooks/index.js +17 -17
  185. package/dist/hooks/useBlogLike.js +1 -1
  186. package/dist/hooks/useComments.js +3 -4
  187. package/dist/hooks/useGtm.js +17 -17
  188. package/dist/hooks/useMoney.js +17 -17
  189. package/dist/hooks/useProduct.js +3 -4
  190. package/dist/hooks/useStore.js +17 -17
  191. package/dist/hooks/useUser.js +5 -6
  192. package/dist/index.js +17 -17
  193. package/dist/native-app/index.d.ts +27 -0
  194. package/dist/native-app/index.d.ts.map +1 -0
  195. package/dist/native-app/index.js +8 -0
  196. package/dist/native-app/index.js.map +1 -0
  197. package/dist/{navigation-F2TD5X2P.js → navigation-P3GZOWUU.js} +8 -7
  198. package/dist/{navigation-F2TD5X2P.js.map → navigation-P3GZOWUU.js.map} +1 -1
  199. package/dist/{navigation-CJHPA74M.js → navigation-TA3I3XEC.js} +5 -5
  200. package/dist/{navigation-CJHPA74M.js.map → navigation-TA3I3XEC.js.map} +1 -1
  201. package/dist/{not-found-4R764WCJ.js → not-found-G4N25RWR.js} +20 -20
  202. package/dist/{not-found-4R764WCJ.js.map → not-found-G4N25RWR.js.map} +1 -1
  203. package/dist/providers/TwilightProvider.d.ts.map +1 -1
  204. package/dist/providers/index.js +17 -17
  205. package/dist/providers/native-safe-area.d.ts +13 -0
  206. package/dist/providers/native-safe-area.d.ts.map +1 -0
  207. package/dist/routes/account/orders.js +6 -7
  208. package/dist/routes/account.js +15 -16
  209. package/dist/routes/account.js.map +1 -1
  210. package/dist/routes/blog.js +10 -11
  211. package/dist/routes/blog.js.map +1 -1
  212. package/dist/routes/brands.js +6 -7
  213. package/dist/routes/brands.js.map +1 -1
  214. package/dist/routes/cart.js +25 -25
  215. package/dist/routes/home.js +22 -22
  216. package/dist/routes/index.js +4 -4
  217. package/dist/routes/loyalty.js +7 -8
  218. package/dist/routes/loyalty.js.map +1 -1
  219. package/dist/routes/page.js +6 -7
  220. package/dist/routes/page.js.map +1 -1
  221. package/dist/routes/product-listing.js +23 -23
  222. package/dist/routes/product.js +21 -21
  223. package/dist/routes/root/beforeLoad.d.ts.map +1 -1
  224. package/dist/routes/seo-redirects.js +3 -3
  225. package/dist/routes/testimonials.js +1 -1
  226. package/dist/routes/thank-you.js +6 -7
  227. package/dist/routes/thank-you.js.map +1 -1
  228. package/dist/skeleton.js +22 -22
  229. package/dist/tanstack/native-app-events.d.ts +18 -0
  230. package/dist/tanstack/native-app-events.d.ts.map +1 -0
  231. package/dist/tanstack/navigation.d.ts.map +1 -1
  232. package/dist/tanstack.js +17 -17
  233. package/dist/types/salla-sdk.d.ts +8 -0
  234. package/dist/types/salla-sdk.d.ts.map +1 -1
  235. package/dist/utils/index.js +4 -5
  236. package/dist/utils/index.js.map +1 -1
  237. package/dist/utils/sdk-helpers.d.ts +13 -0
  238. package/dist/utils/sdk-helpers.d.ts.map +1 -1
  239. package/dist/utils/store-base.d.ts +9 -0
  240. package/dist/utils/store-base.d.ts.map +1 -1
  241. package/dist/utils/theme-version.d.ts +14 -1
  242. package/dist/utils/theme-version.d.ts.map +1 -1
  243. package/dist/vite/index.js +1 -0
  244. package/dist/vite/index.js.map +1 -1
  245. package/dist/vite/plugins/package-aliases.plugin.d.ts.map +1 -1
  246. package/package.json +5 -1
  247. package/dist/MainMenu-ETIJZLKV.js.map +0 -1
  248. package/dist/PageSingle-AX7M6XH3.js.map +0 -1
  249. package/dist/TestimonialsPage-Q5UIOYG6.js.map +0 -1
  250. package/dist/chunk-5Y64476S.js +0 -80
  251. package/dist/chunk-5Y64476S.js.map +0 -1
  252. package/dist/chunk-DISOIXUL.js.map +0 -1
  253. package/dist/chunk-EI52BZFN.js +0 -14
  254. package/dist/chunk-GNH3W6T4.js +0 -114
  255. package/dist/chunk-GNH3W6T4.js.map +0 -1
  256. package/dist/chunk-IKUDCH7Q.js.map +0 -1
  257. package/dist/chunk-ITHU2R5C.js.map +0 -1
  258. package/dist/chunk-KCCU3S5F.js.map +0 -1
  259. package/dist/chunk-NTIGQYSN.js.map +0 -1
  260. package/dist/chunk-SR4OTLTJ.js.map +0 -1
  261. package/dist/chunk-SVPXQCOA.js.map +0 -1
  262. package/dist/chunk-TY3XJOIQ.js.map +0 -1
  263. package/dist/chunk-TYLKNVQA.js.map +0 -1
  264. package/dist/document-class-P33S4CA7.js +0 -26
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/app-scope.ts","../src/utils/theme-hook-slots.ts"],"names":[],"mappings":"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","file":"chunk-2XGQSJKH.js","sourcesContent":["import type { SallaSDK } from '../types/salla-sdk';\nimport { escapeForInlineScript } from './inline-script';\n\nconst isBrowser = typeof window !== 'undefined';\n\n/** One app's private `app.*` bag, keyed without the `app.` prefix (`app.color` → `color`). */\nexport type AppConfigBag = Record<string, unknown>;\n\n/** One public `app.*` bucket per app, keyed by appScopeId. Everything else is read from the\n * real `salla.config` at runtime. */\nexport interface AppScopeContexts {\n apps: Record<string, AppConfigBag>;\n}\n\n/** Builds the `scopeId → sandboxed SDK` factory over a live bucket bag. */\nexport type AppScopeFactoryBuilder = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n w: any,\n appCtx: Record<string, AppConfigBag>\n) => (scopeId: string) => SallaSDK;\n\n/**\n * The sandbox itself: proxies that resolve `app.*` against the app's own bucket and pass\n * everything else through to the real SDK.\n *\n * MUST stay self-contained (only `Object`/`Proxy` and its two arguments): it is serialized via\n * `.toString()` next to {@link appScopeBootstrap} and handed in as an argument, so anything it\n * closed over at module scope would be undefined in the inline head copy. Split out from the\n * bootstrap purely to keep both halves reviewable.\n */\nexport const createAppScopeFactory: AppScopeFactoryBuilder = (w, appCtx) => {\n const isAppKey = (key: unknown): key is string =>\n typeof key === 'string' && key.indexOf('app.') === 0;\n const bucketKey = (key: string): string => key.slice(4);\n const realSalla = (): Record<string, unknown> => w.salla || w.Salla || {};\n const realConfig = (): Record<string, unknown> =>\n (realSalla().config as Record<string, unknown>) || {};\n const passthrough = (obj: Record<string, unknown>, prop: string | symbol): unknown => {\n const member = obj[prop as string];\n return typeof member === 'function' ? member.bind(obj) : member;\n };\n\n const createAppScope = (scopeId: string): SallaSDK => {\n const bucket = (): AppConfigBag => (appCtx[scopeId] = appCtx[scopeId] || {});\n\n const getConfig = (key: string, fallback?: unknown): unknown => {\n if (isAppKey(key)) {\n const sub = bucketKey(key);\n const b = bucket();\n // `app.*` miss returns the caller default, never the real config — a missing app\n // setting must not resolve to a same-named global.\n return sub in b ? b[sub] : fallback;\n }\n const cfg = realConfig();\n return typeof cfg.get === 'function'\n ? (cfg.get as (k: string, d?: unknown) => unknown)(key, fallback)\n : fallback;\n };\n\n const setConfig = (key: string, value: unknown): unknown => {\n if (isAppKey(key)) {\n bucket()[bucketKey(key)] = value;\n return value;\n }\n const cfg = realConfig();\n return typeof cfg.set === 'function'\n ? (cfg.set as (k: string, v: unknown) => unknown)(key, value)\n : value;\n };\n\n const hasConfig = (key: string): boolean =>\n isAppKey(key) ? bucketKey(key) in bucket() : key in realConfig();\n\n const configProxy = new Proxy({} as Record<string, unknown>, {\n get(_t, prop) {\n if (prop === 'get') return getConfig;\n if (prop === 'set') return setConfig;\n if (prop === 'has') return hasConfig;\n if (isAppKey(prop)) return getConfig(prop);\n return passthrough(realConfig(), prop);\n },\n set(_t, prop, value) {\n setConfig(prop as string, value);\n return true;\n },\n has(_t, prop) {\n return hasConfig(prop as string);\n },\n });\n\n return new Proxy({} as Record<string, unknown>, {\n get(_t, prop) {\n return prop === 'config' ? configProxy : passthrough(realSalla(), prop);\n },\n set(_t, prop, value) {\n // Reassigning `salla.config` wholesale would escape the sandbox; swallow it.\n if (prop === 'config') return true;\n realSalla()[prop as string] = value;\n return true;\n },\n }) as unknown as SallaSDK;\n };\n\n return createAppScope;\n};\n\n/**\n * Installs `window.Salla.appScope`, seeded with `contexts` and sandboxed by `makeFactory`.\n *\n * MUST stay self-contained (only `window`/`Object` and its arguments): it's serialized via\n * `.toString()` and inlined into the SSR head so the factory exists at parse time — before the\n * SDK init/hydration a CDN snippet's `onReady` races, else it throws `Salla.appScope is not a\n * function`. `makeFactory` is passed in rather than imported for exactly that reason. Also\n * called directly by `installAppScope` (tests/fallback).\n *\n * Idempotent: the factory is first-write-wins, while buckets are merged per scope (also\n * first-write-wins) so a later call can seed scopes the first one had no data for. `appCtx` is\n * closure-private (namespacing, not security: buckets are public-only and the boundary is\n * server-side).\n */\nexport function appScopeBootstrap(\n contexts: AppScopeContexts,\n makeFactory: AppScopeFactoryBuilder\n): void {\n if (typeof window === 'undefined') return;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const w = window as any;\n const Salla = (w.Salla = w.Salla || {});\n if (Salla.appScope) {\n // Already installed (normally by the inline head copy). The factory is first-write-wins,\n // but buckets are not: the head may have installed with none of them — the settings\n // endpoint can fail or lag behind the snippets one — so hand them to the existing install.\n if (Salla.__appScopeSeed) Salla.__appScopeSeed(contexts);\n return;\n }\n\n // Live bag + pristine snapshot (for mock overlays). Copy, don't alias: a snippet may\n // `config.set('app.x')` and the payload can be a cached response.\n const appCtx: Record<string, AppConfigBag> = {};\n const base: Record<string, AppConfigBag> = {};\n // Which scopes already got their real bucket, so a later seed can't overwrite one.\n const seeded: Record<string, boolean> = {};\n const seed = (next: AppScopeContexts): void => {\n const bags = (next && next.apps) || {};\n Object.keys(bags).forEach((scopeId) => {\n if (seeded[scopeId]) return;\n seeded[scopeId] = true;\n appCtx[scopeId] = Object.assign({}, appCtx[scopeId] || {}, bags[scopeId] || {});\n base[scopeId] = Object.assign({}, appCtx[scopeId]);\n });\n };\n seed(contexts);\n\n const createAppScope = makeFactory(w, appCtx);\n Salla.appScope = (scopeId: string): SallaSDK => createAppScope(scopeId);\n\n // Fill in buckets for scopes not seeded yet (first-write-wins per scope). Lets the head\n // install the factory unconditionally — at parse time, before any snippet's onReady — and\n // still pick up buckets that only the client managed to fetch.\n Salla.__appScopeSeed = (next: AppScopeContexts): void => seed(next);\n\n // Overlay preview mocks onto an app's pristine baseline, so fields the partner did not mock\n // keep their real values. Returns false for an unknown scope or before install.\n Salla.__appScopeMock = (scopeId: string, mocks: AppConfigBag): boolean => {\n if (!(scopeId in base)) return false;\n appCtx[scopeId] = Object.assign({}, base[scopeId], mocks);\n return true;\n };\n}\n\n/** Overlay preview mocks onto one app's bucket (over its pristine values). Delegates to the\n * bootstrap's `__appScopeMock`, so it works for both install paths. False if unknown/uninstalled. */\nexport function applyAppScopeMocks(appScopeId: string, mocks: AppConfigBag): boolean {\n if (!isBrowser) return false;\n const mock = (window.Salla as unknown as { __appScopeMock?: MockApplier } | undefined)\n ?.__appScopeMock;\n return mock?.(appScopeId, mocks) ?? false;\n}\n\ntype MockApplier = (appScopeId: string, mocks: AppConfigBag) => boolean;\n\n/** Serialize the installer into an inline `<script>` body seeded with `contexts` — both halves\n * via `.toString()`, hence their self-contained requirement. See `rootHead`. */\nexport function renderAppScopeInstallScript(contexts: AppScopeContexts): string {\n // Bucket values are partner-set, so escape the JSON seed against a `</script>` breakout.\n // The function sources have no `<`, so they need no escaping.\n const json = escapeForInlineScript(JSON.stringify(contexts));\n return `(${appScopeBootstrap.toString()})(${json},${createAppScopeFactory.toString()});`;\n}\n\n/** Install `Salla.appScope` on the client, or seed buckets into the inline SSR head copy that\n * already installed it. No-op on the server. Fallback for unseeded loads + the unit-test entry\n * point. */\nexport function installAppScope(contexts: AppScopeContexts): void {\n if (!isBrowser) return;\n appScopeBootstrap(contexts, createAppScopeFactory);\n}\n","import { escapeForInlineScript } from './inline-script';\n\nconst registered = new Set<string>();\n\nlet retryArmed = false;\n\n/**\n * Declare hook slots the theme renders itself so apps may mount into them.\n *\n * The SDK rejects `mount()` for any name absent from its `_themeSlots` whitelist, so a theme\n * rendering its own `<salla-hook>` must register the name. Call at module scope; the engine\n * applies the names via {@link applyThemeHookSlots}.\n */\nexport function registerThemeHookSlots(...names: string[]): void {\n for (const name of names) registered.add(name);\n}\n\n/** Push the registered names in. Returns false if the SDK hasn't exposed the list yet. */\nfunction pushSlots(): boolean {\n const slots = window.salla?.hooks?._themeSlots;\n if (!Array.isArray(slots)) return false;\n for (const name of registered) if (!slots.includes(name)) slots.push(name);\n return true;\n}\n\n/**\n * Push every registered slot name into the SDK whitelist. Idempotent. Engine-only.\n *\n * The SDK's hooks module may attach after this runs, so a first no-op falls back to a\n * one-shot retry on `twilight::initiated` — still before apps mount from their own onReady.\n *\n * This is only the late backstop: the whitelist is primarily seeded at parse time by the\n * inline head script from {@link renderThemeHookSlotsScript}, because an app's snippet\n * registers its `onReady` callback before React ever hydrates.\n */\nexport function applyThemeHookSlots(): void {\n if (typeof window === 'undefined' || registered.size === 0) return;\n if (pushSlots() || retryArmed) return;\n\n retryArmed = true;\n window.addEventListener('twilight::initiated', () => void pushSlots(), { once: true });\n}\n\n/** The slot names registered so far. Read by `rootHead` when rendering the inline script. */\nexport function getRegisteredThemeHookSlots(): string[] {\n return [...registered];\n}\n\n/**\n * Serialize the whitelist push into an inline head `<script>` body, so the slots are\n * registered at parse time.\n *\n * Ordering is the whole point: CDN snippets are parser-inserted `<script defer>` tags in the\n * body, so an app's `Salla.onReady` callback is registered long before React hydrates and runs\n * {@link applyThemeHookSlots}. Whichever `twilight::initiated` listener was added first runs\n * first, so the push must be armed from the head — otherwise the SDK rejects the app's\n * `hooks.mount()` with \"Hook <name> is not allowed\" and the app never renders.\n *\n * Returns null when the theme registered no slots. Kept self-contained (only `window`) since\n * it ships as raw source, not as a bundled module.\n */\nexport function renderThemeHookSlotsScript(names: string[] = getRegisteredThemeHookSlots()) {\n if (!names.length) return null;\n const json = escapeForInlineScript(JSON.stringify(names));\n return (\n `(function(names){` +\n `var w=window;` +\n `function push(){` +\n `var h=w.salla&&w.salla.hooks;var slots=h&&h._themeSlots;` +\n `if(!Array.isArray(slots))return false;` +\n `for(var i=0;i<names.length;i++)if(slots.indexOf(names[i])<0)slots.push(names[i]);` +\n `return true}` +\n `if(push())return;` +\n `w.addEventListener('twilight::initiated',function(){push()},{once:true})` +\n `})(${json});`\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/app-scope.ts","../src/utils/theme-hook-slots.ts"],"names":[],"mappings":"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","file":"chunk-HBTIZWT2.js","sourcesContent":["import type { SallaSDK } from '../types/salla-sdk';\nimport { escapeForInlineScript } from './inline-script';\n\nconst isBrowser = typeof window !== 'undefined';\n\n/** One app's private `app.*` bag, keyed without the `app.` prefix (`app.color` → `color`). */\nexport type AppConfigBag = Record<string, unknown>;\n\n/** One public `app.*` bucket per app, keyed by appScopeId. Everything else is read from the\n * real `salla.config` at runtime. */\nexport interface AppScopeContexts {\n apps: Record<string, AppConfigBag>;\n}\n\n/** Builds the `scopeId → sandboxed SDK` factory over a live bucket bag. */\nexport type AppScopeFactoryBuilder = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n w: any,\n appCtx: Record<string, AppConfigBag>\n) => (scopeId: string) => SallaSDK;\n\n/**\n * The sandbox itself: proxies that resolve `app.*` against the app's own bucket and pass\n * everything else through to the real SDK.\n *\n * MUST stay self-contained (only `Object`/`Proxy` and its two arguments): it is serialized via\n * `.toString()` next to {@link appScopeBootstrap} and handed in as an argument, so anything it\n * closed over at module scope would be undefined in the inline head copy. Split out from the\n * bootstrap purely to keep both halves reviewable.\n */\nexport const createAppScopeFactory: AppScopeFactoryBuilder = (w, appCtx) => {\n const isAppKey = (key: unknown): key is string =>\n typeof key === 'string' && key.indexOf('app.') === 0;\n const bucketKey = (key: string): string => key.slice(4);\n const realSalla = (): Record<string, unknown> => w.salla || w.Salla || {};\n const realConfig = (): Record<string, unknown> =>\n (realSalla().config as Record<string, unknown>) || {};\n const passthrough = (obj: Record<string, unknown>, prop: string | symbol): unknown => {\n const member = obj[prop as string];\n return typeof member === 'function' ? member.bind(obj) : member;\n };\n\n const createAppScope = (scopeId: string): SallaSDK => {\n const bucket = (): AppConfigBag => (appCtx[scopeId] = appCtx[scopeId] || {});\n\n const getConfig = (key: string, fallback?: unknown): unknown => {\n if (isAppKey(key)) {\n const sub = bucketKey(key);\n const b = bucket();\n // `app.*` miss returns the caller default, never the real config — a missing app\n // setting must not resolve to a same-named global.\n return sub in b ? b[sub] : fallback;\n }\n const cfg = realConfig();\n return typeof cfg.get === 'function'\n ? (cfg.get as (k: string, d?: unknown) => unknown)(key, fallback)\n : fallback;\n };\n\n const setConfig = (key: string, value: unknown): unknown => {\n if (isAppKey(key)) {\n bucket()[bucketKey(key)] = value;\n return value;\n }\n const cfg = realConfig();\n return typeof cfg.set === 'function'\n ? (cfg.set as (k: string, v: unknown) => unknown)(key, value)\n : value;\n };\n\n const hasConfig = (key: string): boolean =>\n isAppKey(key) ? bucketKey(key) in bucket() : key in realConfig();\n\n const configProxy = new Proxy({} as Record<string, unknown>, {\n get(_t, prop) {\n if (prop === 'get') return getConfig;\n if (prop === 'set') return setConfig;\n if (prop === 'has') return hasConfig;\n if (isAppKey(prop)) return getConfig(prop);\n return passthrough(realConfig(), prop);\n },\n set(_t, prop, value) {\n setConfig(prop as string, value);\n return true;\n },\n has(_t, prop) {\n return hasConfig(prop as string);\n },\n });\n\n return new Proxy({} as Record<string, unknown>, {\n get(_t, prop) {\n return prop === 'config' ? configProxy : passthrough(realSalla(), prop);\n },\n set(_t, prop, value) {\n // Reassigning `salla.config` wholesale would escape the sandbox; swallow it.\n if (prop === 'config') return true;\n realSalla()[prop as string] = value;\n return true;\n },\n }) as unknown as SallaSDK;\n };\n\n return createAppScope;\n};\n\n/**\n * Installs `window.Salla.appScope`, seeded with `contexts` and sandboxed by `makeFactory`.\n *\n * MUST stay self-contained (only `window`/`Object` and its arguments): it's serialized via\n * `.toString()` and inlined into the SSR head so the factory exists at parse time — before the\n * SDK init/hydration a CDN snippet's `onReady` races, else it throws `Salla.appScope is not a\n * function`. `makeFactory` is passed in rather than imported for exactly that reason. Also\n * called directly by `installAppScope` (tests/fallback).\n *\n * Idempotent: the factory is first-write-wins, while buckets are merged per scope (also\n * first-write-wins) so a later call can seed scopes the first one had no data for. `appCtx` is\n * closure-private (namespacing, not security: buckets are public-only and the boundary is\n * server-side).\n */\nexport function appScopeBootstrap(\n contexts: AppScopeContexts,\n makeFactory: AppScopeFactoryBuilder\n): void {\n if (typeof window === 'undefined') return;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const w = window as any;\n const Salla = (w.Salla = w.Salla || {});\n if (Salla.appScope) {\n // Already installed (normally by the inline head copy). The factory is first-write-wins,\n // but buckets are not: the head may have installed with none of them — the settings\n // endpoint can fail or lag behind the snippets one — so hand them to the existing install.\n if (Salla.__appScopeSeed) Salla.__appScopeSeed(contexts);\n return;\n }\n\n // Live bag + pristine snapshot (for mock overlays). Copy, don't alias: a snippet may\n // `config.set('app.x')` and the payload can be a cached response.\n const appCtx: Record<string, AppConfigBag> = {};\n const base: Record<string, AppConfigBag> = {};\n // Which scopes already got their real bucket, so a later seed can't overwrite one.\n const seeded: Record<string, boolean> = {};\n const seed = (next: AppScopeContexts): void => {\n const bags = (next && next.apps) || {};\n Object.keys(bags).forEach((scopeId) => {\n if (seeded[scopeId]) return;\n seeded[scopeId] = true;\n appCtx[scopeId] = Object.assign({}, appCtx[scopeId] || {}, bags[scopeId] || {});\n base[scopeId] = Object.assign({}, appCtx[scopeId]);\n });\n };\n seed(contexts);\n\n const createAppScope = makeFactory(w, appCtx);\n Salla.appScope = (scopeId: string): SallaSDK => createAppScope(scopeId);\n\n // Fill in buckets for scopes not seeded yet (first-write-wins per scope). Lets the head\n // install the factory unconditionally — at parse time, before any snippet's onReady — and\n // still pick up buckets that only the client managed to fetch.\n Salla.__appScopeSeed = (next: AppScopeContexts): void => seed(next);\n\n // Overlay preview mocks onto an app's pristine baseline, so fields the partner did not mock\n // keep their real values. Returns false for an unknown scope or before install.\n Salla.__appScopeMock = (scopeId: string, mocks: AppConfigBag): boolean => {\n if (!(scopeId in base)) return false;\n appCtx[scopeId] = Object.assign({}, base[scopeId], mocks);\n return true;\n };\n}\n\n/** Overlay preview mocks onto one app's bucket (over its pristine values). Delegates to the\n * bootstrap's `__appScopeMock`, so it works for both install paths. False if unknown/uninstalled. */\nexport function applyAppScopeMocks(appScopeId: string, mocks: AppConfigBag): boolean {\n if (!isBrowser) return false;\n const mock = (window.Salla as unknown as { __appScopeMock?: MockApplier } | undefined)\n ?.__appScopeMock;\n return mock?.(appScopeId, mocks) ?? false;\n}\n\ntype MockApplier = (appScopeId: string, mocks: AppConfigBag) => boolean;\n\n/** Serialize the installer into an inline `<script>` body seeded with `contexts` — both halves\n * via `.toString()`, hence their self-contained requirement. See `rootHead`. */\nexport function renderAppScopeInstallScript(contexts: AppScopeContexts): string {\n // Bucket values are partner-set, so escape the JSON seed against a `</script>` breakout.\n // The function sources have no `<`, so they need no escaping.\n const json = escapeForInlineScript(JSON.stringify(contexts));\n return `(${appScopeBootstrap.toString()})(${json},${createAppScopeFactory.toString()});`;\n}\n\n/** Install `Salla.appScope` on the client, or seed buckets into the inline SSR head copy that\n * already installed it. No-op on the server. Fallback for unseeded loads + the unit-test entry\n * point. */\nexport function installAppScope(contexts: AppScopeContexts): void {\n if (!isBrowser) return;\n appScopeBootstrap(contexts, createAppScopeFactory);\n}\n","import { escapeForInlineScript } from './inline-script';\n\nconst registered = new Set<string>();\n\nlet retryArmed = false;\n\n/**\n * Declare hook slots the theme renders itself so apps may mount into them.\n *\n * The SDK rejects `mount()` for any name absent from its `_themeSlots` whitelist, so a theme\n * rendering its own `<salla-hook>` must register the name. Call at module scope; the engine\n * applies the names via {@link applyThemeHookSlots}.\n */\nexport function registerThemeHookSlots(...names: string[]): void {\n for (const name of names) registered.add(name);\n}\n\n/** Push the registered names in. Returns false if the SDK hasn't exposed the list yet. */\nfunction pushSlots(): boolean {\n const slots = window.salla?.hooks?._themeSlots;\n if (!Array.isArray(slots)) return false;\n for (const name of registered) if (!slots.includes(name)) slots.push(name);\n return true;\n}\n\n/**\n * Push every registered slot name into the SDK whitelist. Idempotent. Engine-only.\n *\n * The SDK's hooks module may attach after this runs, so a first no-op falls back to a\n * one-shot retry on `twilight::initiated` — still before apps mount from their own onReady.\n *\n * This is only the late backstop: the whitelist is primarily seeded at parse time by the\n * inline head script from {@link renderThemeHookSlotsScript}, because an app's snippet\n * registers its `onReady` callback before React ever hydrates.\n */\nexport function applyThemeHookSlots(): void {\n if (typeof window === 'undefined' || registered.size === 0) return;\n if (pushSlots() || retryArmed) return;\n\n retryArmed = true;\n window.addEventListener('twilight::initiated', () => void pushSlots(), { once: true });\n}\n\n/** The slot names registered so far. Read by `rootHead` when rendering the inline script. */\nexport function getRegisteredThemeHookSlots(): string[] {\n return [...registered];\n}\n\n/**\n * Serialize the whitelist push into an inline head `<script>` body, so the slots are\n * registered at parse time.\n *\n * Ordering is the whole point: CDN snippets are parser-inserted `<script defer>` tags in the\n * body, so an app's `Salla.onReady` callback is registered long before React hydrates and runs\n * {@link applyThemeHookSlots}. Whichever `twilight::initiated` listener was added first runs\n * first, so the push must be armed from the head — otherwise the SDK rejects the app's\n * `hooks.mount()` with \"Hook <name> is not allowed\" and the app never renders.\n *\n * Returns null when the theme registered no slots. Kept self-contained (only `window`) since\n * it ships as raw source, not as a bundled module.\n */\nexport function renderThemeHookSlotsScript(names: string[] = getRegisteredThemeHookSlots()) {\n if (!names.length) return null;\n const json = escapeForInlineScript(JSON.stringify(names));\n return (\n `(function(names){` +\n `var w=window;` +\n `function push(){` +\n `var h=w.salla&&w.salla.hooks;var slots=h&&h._themeSlots;` +\n `if(!Array.isArray(slots))return false;` +\n `for(var i=0;i<names.length;i++)if(slots.indexOf(names[i])<0)slots.push(names[i]);` +\n `return true}` +\n `if(push())return;` +\n `w.addEventListener('twilight::initiated',function(){push()},{once:true})` +\n `})(${json});`\n );\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-MLWGLXJZ.js').then((m) => ({ default: m.Breadcrumb }))
7
+ () => import('./Breadcrumb-74NZ4CAI.js').then((m) => ({ default: m.Breadcrumb }))
8
8
  );
9
9
  var LazyNoContent = lazy(
10
10
  () => import('./NoContent-63TMCPGY.js').then((m) => ({ default: m.NoContent }))
@@ -151,5 +151,5 @@ function DeferredData({ promise, fallback, children }) {
151
151
  }
152
152
 
153
153
  export { DeferredData, Image, LazyBreadcrumb, LazyCurrencySymbol, LazyErrorPage, LazyNoContent, LazyRenderWhenVisible, resolveDeferred };
154
- //# sourceMappingURL=chunk-J2YKHDMH.js.map
155
- //# sourceMappingURL=chunk-J2YKHDMH.js.map
154
+ //# sourceMappingURL=chunk-I26VPNDP.js.map
155
+ //# sourceMappingURL=chunk-I26VPNDP.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,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,MACP,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,SAAA,IAAa,CAAC,WAAA,EAAa;AAC7B,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;AC1GD,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-J2YKHDMH.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 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 {...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 (noWrapper || !aspectRatio) {\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-I26VPNDP.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 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 {...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 (noWrapper || !aspectRatio) {\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"]}
@@ -0,0 +1,186 @@
1
+ import { configureNavigation, UnauthorizedError, NavigationProvider, resolveRelativePath } from './chunk-SDIQHTDG.js';
2
+ import { LinkProvider } from './chunk-BYMOPN2S.js';
3
+ import { useIsNativeApp } from './chunk-3IHFA2X5.js';
4
+ import { resolveStoreBase, onSallaEvent } from './chunk-QVJDYSCT.js';
5
+ import { loginRedirectHref, isLoopback, hasStoreUrlBase } from './chunk-LPQFTXBB.js';
6
+ import { getTwilightContext, getRequestStore } from './chunk-N2S25NXP.js';
7
+ import { isLocale } from './chunk-T72DAX7R.js';
8
+ import { useTwilight } from './chunk-DF6FBKDN.js';
9
+ import { useParams, Link, redirect, notFound, useNavigate, useRouter } from '@tanstack/react-router';
10
+ import { forwardRef, createElement, useCallback, useEffect } from 'react';
11
+ import { jsxs, jsx } from 'react/jsx-runtime';
12
+
13
+ function localizeDestination(destination, locale) {
14
+ if (!locale || !destination.startsWith("/") || destination.startsWith("//")) return destination;
15
+ const firstSegment = destination.split("/")[1]?.split(/[?#]/)[0];
16
+ if (isLocale(firstSegment)) return destination;
17
+ return destination === "/" ? `/${locale}` : `/${locale}${destination}`;
18
+ }
19
+ var TanStackLinkAdapter = forwardRef(
20
+ ({
21
+ to,
22
+ href,
23
+ children,
24
+ className,
25
+ style,
26
+ title,
27
+ target,
28
+ rel,
29
+ onClick,
30
+ preload,
31
+ replace,
32
+ "aria-label": ariaLabel,
33
+ ...rest
34
+ }, ref) => {
35
+ const { locale } = useParams({ strict: false });
36
+ const destination = localizeDestination(to ?? href ?? "/", locale);
37
+ return createElement(
38
+ Link,
39
+ {
40
+ ref,
41
+ to: destination,
42
+ className,
43
+ style,
44
+ title,
45
+ target,
46
+ rel,
47
+ onClick,
48
+ preload: preload === "intent" || preload === false ? preload : void 0,
49
+ replace,
50
+ "aria-label": ariaLabel,
51
+ ...rest
52
+ },
53
+ children
54
+ );
55
+ }
56
+ );
57
+ TanStackLinkAdapter.displayName = "TanStackLinkAdapter";
58
+ function createTanStackLinkAdapter() {
59
+ return TanStackLinkAdapter;
60
+ }
61
+ var UI_UPDATE_EVENT = "mobile::ui.update";
62
+ var OPEN_ORDER_EVENT = "mobile::open.order";
63
+ var NAVIGATE_TO_EVENT = "mobile::navigate.to";
64
+ function NativeAppEvents({ locale }) {
65
+ return useIsNativeApp() ? /* @__PURE__ */ jsx(Listeners, { locale }) : null;
66
+ }
67
+ function Listeners({ locale }) {
68
+ useNativeAppEvents(locale);
69
+ return null;
70
+ }
71
+ function useNativeAppEvents(locale) {
72
+ const router = useRouter();
73
+ const { store } = useTwilight();
74
+ const storeUrl = store?.url;
75
+ const username = store?.username;
76
+ useEffect(() => {
77
+ const open = (path) => void router.navigate({ href: localizeDestination(path, locale) });
78
+ const refresh = () => {
79
+ void Promise.allSettled([
80
+ router.invalidate(),
81
+ getTwilightContext().queryClient?.refetchQueries({ type: "active" })
82
+ ]);
83
+ };
84
+ const openOrder = (data) => {
85
+ const rawId = data?.id;
86
+ if (typeof rawId !== "string" && typeof rawId !== "number") return;
87
+ const id = String(rawId).trim();
88
+ if (!id) return;
89
+ void getTwilightContext().queryClient?.invalidateQueries({ queryKey: ["cart"] });
90
+ open(`/account/orders/${encodeURIComponent(id)}`);
91
+ };
92
+ const navigateTo = (data) => {
93
+ const url = data?.url;
94
+ if (typeof url !== "string" || !url.trim() || !storeUrl) return;
95
+ const path = deepLinkPath(url.trim(), storeUrl, username);
96
+ if (path) void router.navigate({ href: inLocale(path, locale) });
97
+ };
98
+ const offs = [
99
+ onSallaEvent(UI_UPDATE_EVENT, refresh),
100
+ onSallaEvent(OPEN_ORDER_EVENT, openOrder),
101
+ onSallaEvent(NAVIGATE_TO_EVENT, navigateTo)
102
+ ];
103
+ return () => offs.forEach((off) => off());
104
+ }, [router, locale, storeUrl, username]);
105
+ }
106
+ function isAbsoluteUrl(url) {
107
+ if (url.startsWith("//")) return true;
108
+ try {
109
+ new URL(url);
110
+ return true;
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ function deepLinkPath(url, storeUrl, username) {
116
+ const path = resolveRelativePath(url, storeUrl, username);
117
+ if (!path || !isAbsoluteUrl(url)) return path;
118
+ const { pathname } = new URL(url, window.location.href);
119
+ return hasStoreUrlBase(pathname, new URL(storeUrl).pathname, username) ? path : null;
120
+ }
121
+ function inLocale(path, locale) {
122
+ const first = path.split("/")[1]?.split(/[?#]/)[0];
123
+ const own = isLocale(first) ? path.slice(first.length + 1) : path;
124
+ const rest = own.startsWith("/") ? own : `/${own}`;
125
+ if (!locale) return rest;
126
+ return rest === "/" ? `/${locale}` : `/${locale}${rest}`;
127
+ }
128
+
129
+ // src/utils/request-host.ts
130
+ function requestHostOf(request) {
131
+ try {
132
+ const fromUrl = new URL(request.url).host;
133
+ if (fromUrl) return fromUrl;
134
+ } catch {
135
+ }
136
+ return request.headers.get("Host")?.trim() || null;
137
+ }
138
+ function requestOriginOf(host) {
139
+ return `${isLoopback(host.replace(/:\d+$/, "")) ? "http" : "https"}://${host}`;
140
+ }
141
+ function currentOrigin() {
142
+ if (typeof window !== "undefined") return window.location.origin;
143
+ const host = getRequestStore().requestHost;
144
+ return host ? requestOriginOf(host) : null;
145
+ }
146
+ configureNavigation({
147
+ notFound: (message) => {
148
+ throw notFound({ data: message });
149
+ },
150
+ redirect: (path, opts) => {
151
+ throw redirect({ to: path, replace: opts?.replace, statusCode: opts?.statusCode });
152
+ },
153
+ unauthorized: (message) => {
154
+ const origin = currentOrigin();
155
+ const { pathname, searchStr } = getTwilightContext().location;
156
+ const href = origin && loginRedirectHref({ pathname, searchStr, origin, base: resolveStoreBase() });
157
+ if (href) throw redirect({ href, reloadDocument: true, replace: true });
158
+ throw new UnauthorizedError(message);
159
+ }
160
+ });
161
+ function NavigationSetup({ children }) {
162
+ const navigate = useNavigate();
163
+ const { locale } = useParams({ strict: false });
164
+ const navigateFn = useCallback(
165
+ (to, opts) => navigate({ to: localizeDestination(to, locale), replace: opts?.replace }),
166
+ [navigate, locale]
167
+ );
168
+ return /* @__PURE__ */ jsxs(NavigationProvider, { navigate: navigateFn, children: [
169
+ /* @__PURE__ */ jsx(NativeAppEvents, { locale }),
170
+ /* @__PURE__ */ jsx(LinkProvider, { adapter: TanStackLinkAdapter, children })
171
+ ] });
172
+ }
173
+ function TanStackNavigationProvider({ children }) {
174
+ const navigate = useNavigate();
175
+ return /* @__PURE__ */ jsx(
176
+ NavigationProvider,
177
+ {
178
+ navigate: (to, opts) => navigate({ to, replace: opts?.replace }),
179
+ children: /* @__PURE__ */ jsx(LinkProvider, { adapter: TanStackLinkAdapter, children })
180
+ }
181
+ );
182
+ }
183
+
184
+ export { NavigationSetup, TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter, requestHostOf };
185
+ //# sourceMappingURL=chunk-J427UFSZ.js.map
186
+ //# sourceMappingURL=chunk-J427UFSZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tanstack/link.tsx","../src/tanstack/native-app-events.tsx","../src/utils/request-host.ts","../src/tanstack/navigation.tsx"],"names":["TanStackLink","tanstackNotFound","tanstackRedirect","useParams","jsx"],"mappings":"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","file":"chunk-J427UFSZ.js","sourcesContent":["import { forwardRef, createElement } from 'react';\nimport { Link as TanStackLink, useParams } from '@tanstack/react-router';\nimport { isLocale } from '../providers/locale-constants';\nimport type { BaseLinkProps } from '../components/common/Link.types';\n\n/**\n * Routes live under an optional `/{-$locale}` param, so a bare `to=\"/brands\"`\n * resolves with the locale omitted and the $locale loader bounces the user to\n * the fallback locale. Prefix the current locale onto internal paths that\n * don't already carry one.\n */\nexport function localizeDestination(destination: string, locale?: string) {\n if (!locale || !destination.startsWith('/') || destination.startsWith('//')) return destination;\n const firstSegment = destination.split('/')[1]?.split(/[?#]/)[0];\n if (isLocale(firstSegment)) return destination;\n return destination === '/' ? `/${locale}` : `/${locale}${destination}`;\n}\n\n/**\n * TanStack Router Link adapter.\n * Translates framework-agnostic props to TanStack Router Link props.\n */\nexport const TanStackLinkAdapter = forwardRef<HTMLAnchorElement, BaseLinkProps>(\n (\n {\n to,\n href,\n children,\n className,\n style,\n title,\n target,\n rel,\n onClick,\n preload,\n replace,\n 'aria-label': ariaLabel,\n ...rest\n },\n ref\n ) => {\n const { locale } = useParams({ strict: false }) as { locale?: string };\n const destination = localizeDestination(to ?? href ?? '/', locale);\n\n return createElement(\n TanStackLink,\n {\n ref,\n to: destination,\n className,\n style,\n title,\n target,\n rel,\n onClick,\n preload: preload === 'intent' || preload === false ? preload : undefined,\n replace,\n 'aria-label': ariaLabel,\n ...(rest as Record<string, unknown>),\n },\n children\n );\n }\n);\n\nTanStackLinkAdapter.displayName = 'TanStackLinkAdapter';\n\n/**\n * Create a TanStack Router Link adapter component.\n */\nexport function createTanStackLinkAdapter() {\n return TanStackLinkAdapter;\n}\n","import { useEffect } from 'react';\nimport { useRouter } from '@tanstack/react-router';\nimport { resolveRelativePath } from '../providers/NavigationProvider';\nimport { useTwilight } from '../providers/twilight-context';\nimport { isLocale } from '../providers/locale-constants';\nimport { getTwilightContext } from '../twilight/context';\nimport { useIsNativeApp } from '../native-app';\nimport { onSallaEvent } from '../utils/sdk-helpers';\nimport { hasStoreUrlBase } from '../utils/store-base';\nimport { localizeDestination } from './link';\n\nconst UI_UPDATE_EVENT = 'mobile::ui.update';\nconst OPEN_ORDER_EVENT = 'mobile::open.order';\nconst NAVIGATE_TO_EVENT = 'mobile::navigate.to';\n\n/**\n * Events the native app sends into its webview. `NavigationSetup` mounts this once, so a\n * theme adds no listener of its own:\n *\n * - `mobile::ui.update` re-runs the route loaders and refetches what is on screen.\n * - `mobile::open.order` `{ id }` opens that order, with a fresh cart.\n * - `mobile::navigate.to` `{ url }` opens a notification deep link in-app. Only a link to\n * this store is followed (`deepLinkPath`), so `javascript:`, off-site and other stores'\n * URLs are dropped.\n *\n * Nothing is mounted outside the app (`useIsNativeApp()`), so a browser runs none of it.\n */\nexport function NativeAppEvents({ locale }: { locale?: string }) {\n return useIsNativeApp() ? <Listeners locale={locale} /> : null;\n}\n\nfunction Listeners({ locale }: { locale?: string }) {\n useNativeAppEvents(locale);\n return null;\n}\n\n/** The listeners themselves. `NativeAppEvents` mounts them inside the app only. */\nexport function useNativeAppEvents(locale?: string): void {\n const router = useRouter();\n const { store } = useTwilight();\n const storeUrl = store?.url;\n const username = store?.username;\n\n useEffect(() => {\n // `href`, not `to`: the router parses the query and the hash out of it.\n const open = (path: string) =>\n void router.navigate({ href: localizeDestination(path, locale) });\n\n const refresh = () => {\n void Promise.allSettled([\n router.invalidate(),\n getTwilightContext().queryClient?.refetchQueries({ type: 'active' }),\n ]);\n };\n const openOrder = (data?: unknown) => {\n const rawId = (data as { id?: unknown } | undefined)?.id;\n if (typeof rawId !== 'string' && typeof rawId !== 'number') return;\n\n const id = String(rawId).trim();\n if (!id) return;\n\n void getTwilightContext().queryClient?.invalidateQueries({ queryKey: ['cart'] });\n open(`/account/orders/${encodeURIComponent(id)}`);\n };\n const navigateTo = (data?: unknown) => {\n const url = (data as { url?: unknown } | undefined)?.url;\n if (typeof url !== 'string' || !url.trim() || !storeUrl) return;\n\n const path = deepLinkPath(url.trim(), storeUrl, username);\n if (path) void router.navigate({ href: inLocale(path, locale) });\n };\n\n const offs = [\n onSallaEvent(UI_UPDATE_EVENT, refresh),\n onSallaEvent(OPEN_ORDER_EVENT, openOrder),\n onSallaEvent(NAVIGATE_TO_EVENT, navigateTo),\n ];\n return () => offs.forEach((off) => off());\n }, [router, locale, storeUrl, username]);\n}\n\n/** A URL that names its host: `https://…` or `//…`. Anything else is a path of this app. */\nfunction isAbsoluteUrl(url: string): boolean {\n if (url.startsWith('//')) return true;\n try {\n // Without a base, only a URL with its own scheme parses.\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * The application path of a deep link to this store, or null for any other link.\n *\n * It passes the test a tapped link does (`resolveRelativePath`: the store's origin, the\n * username taken off), and one more. On a shared host that origin is every store's, so\n * an absolute link has to carry this store's username: without it, another store's\n * `/ar/offers` would open this store's offers.\n */\nfunction deepLinkPath(url: string, storeUrl: string, username?: string): string | null {\n const path = resolveRelativePath(url, storeUrl, username);\n if (!path || !isAbsoluteUrl(url)) return path;\n\n // Both parse: `resolveRelativePath` returns null when either does not.\n const { pathname } = new URL(url, window.location.href);\n return hasStoreUrlBase(pathname, new URL(storeUrl).pathname, username) ? path : null;\n}\n\n/**\n * A deep link in the locale the visitor is browsing in. A notification is written in one\n * language and opened in whichever is on screen, so the link's own locale gives way.\n *\n * The prefix is written here, not by `localizeDestination`: that one leaves a path alone\n * when it already starts with a locale, and would take the slug of `/ar/en/p456` for one.\n */\nfunction inLocale(path: string, locale?: string): string {\n const first = path.split('/')[1]?.split(/[?#]/)[0];\n const own = isLocale(first) ? path.slice(first.length + 1) : path;\n const rest = own.startsWith('/') ? own : `/${own}`;\n\n if (!locale) return rest;\n return rest === '/' ? `/${locale}` : `/${locale}${rest}`;\n}\n","/**\n * What the request itself is enough to describe: its host.\n *\n * Small, and deliberately its own module rather than a helper inside the\n * middleware. This value decides two things — which store a live storefront is,\n * and whether the request is allowed to name a store at all — so it is worth\n * testing directly instead of only through the wiring that calls it.\n */\nimport { isLoopback } from './cookies';\n\n/** The part of a `Request` this needs, so a test does not have to build a whole one. */\nexport interface HostSource {\n url: string;\n headers: { get(name: string): string | null };\n}\n\n/**\n * The host this request arrived on, with its port when it has one.\n *\n * Taken from the request URL, which in a Worker is the address the platform\n * actually routed on, and from the `Host` header only when that fails.\n *\n * **`X-Forwarded-Host` is deliberately not consulted.** A client can set it, and\n * this value gates `allowsRequestStoreId` — so honouring it would be a way to\n * talk a merchant's own domain into behaving like the preview host, and from\n * there into serving a stranger's shop. The dispatcher strips that header today;\n * a theme must not be one edit to another repository's allowlist away from a\n * spoofable identity.\n */\nexport function requestHostOf(request: HostSource): string | null {\n try {\n const fromUrl = new URL(request.url).host;\n if (fromUrl) return fromUrl;\n } catch {\n /* an unparseable URL falls through to the header */\n }\n\n return request.headers.get('Host')?.trim() || null;\n}\n\n/** The origin a browser reached this host on: `http` for a dev server, `https` otherwise. */\nexport function requestOriginOf(host: string): string {\n return `${isLoopback(host.replace(/:\\d+$/, '')) ? 'http' : 'https'}://${host}`;\n}\n","import {\n useNavigate,\n useParams,\n redirect as tanstackRedirect,\n notFound as tanstackNotFound,\n} from '@tanstack/react-router';\nimport {\n NavigationProvider,\n configureNavigation,\n type NavigateOptions,\n} from '../providers/NavigationProvider';\nimport { LinkProvider } from '../providers/LinkProvider';\nimport { TanStackLinkAdapter, localizeDestination } from './link';\nimport { NativeAppEvents } from './native-app-events';\nimport { useCallback, type ReactNode } from 'react';\nimport { UnauthorizedError, type RedirectOptions } from '../providers/NavigationProvider';\nimport { getRequestStore, getTwilightContext } from '../twilight/context';\nimport { resolveStoreBase } from '../utils/store-identity';\nimport { loginRedirectHref } from '../utils/store-base';\nimport { requestOriginOf } from '../utils/request-host';\n\nfunction currentOrigin(): string | null {\n if (typeof window !== 'undefined') return window.location.origin;\n const host = getRequestStore().requestHost;\n return host ? requestOriginOf(host) : null;\n}\n\nconfigureNavigation({\n notFound: (message?: string) => {\n throw tanstackNotFound({ data: message });\n },\n redirect: (path: string, opts?: RedirectOptions) => {\n throw tanstackRedirect({ to: path, replace: opts?.replace, statusCode: opts?.statusCode });\n },\n unauthorized: (message?: string) => {\n const origin = currentOrigin();\n const { pathname, searchStr } = getTwilightContext().location;\n const href =\n origin && loginRedirectHref({ pathname, searchStr, origin, base: resolveStoreBase() });\n // A full load, because the SDK only reads `intended_to` when a page starts.\n if (href) throw tanstackRedirect({ href, reloadDocument: true, replace: true });\n throw new UnauthorizedError(message);\n },\n});\n\n/**\n * TanStack navigation setup - wraps children with NavigationProvider and LinkProvider.\n * Called by TwilightProvider when client.framework === 'tanstack'.\n */\nexport function NavigationSetup({ children }: { children: ReactNode }) {\n const navigate = useNavigate();\n const { locale } = useParams({ strict: false }) as { locale?: string };\n const navigateFn = useCallback(\n (to: string, opts?: NavigateOptions) =>\n navigate({ to: localizeDestination(to, locale), replace: opts?.replace }),\n [navigate, locale]\n );\n\n return (\n <NavigationProvider navigate={navigateFn}>\n <NativeAppEvents locale={locale} />\n <LinkProvider adapter={TanStackLinkAdapter}>{children}</LinkProvider>\n </NavigationProvider>\n );\n}\n\n/** @deprecated Use NavigationSetup instead */\nexport function TanStackNavigationProvider({ children }: { children: ReactNode }) {\n const navigate = useNavigate();\n return (\n <NavigationProvider\n navigate={(to: string, opts?: NavigateOptions) => navigate({ to, replace: opts?.replace })}\n >\n <LinkProvider adapter={TanStackLinkAdapter}>{children}</LinkProvider>\n </NavigationProvider>\n );\n}\n"]}
@@ -167,6 +167,12 @@ function withoutStoreUrlBase(pathname, storeUrlPathname, username) {
167
167
  segments.splice(at, 1);
168
168
  return segments.join("/") || "/";
169
169
  }
170
+ function hasStoreUrlBase(pathname, storeUrlPathname, username) {
171
+ const own = storeUrlSegment(storeUrlPathname, username);
172
+ if (!own) return true;
173
+ const segments = pathname.split("/");
174
+ return segments[1] === own || isLocale(segments[1]) && segments[2] === own;
175
+ }
170
176
  function storeUrlSegment(storeUrlPathname, username) {
171
177
  const last = storeUrlPathname.split("/").filter(Boolean).pop();
172
178
  if (!last) return null;
@@ -192,6 +198,6 @@ function loginRedirectHref(args) {
192
198
  return `${browserPath(home)}?intended_to=${encodeURIComponent(intended)}`;
193
199
  }
194
200
 
195
- export { AUTH_TOKEN_COOKIE_NAME, clearAuthTokenCookie, extractScopeFromCookies, extractTokenFromCookies, hostIdentifiesStore, isLoopback, loginRedirectHref, prefixStoreBase, readSdkScope, rememberDevStoreId, resolveRequestStore, resolveRequestStoreBase, resolveRequestVersionId, storeBaseRedirectHref, stripStoreBase, syncScopeCookie, withoutStoreUrlBase };
196
- //# sourceMappingURL=chunk-SR4OTLTJ.js.map
197
- //# sourceMappingURL=chunk-SR4OTLTJ.js.map
201
+ export { AUTH_TOKEN_COOKIE_NAME, clearAuthTokenCookie, extractScopeFromCookies, extractTokenFromCookies, hasStoreUrlBase, hostIdentifiesStore, isLoopback, loginRedirectHref, prefixStoreBase, readSdkScope, rememberDevStoreId, resolveRequestStore, resolveRequestStoreBase, resolveRequestVersionId, storeBaseRedirectHref, stripStoreBase, syncScopeCookie, withoutStoreUrlBase };
202
+ //# sourceMappingURL=chunk-LPQFTXBB.js.map
203
+ //# sourceMappingURL=chunk-LPQFTXBB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/cookies.ts","../src/utils/store-base.ts"],"names":[],"mappings":"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","file":"chunk-LPQFTXBB.js","sourcesContent":["import { isLocale } from '../providers/locale-constants';\n\nexport const AUTH_TOKEN_COOKIE_NAME = 'token';\nexport const SCOPE_COOKIE_NAME = 'scope';\n\n/**\n * Which store this request is for, when the hostname does not say.\n *\n * A live storefront is reached at its own domain, so the hostname identifies it\n * and nothing else is needed. A preview is not: every theme under review is\n * served from the one preview hostname, so the store has to be named some other\n * way — the dispatcher takes it from `?storeId=` and puts it here, the same way\n * it remembers which theme to serve.\n *\n * Written by the dispatcher rather than the theme, and set on the *forwarded\n * request* as well as the response, because the response cookie only arrives in\n * time for the second page load and the first one has to render too.\n *\n * The literal is a contract with `STORE_COOKIE` in store-front-dispacher\n * (`src/dispatch/preview.ts`), and **nothing checks the two agree**. Drift does\n * not fail loudly — it renders somebody else's shop. Grep both repos before\n * changing it.\n */\nexport const STORE_ID_COOKIE_NAME = 'salla_sid';\n\n/** Query parameter naming the store, on a host that serves more than one. */\nexport const STORE_ID_PARAM = 'storeId';\n\n/**\n * Which version of the theme's settings to render.\n *\n * A merchant's theme settings are versioned, and the storefront normally shows\n * whichever version is live — the API answers with it, and names it back as\n * `theme.profile.id`. Two places need a different one: the merchant's own theme\n * editor, which previews a draft version before it is published, and a partner\n * running a theme locally against a store whose settings they are editing. Both\n * open the theme inside an iframe, and the version travels in that URL.\n *\n * Named `versionId` rather than the `version_id` the Dashboard uses internally,\n * because it sits beside `?storeId=` and one URL should not spell two ids two\n * ways. The value is the same one either way: the Optimus-encoded version id,\n * which is exactly what `s-version-id` has always carried.\n *\n * The literal is a contract with `VERSION_COOKIE` in store-front-dispacher\n * (`src/dispatch/preview.ts`), on the same terms as {@link STORE_ID_COOKIE_NAME}:\n * nothing checks the two agree, and drift shows a merchant the wrong version of\n * their own settings rather than failing.\n */\nexport const VERSION_ID_COOKIE_NAME = 'salla_vid';\n\n/** Query parameter naming the theme-settings version, where one may be named. */\nexport const VERSION_ID_PARAM = 'versionId';\n\n/**\n * An id named by a request is an integer, and anything else is not one.\n *\n * Validated rather than passed through because these values end up in an upstream\n * API path and header. Leading zeroes, signs, decimals and whitespace are all\n * rejected: the point is a single canonical form, not the widest set of things\n * that could be coerced into a number.\n *\n * One function for both ids on purpose. They arrive the same way, from the same\n * untrusted place, and are spent the same way; two copies of this rule would be\n * two chances for one of them to be relaxed on its own.\n */\nfunction parseRequestId(raw: string | null | undefined): string | null {\n if (!raw) return null;\n return /^[1-9][0-9]{0,18}$/.test(raw) ? raw : null;\n}\n\n/** A store id in its canonical form, or null when it is not one. */\nexport function parseStoreId(raw: string | null | undefined): string | null {\n return parseRequestId(raw);\n}\n\n/** A theme-settings version id in its canonical form, or null when it is not one. */\nexport function parseVersionId(raw: string | null | undefined): string | null {\n return parseRequestId(raw);\n}\n\n/** The store id the dispatcher left in the cookie, or null when absent or malformed. */\nexport function extractStoreIdFromCookies(cookieHeader: string | null): string | null {\n return parseStoreId(extractTokenFromCookies(cookieHeader, STORE_ID_COOKIE_NAME));\n}\n\n/** The version id the dispatcher left in the cookie, or null when absent or malformed. */\nexport function extractVersionIdFromCookies(cookieHeader: string | null): string | null {\n return parseVersionId(extractTokenFromCookies(cookieHeader, VERSION_ID_COOKIE_NAME));\n}\n\n/**\n * The only hosts on which a request may name its own store.\n *\n * **This is a security boundary, not a convenience.** On a merchant's own domain\n * the hostname *is* the store, and it is the only thing that may decide. A theme\n * that also honoured `?storeId=` there would let anyone open\n * `https://reefperfumes.com/?storeId=<someone else>` and be served a different\n * merchant's shop from the domain its owner controls — their branding, their\n * customers' address bar, somebody else's catalogue — and the cookie would keep\n * serving it for the rest of that browser's session. Salla points SaaS domains\n * at this dispatcher, so those hostnames are real and reachable.\n *\n * The override exists for one situation: a host that serves many stores and so\n * cannot identify one from its name. That is the preview host, where every theme\n * under review answers on the same address, and local development.\n *\n * Adding an entry grants that host the ability to render any store on request.\n * Add nothing that a merchant's traffic reaches.\n */\nexport const STORE_ID_HOSTS: readonly string[] = ['preview.salla.design'];\n\n/** The hostname alone — a port never distinguishes one host's authority from another's. */\nfunction hostnameOf(host: string): string {\n const trimmed = host.trim().toLowerCase();\n // IPv6 literals are bracketed, and the colons inside them are not a port.\n if (trimmed.startsWith('[')) return trimmed.slice(0, trimmed.indexOf(']') + 1) || trimmed;\n const colon = trimmed.indexOf(':');\n return colon === -1 ? trimmed : trimmed.slice(0, colon);\n}\n\nexport function isLoopback(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '[::1]' ||\n hostname.endsWith('.localhost')\n );\n}\n\n/**\n * Whether this host is allowed to let the request choose a store.\n *\n * Deliberately an allowlist of exact hostnames plus loopback. No suffix matching:\n * a rule like \"anything ending in salla.design\" is one wildcard DNS record away\n * from admitting a host nobody meant to admit, and the list of hosts that serve\n * more than one store is short and known.\n *\n * It gates {@link resolveRequestVersionId} as well, and the name has been left\n * alone rather than generalised because one predicate that both call is the\n * property worth keeping — a second, subtly different list is how a host ends up\n * permitted to name one thing and not the other. A version is worth gating for\n * the same reason a store is: on a merchant's own domain, honouring\n * `?versionId=` would publish whatever draft settings they are still working on\n * to anyone who guessed the URL.\n */\nexport function allowsRequestStoreId(host: string | null | undefined): boolean {\n if (!host) return false;\n const hostname = hostnameOf(host);\n return STORE_ID_HOSTS.includes(hostname) || isLoopback(hostname);\n}\n\n/**\n * Whether this host *is* a store, so its name can be used as the identifier.\n *\n * The exact inverse of {@link allowsRequestStoreId}, and deliberately written as\n * one so the two can never disagree: a host that may name its store is a host\n * that serves more than one, and a host that serves more than one cannot be the\n * answer to \"which store is this?\". `preview.salla.design` and `localhost:5188`\n * are not shops; asking the API about them earns a 422 and a page that reads as\n * a broken theme.\n */\nexport function hostIdentifiesStore(host: string | null | undefined): boolean {\n return Boolean(host) && !allowsRequestStoreId(host);\n}\n\n/**\n * The store this request names, on a host permitted to name one.\n *\n * The host check is inside the resolution rather than at a call site, because a\n * call site is a thing someone can add without reading this comment. There is no\n * way to ask \"what store did the request name?\" without also asking \"is this a\n * host that may say?\" — get it wrong and the answer is a security bug that looks\n * like a feature.\n *\n * Between the two permitted sources the URL wins, the same precedence the\n * dispatcher uses for the theme and for the same reason: a link is how someone\n * switches, and a cookie they cannot see should never beat the address they\n * just typed.\n */\nexport function resolveRequestStoreId(\n url: string,\n cookieHeader: string | null,\n host: string | null | undefined\n): string | null {\n return resolveRequestId(url, cookieHeader, host, STORE_ID_PARAM, STORE_ID_COOKIE_NAME);\n}\n\n/**\n * A store username as it can appear as the first segment of a path.\n *\n * Starts with a letter or digit, so nothing the platform mounts at the root of a\n * host — `/_serverFn/`, `/.well-known/` — is ever read as a store. Dots are allowed\n * (`zyros.sa`), but a root file (`/favicon.ico`, `/robots.txt`) is not a store.\n * The value is sent upstream as the `store-identifier` header, so the set is kept\n * narrow on purpose: a username outside it cannot be addressed by path, and\n * `?storeId=` still can.\n */\nconst STORE_BASE_SEGMENT = /^[a-z0-9][a-z0-9._-]{0,62}$/i;\nconst ROOT_FILE =\n /\\.(ico|txt|xml|json|webmanifest|html?|js|mjs|css|map|png|jpe?g|gif|svg|webp|avif|woff2?|ttf|otf|eot|pdf|mp4|webm|wasm)$/i;\n\n/**\n * Whether this could be a store's username in the first segment of a path.\n *\n * A supported locale code never is, in any case: `/ar` and `/EN` are languages,\n * so `preview.salla.design/en/cart` is the English cart of the store the cookie\n * names. That makes a store whose username is a locale code (`ar` is one)\n * unreachable by path; `?storeId=` still reaches it.\n *\n * The same predicate decides whether a username may become a path's root\n * (`storeBaseRedirectHref`). That is what stops the redirect from looping: a\n * store called `ar`, sent to `/ar/…`, would find no store there and be sent again.\n */\nexport function isStoreBaseSegment(value: string | null | undefined): value is string {\n return (\n typeof value === 'string' &&\n STORE_BASE_SEGMENT.test(value) &&\n !ROOT_FILE.test(value) &&\n !isLocale(value.toLowerCase())\n );\n}\n\n/**\n * The store the first segment of this request's path names, on a host permitted\n * to name one.\n *\n * On such a host the first segment **is** the store. It is the root of the\n * application there, so `https://preview.salla.design/mtgr-alaatr-2/cart` is the\n * cart of the store whose username is `mtgr-alaatr-2`. This is a rule rather than\n * a guess, and it has to be: `cart`, `offers` and `search` are all real store\n * usernames, so a store cannot be told from a page by looking at the segment.\n * `/cart` on these hosts is the store called `cart`.\n *\n * The one segment that is not a store is a supported locale code (see\n * {@link isStoreBaseSegment}). `/ar/cart` names a language, and the store comes\n * from the cookie or `VITE_STORE_DOMAIN`, as it would at `/`.\n *\n * A URL that carries `storeId` is not read this way at all, whatever its value.\n * That is how `salla theme dev` names a store (`/ar?storeId=…`), on a path that\n * begins with a page; the root loader then redirects to the store's own address.\n * Checking for a *valid* id instead would let a malformed one hand the page's\n * first segment the store's job. (On the preview host the dispatcher removes the\n * parameter and sends a cookie; the editor opens that host at `/`, where there is\n * no segment to read.)\n *\n * Same gate as {@link resolveRequestStoreId}, for the same reason: on a merchant's\n * own domain the hostname is the store and the path is only ever a page.\n */\nexport function resolveRequestStoreBase(\n url: string,\n host: string | null | undefined\n): string | null {\n if (!allowsRequestStoreId(host)) return null;\n\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n if (parsed.searchParams.has(STORE_ID_PARAM)) return null;\n\n const first = parsed.pathname.split('/')[1];\n return isStoreBaseSegment(first) ? first : null;\n}\n\n/** Which store a request addressed, and how. At most one of the two is set. */\nexport interface RequestStore {\n /** Named by `?storeId=`, or by the cookie remembering it. */\n storeId: string | null;\n /** Named by the first segment of the path. */\n storeBase: string | null;\n}\n\n/**\n * The store this request addressed: the query, then the path, then the cookie.\n *\n * The path outranks the cookie because it is the address the visitor can see.\n * The cookie is one value for the whole preview host, so with two stores open in\n * two tabs it names whichever was opened last; the path names the one in front\n * of them.\n */\nexport function resolveRequestStore(\n url: string,\n cookieHeader: string | null,\n host: string | null | undefined\n): RequestStore {\n const storeBase = resolveRequestStoreBase(url, host);\n return {\n storeBase,\n storeId: storeBase ? null : resolveRequestStoreId(url, cookieHeader, host),\n };\n}\n\n/**\n * The theme-settings version this request names, on a host permitted to name one.\n *\n * Same shape and the same host gate as {@link resolveRequestStoreId}, deliberately:\n * both answer \"what did this request ask to be shown?\", both are reached only on\n * a host that serves more than one thing, and a version that could be named where\n * a store could not would be a second rule to keep in step with the first.\n *\n * Null is the ordinary answer, and it is not a failure — it means nothing\n * addressed a version, so the store's own live one is what gets rendered.\n */\nexport function resolveRequestVersionId(\n url: string,\n cookieHeader: string | null,\n host: string | null | undefined\n): string | null {\n return resolveRequestId(url, cookieHeader, host, VERSION_ID_PARAM, VERSION_ID_COOKIE_NAME);\n}\n\n/**\n * The id this request names, from the query first and the cookie after.\n *\n * The host check lives here rather than at either call site, for the reason the\n * two wrappers above are wrappers at all: there must be no way to ask what a\n * request named without also asking whether this host may say.\n */\nfunction resolveRequestId(\n url: string,\n cookieHeader: string | null,\n host: string | null | undefined,\n param: string,\n cookieName: string\n): string | null {\n if (!allowsRequestStoreId(host)) return null;\n\n let fromQuery: string | null = null;\n try {\n fromQuery = parseRequestId(new URL(url).searchParams.get(param));\n } catch {\n /* a relative or malformed URL simply names nothing */\n }\n return fromQuery ?? parseRequestId(extractTokenFromCookies(cookieHeader, cookieName));\n}\n\n/**\n * Deletes the auth `token` cookie. This cookie is written client-side by the theme\n * (TwilightProvider), not by the SDK — `salla.cookie.clearAll()` only clears its own\n * allowlist and leaves `token` behind — so logout must clear it here. Client-only.\n */\n/**\n * On a dev server, remembers the store the page is showing, so a later URL that\n * names no store keeps it instead of falling back to `VITE_STORE_DOMAIN`.\n * Loopback only: on the preview host this cookie belongs to the dispatcher. Client-only.\n */\nexport function rememberDevStoreId(id: string | number | null | undefined): void {\n if (typeof document === 'undefined' || !isLoopback(window.location.hostname)) return;\n const storeId = parseStoreId(id == null ? null : String(id));\n if (storeId) document.cookie = `${STORE_ID_COOKIE_NAME}=${storeId}; path=/; SameSite=Lax`;\n}\n\nexport function clearAuthTokenCookie(): void {\n if (typeof document === 'undefined') return;\n document.cookie = `${AUTH_TOKEN_COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n}\n\nexport function extractTokenFromCookies(\n cookieHeader: string | null,\n cookieName: string\n): string | null {\n if (!cookieHeader) return null;\n\n const prefix = `${cookieName}=`;\n let start = 0;\n\n while (start < cookieHeader.length) {\n const idx = cookieHeader.indexOf(prefix, start);\n if (idx === -1) return null;\n\n const prevChar = idx > 0 ? cookieHeader[idx - 1] : '';\n if (prevChar === '' || prevChar === ';' || prevChar === ' ') {\n let end = cookieHeader.indexOf(';', idx);\n if (end === -1) end = cookieHeader.length;\n\n const value = cookieHeader.slice(idx + prefix.length, end).trim();\n try {\n return decodeURIComponent(value) || null;\n } catch {\n return value || null;\n }\n }\n\n start = idx + prefix.length;\n }\n\n return null;\n}\n\n/**\n * The scope the Salla SDK persists as `scope`: the market (`id`/`type`) plus, once\n * bullet delivery confirms an address or branch, the allocation. The SDK sends all\n * four as request headers (`s-scope-id`, `s-scope-type`, `s-scope-allocation-type`,\n * `s-scope-allocation-id`) and the API resolves stock per allocation — a scope sent\n * without its allocation is a different question, answered from a different branch.\n */\nexport interface ActiveScope {\n id: string;\n type?: string;\n allocation_type?: string;\n allocation_id?: string;\n}\n\n/** The SDK stores the scope either as its full object or as a bare id. */\nfunction normalizeScope(raw: unknown): ActiveScope | null {\n if (raw == null) return null;\n if (typeof raw !== 'object') return { id: String(raw) };\n const s = raw as Record<string, unknown>;\n if (s.id == null) return null;\n const scope: ActiveScope = { id: String(s.id) };\n if (s.type != null) scope.type = String(s.type);\n if (s.allocation_type != null) scope.allocation_type = String(s.allocation_type);\n if (s.allocation_id != null) scope.allocation_id = String(s.allocation_id);\n return scope;\n}\n\n/**\n * Reads the active scope from the `scope` cookie, which Salla persists as a JSON\n * object (e.g. `{\"id\":123,\"type\":\"scope\",\"allocation_type\":\"branch\",\"allocation_id\":\"9\"}`).\n * Returns null when the cookie is missing or unparseable. Used server-side, where\n * `salla.storage` is absent.\n */\nexport function extractScopeFromCookies(cookieHeader: string | null): ActiveScope | null {\n const raw = extractTokenFromCookies(cookieHeader, SCOPE_COOKIE_NAME);\n if (!raw) return null;\n try {\n return normalizeScope(JSON.parse(raw));\n } catch {\n return null;\n }\n}\n\n/** {@link extractScopeFromCookies} reduced to the id. */\nexport function extractScopeIdFromCookies(cookieHeader: string | null): string | null {\n return extractScopeFromCookies(cookieHeader)?.id ?? null;\n}\n\n/**\n * The scope the Salla SDK persisted in its storage (`salla.storage.get('scope')`).\n *\n * Returns `undefined` when the SDK storage API isn't ready yet — deliberately\n * distinct from `null` (\"no branch selected\"), so callers can't mistake a\n * not-yet-hydrated SDK for a cleared selection. Client-only.\n */\nexport function readSdkScope(): ActiveScope | null | undefined {\n const storage = typeof window !== 'undefined' ? window.salla?.storage : undefined;\n if (typeof storage?.get !== 'function') return undefined;\n return normalizeScope(storage.get(SCOPE_COOKIE_NAME));\n}\n\n/** {@link readSdkScope} reduced to the id; keeps the not-ready/none distinction. */\nexport function readSdkScopeId(): string | null | undefined {\n const scope = readSdkScope();\n return scope === undefined ? undefined : (scope?.id ?? null);\n}\n\n/** One year — the SDK keeps the selected branch in localStorage indefinitely. */\nconst SCOPE_COOKIE_MAX_AGE = 60 * 60 * 24 * 365;\n\nconst sameScope = (a: ActiveScope | null, b: ActiveScope | null): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * Mirrors the scope the Salla SDK selected into the `scope` cookie so the SERVER\n * can see it. The SDK persists the selection in localStorage ONLY and writes no\n * cookie, so without this the server computes scope=null for every visitor who\n * picked a branch while the client computes the branch id — the dehydrated settings\n * query key never matches and the client refetches store settings on every page\n * load (SAL-122).\n *\n * Written in the SDK's own JSON shape so {@link extractScopeFromCookies} parses it,\n * allocation included: the bullet-delivery component writes the same cookie with the\n * full object, and rewriting it with the id alone would drop the branch the server\n * needs. Returns true when the cookie was (re)written. Client-only; no-op on the server.\n */\nexport function writeScopeCookie(scope: ActiveScope | null): boolean {\n if (typeof document === 'undefined') return false;\n if (sameScope(extractScopeFromCookies(document.cookie), scope)) return false;\n\n if (scope == null) {\n document.cookie = `${SCOPE_COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n return true;\n }\n\n const value = encodeURIComponent(JSON.stringify(scope));\n document.cookie = `${SCOPE_COOKIE_NAME}=${value}; path=/; max-age=${SCOPE_COOKIE_MAX_AGE}; samesite=lax`;\n return true;\n}\n\n/**\n * Keeps the `scope` cookie in step with the SDK's selected branch. Call on every\n * client navigation; it no-ops while the SDK storage API is still hydrating so a\n * late-loading SDK can't wipe a valid cookie.\n */\nexport function syncScopeCookie(): boolean {\n const scope = readSdkScope();\n return scope === undefined ? false : writeScopeCookie(scope);\n}\n","/**\n * @fileoverview Paths on a host where the store is the root.\n *\n * On `preview.salla.design` and a dev server a store is addressed by the first\n * segment of the path — `/mtgr-alaatr-2/cart` — and that segment is the root of\n * the application. No route knows about it: the router takes it off every URL on\n * the way in and puts it back on every URL on the way out\n * (`tanstack/store-base.ts`), so pages, links and loaders all see `/cart`.\n *\n * Which segment it is, and on which hosts, is decided once, by\n * `resolveRequestStoreBase` in `utils/cookies.ts`. This file only moves it on and\n * off a path. See `docs/store-base-path.md`.\n */\nimport { allowsRequestStoreId, isStoreBaseSegment, STORE_ID_PARAM } from './cookies';\nimport { isLocale } from '../providers/locale-constants';\n\n/**\n * An application pathname, without the store segment in front.\n *\n * Only a whole segment is removed, so `/mtgr-alaatr-2x/cart` is left alone, and a\n * pathname that does not start with the segment comes back unchanged.\n */\nexport function stripStoreBase(pathname: string, base: string): string {\n const prefix = `/${base}`;\n if (pathname === prefix) return '/';\n return pathname.startsWith(`${prefix}/`) ? pathname.slice(prefix.length) : pathname;\n}\n\n/**\n * An application path as the browser addresses it, with the store segment in front.\n *\n * It never checks whether the segment is already there, because that cannot be\n * told apart from a page of the same name: a store called `cart` keeps its cart at\n * `/cart/cart`. Callers pass application paths only.\n */\nexport function prefixStoreBase(path: string, base: string): string {\n const rooted = path.startsWith('/') ? path : `/${path}`;\n // The store's root is `/<base>`, not `/<base>/`, with or without a query or hash.\n const atRoot = rooted === '/' || rooted[1] === '?' || rooted[1] === '#';\n return `/${base}${atRoot ? rooted.slice(1) : rooted}`;\n}\n\n/**\n * A pathname from a link the Salla API handed out, without the store's username in it.\n *\n * A store with no domain of its own is served under its username on a shared host,\n * and every URL the API returns for it carries that segment. Its `store.url` is\n * `/{lang}/{username}/` when the store is multilingual and `/{username}/` when it is\n * not: `https://demostore.salla.sa/ar/dev-vgckq3fssfhjewwi/`, `https://salla.sa/cart/`.\n * The segment there belongs to Salla's host, not to the application. Left in, it\n * lands where a page slug is expected and matches no route.\n *\n * The username is the last segment of `store.url`, but only when it equals the\n * store's username. Neither its position nor its spelling says so on its own: `/ar/`\n * is the locale of `https://3tir.com/ar/`, a store on its own domain whose links carry\n * no username, and it is also the whole address of the store called `ar`,\n * `https://salla.sa/ar/`. Without a username to compare against, a last segment\n * spelled like a locale is taken to be one, which is wrong only for a store whose\n * username is a locale code.\n *\n * The locale stays wherever the link put it.\n */\nexport function withoutStoreUrlBase(\n pathname: string,\n storeUrlPathname: string,\n username?: string | null\n): string {\n const own = storeUrlSegment(storeUrlPathname, username);\n if (!own) return pathname;\n\n const segments = pathname.split('/');\n // Salla puts the locale first (`/ar/dev-x/…`); a store that is not multilingual has\n // none (`/dev-x/…`). Checked in that order, `/ar/ar/…` for a store called `ar` keeps\n // its locale.\n let at = -1;\n if (isLocale(segments[1]) && segments[2] === own) at = 2;\n else if (segments[1] === own) at = 1;\n if (at === -1) return pathname;\n\n segments.splice(at, 1);\n return segments.join('/') || '/';\n}\n\n/**\n * Whether a pathname on the store's host is this store's.\n *\n * On a shared host the origin belongs to every store there, and a link names its store\n * by the username in its path, where {@link withoutStoreUrlBase} looks for it. One\n * without it is another store's page, or the host's own. A store on its own domain has\n * no such segment, and every path on its host is its own.\n */\nexport function hasStoreUrlBase(\n pathname: string,\n storeUrlPathname: string,\n username?: string | null\n): boolean {\n const own = storeUrlSegment(storeUrlPathname, username);\n if (!own) return true;\n\n const segments = pathname.split('/');\n return segments[1] === own || (isLocale(segments[1]) && segments[2] === own);\n}\n\n/** The segment `store.url` serves the store under, or null when it has none. */\nfunction storeUrlSegment(storeUrlPathname: string, username?: string | null): string | null {\n const last = storeUrlPathname.split('/').filter(Boolean).pop();\n if (!last) return null;\n if (username) return last === username ? last : null;\n return isLocale(last) ? null : last;\n}\n\n/**\n * Where to send a page whose store was not named by its own first segment, or null\n * when it already was.\n *\n * On a host where the store is the root, every page has one address,\n * `/<username>/…`. A request that found its store some other way (`?storeId=`, the\n * preview cookie, `VITE_STORE_DOMAIN`, or a first segment that named the store by\n * another spelling, such as its numeric id) is sent there once the store's settings\n * say what its username is.\n *\n * `storeId` is dropped from the query on the way. It has to be: a URL carrying it\n * is never read for a store segment, so keeping it would redirect to an address\n * that redirects again, forever. For the same reason a username that could not be\n * read back out of a path produces no redirect at all.\n *\n * `href` is the application's own href (path, query and hash, already without any\n * store segment), which the router keeps percent-encoded, so the result is safe to\n * put in a `Location` header.\n */\nexport function storeBaseRedirectHref(args: {\n host: string | null | undefined;\n base: string | null;\n username: string | null | undefined;\n href: string;\n}): string | null {\n const { host, base, username, href } = args;\n if (!allowsRequestStoreId(host) || !isStoreBaseSegment(username) || username === base) {\n return null;\n }\n\n const url = new URL(href, 'http://store-base.invalid');\n url.searchParams.delete(STORE_ID_PARAM);\n return `${prefixStoreBase(url.pathname, username)}${url.search}${url.hash}`;\n}\n\n/**\n * Where to send a guest who opened a customer-only page: the locale's home with\n * `intended_to`, which the SDK reads to open the login modal and come back after.\n * Null when already there, so the redirect cannot loop.\n */\nexport function loginRedirectHref(args: {\n pathname: string;\n searchStr: string;\n origin: string;\n base: string | null;\n}): string | null {\n const { pathname, searchStr, origin, base } = args;\n const first = pathname.split('/')[1];\n const home = isLocale(first) ? `/${first}` : '/';\n if ((pathname.replace(/\\/$/, '') || '/') === home) return null;\n\n const browserPath = (path: string) => (base ? prefixStoreBase(path, base) : path);\n const intended = `${origin}${browserPath(pathname)}${searchStr}`;\n return `${browserPath(home)}?intended_to=${encodeURIComponent(intended)}`;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { isNativeApp } from './chunk-3IHFA2X5.js';
1
2
  import { useTwilight } from './chunk-DF6FBKDN.js';
2
3
  import { useRef, useState, useEffect } from 'react';
3
4
  import { toast, Toaster as Toaster$1 } from 'sonner';
@@ -19,7 +20,7 @@ var MOBILE_BREAKPOINT = 768;
19
20
  var NATIVE_ALERT_EVENT = "ui::alert";
20
21
  function dispatchNativeAlert(type, message, title) {
21
22
  const salla = window.salla;
22
- if (!salla?.mobile?.isEnabled?.() || !salla.event?.dispatch) return false;
23
+ if (!isNativeApp() || !salla?.event?.dispatch) return false;
23
24
  salla.event.dispatch(NATIVE_ALERT_EVENT, {
24
25
  type,
25
26
  message,
@@ -136,5 +137,5 @@ function Toaster({
136
137
  }
137
138
 
138
139
  export { Toaster };
139
- //# sourceMappingURL=chunk-SVPXQCOA.js.map
140
- //# sourceMappingURL=chunk-SVPXQCOA.js.map
140
+ //# sourceMappingURL=chunk-MISI3T6V.js.map
141
+ //# sourceMappingURL=chunk-MISI3T6V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/toast/Toaster.tsx"],"names":["SonnerToaster"],"mappings":"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","file":"chunk-MISI3T6V.js","sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { Toaster as SonnerToaster, toast } from 'sonner';\nimport { useTwilight } from '../../providers/twilight-context';\nimport { isNativeApp } from '../../native-app';\nimport type { ToastPosition } from './types';\n\nconst toastClassNames = {\n toast: 'group bg-white border-2 rounded-xl shadow-2xl p-4 font-primary',\n title: 'text-base font-bold',\n description: 'text-sm mt-1 text-gray-600',\n actionButton: 'bg-primary text-white px-3 py-1 rounded',\n cancelButton: 'bg-gray-100 px-3 py-1 rounded',\n success: 'border-green-500 [&_svg]:text-green-500 [&_aside]:text-green-700',\n error: 'border-red-500 [&_svg]:text-red-500 [&_aside]:text-red-700',\n warning: 'border-yellow-500 [&_svg]:text-yellow-500 [&_aside]:text-yellow-700',\n info: 'border-blue-500 [&_svg]:text-blue-500 [&_aside]:text-blue-700',\n loading: 'border-gray-400',\n};\n\ntype RawMessage = string | { title?: string; text?: string; icon?: string };\ntype ToastVariant = 'success' | 'error' | 'warning' | 'info';\n\nconst MOBILE_BREAKPOINT = 768;\nconst NATIVE_ALERT_EVENT = 'ui::alert';\n\nfunction dispatchNativeAlert(type: ToastVariant, message: string, title?: string) {\n const salla = window.salla;\n if (!isNativeApp() || !salla?.event?.dispatch) return false;\n\n salla.event.dispatch(NATIVE_ALERT_EVENT, {\n type,\n message,\n ...(title ? { title } : {}),\n });\n return true;\n}\n\nexport function Toaster({\n mobilePosition = 'bottom-center',\n addToCartToast = true,\n}: {\n mobilePosition?: ToastPosition;\n /** Show the default add-to-cart toast. Themes whose cart badge is the feedback can turn it off. */\n addToCartToast?: boolean;\n}) {\n const { theme } = useTwilight();\n const themeRef = useRef(theme);\n themeRef.current = theme;\n const flashShownRef = useRef(false);\n\n const isRtl = theme.is_rtl;\n const desktopPosition: ToastPosition = isRtl ? 'top-left' : 'top-right';\n\n const [position, setPosition] = useState<ToastPosition>(() => {\n if (typeof window === 'undefined') return desktopPosition;\n return window.innerWidth < MOBILE_BREAKPOINT ? mobilePosition : desktopPosition;\n });\n\n useEffect(() => {\n const handleResize = () => {\n setPosition(window.innerWidth < MOBILE_BREAKPOINT ? mobilePosition : desktopPosition);\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [desktopPosition, mobilePosition]);\n\n useEffect(() => {\n const salla = window.salla;\n if (!salla) return;\n let active = true;\n\n const handleNotify = (message: RawMessage, type: string, data?: unknown) => {\n const eventData = data as { data?: { googleTags?: { event?: string } } } | undefined;\n const shouldSuppressAddToCartToast =\n (!addToCartToast || themeRef.current.settings?.enable_add_product_toast) &&\n eventData?.data?.googleTags?.event === 'addToCart';\n let title: string;\n let toastType: ToastVariant;\n\n if (typeof message === 'object' && message !== null) {\n title = message.title || message.text || '';\n toastType = (message.icon || type || 'info') as ToastVariant;\n } else {\n title = message;\n toastType = (type || 'info') as ToastVariant;\n }\n\n // Suppress the default addToCart toast when the theme opted out (addToCartToast=false)\n // or renders its own rich toast (enable_add_product_toast) so they don't double up.\n if (shouldSuppressAddToCartToast) {\n return;\n }\n\n if (dispatchNativeAlert(toastType, title)) {\n return;\n }\n\n if (toastType === 'success') {\n toast.success(title, { duration: 3000 });\n } else if (toastType === 'error') {\n toast.error(title, { duration: 3000 });\n } else if (toastType === 'warning') {\n toast.warning(title, { duration: 3000 });\n } else {\n toast.info(title, { duration: 3000 });\n }\n };\n\n // Before the SDK loads `salla` is the head stub, and the SDK's default notifier is alert().\n void (async () => {\n try {\n await salla.onReady?.();\n } catch {\n // onReady() may fail during partial initialization; the toast still beats alert().\n }\n if (active) salla.notify?.setNotifier?.(handleNotify);\n })();\n return () => {\n active = false;\n salla.notify?.setNotifier?.(() => {});\n };\n }, [addToCartToast]);\n\n useEffect(() => {\n if (flashShownRef.current || typeof window === 'undefined') return;\n\n const params = new URLSearchParams(window.location.search);\n const successMsg = params.get('success');\n const dangerMsg = params.get('danger');\n\n if (!successMsg && !dangerMsg) return;\n\n flashShownRef.current = true;\n\n const message = successMsg || dangerMsg || '';\n const toastType = dangerMsg ? 'error' : 'success';\n\n const url = new URL(window.location.href);\n url.searchParams.delete('success');\n url.searchParams.delete('danger');\n window.history.replaceState({}, '', url.toString());\n\n const timer = setTimeout(() => {\n if (dispatchNativeAlert(toastType, message)) return;\n\n if (toastType === 'success') {\n toast.success(message, { duration: 3000 });\n } else {\n toast.error(message, { duration: 3000 });\n }\n }, 100);\n\n return () => clearTimeout(timer);\n }, []);\n\n return (\n <SonnerToaster\n position={position}\n // Keep sonner's default gaps (24px desktop / 16px mobile) but clear the\n // native status bar inset (--app-safe-area-top, set by useSafeAreaInset)\n // so top-positioned toasts aren't covered in the app webview.\n offset={{ top: 'calc(var(--app-safe-area-top, 0px) + 24px)' }}\n mobileOffset={{ top: 'calc(var(--app-safe-area-top, 0px) + 16px)' }}\n toastOptions={{\n classNames: toastClassNames,\n style: {\n fontFamily: 'var(--font-main, inherit)',\n },\n }}\n style={{\n fontFamily: 'var(--font-main, inherit)',\n }}\n />\n );\n}\n\nexport type { ToasterProps } from 'sonner';\n"]}
@@ -1,5 +1,5 @@
1
- import { orThrow, orUnauthorized } from './chunk-SSPAMQRV.js';
2
- import { api } from './chunk-IKUDCH7Q.js';
1
+ import { orThrow, orUnauthorized } from './chunk-SDIQHTDG.js';
2
+ import { api } from './chunk-VX2T7JCB.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  var order = {
@@ -78,5 +78,5 @@ var order = {
78
78
  };
79
79
 
80
80
  export { order };
81
- //# sourceMappingURL=chunk-TRZAQSHU.js.map
82
- //# sourceMappingURL=chunk-TRZAQSHU.js.map
81
+ //# sourceMappingURL=chunk-MSUGP566.js.map
82
+ //# sourceMappingURL=chunk-MSUGP566.js.map