@salla.sa/twilight-theme-engine 1.0.130 → 1.0.131

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 (228) hide show
  1. package/dist/{AddToCartForm-ZJIIU4I4.js → AddToCartForm-S73TIRFL.js} +3 -3
  2. package/dist/{AddToCartForm-ZJIIU4I4.js.map → AddToCartForm-S73TIRFL.js.map} +1 -1
  3. package/dist/{BlogAuthorPage-DNZSR42D.js → BlogAuthorPage-ISOONUBI.js} +17 -17
  4. package/dist/{BlogAuthorPage-DNZSR42D.js.map → BlogAuthorPage-ISOONUBI.js.map} +1 -1
  5. package/dist/{BlogCategoryPage-AC4DDQ7N.js → BlogCategoryPage-3CEQWDB7.js} +17 -17
  6. package/dist/{BlogCategoryPage-AC4DDQ7N.js.map → BlogCategoryPage-3CEQWDB7.js.map} +1 -1
  7. package/dist/{BlogPage-F5OY24RP.js → BlogPage-AYYUM3GY.js} +15 -15
  8. package/dist/{BlogPage-F5OY24RP.js.map → BlogPage-AYYUM3GY.js.map} +1 -1
  9. package/dist/{BlogSinglePage-YXC5WU3N.js → BlogSinglePage-NH7RZVLA.js} +15 -15
  10. package/dist/{BlogSinglePage-YXC5WU3N.js.map → BlogSinglePage-NH7RZVLA.js.map} +1 -1
  11. package/dist/{BlogTagPage-6QQ2CF2B.js → BlogTagPage-LONJWWDW.js} +17 -17
  12. package/dist/{BlogTagPage-6QQ2CF2B.js.map → BlogTagPage-LONJWWDW.js.map} +1 -1
  13. package/dist/{BrandsPage-UXWNTTT3.js → BrandsPage-DTV4FJBP.js} +16 -16
  14. package/dist/{BrandsPage-UXWNTTT3.js.map → BrandsPage-DTV4FJBP.js.map} +1 -1
  15. package/dist/{Breadcrumb-TUXEVRZZ.js → Breadcrumb-JCEPGH5A.js} +15 -15
  16. package/dist/{Breadcrumb-TUXEVRZZ.js.map → Breadcrumb-JCEPGH5A.js.map} +1 -1
  17. package/dist/{CartItem-B7AYUFGZ.js → CartItem-NTIU45BB.js} +15 -15
  18. package/dist/{CartItem-B7AYUFGZ.js.map → CartItem-NTIU45BB.js.map} +1 -1
  19. package/dist/{CartSummary-LSFD7QUY.js → CartSummary-GETYV24Q.js} +15 -15
  20. package/dist/{CartSummary-LSFD7QUY.js.map → CartSummary-GETYV24Q.js.map} +1 -1
  21. package/dist/{Copyright-HH2S2KDM.js → Copyright-W7RY445F.js} +3 -3
  22. package/dist/{Copyright-HH2S2KDM.js.map → Copyright-W7RY445F.js.map} +1 -1
  23. package/dist/{CustomerLayout-2NVQ6G72.js → CustomerLayout-P5QZJDMR.js} +15 -15
  24. package/dist/{CustomerLayout-2NVQ6G72.js.map → CustomerLayout-P5QZJDMR.js.map} +1 -1
  25. package/dist/{Footer-4LQIBAHJ.js → Footer-GANB36WN.js} +4 -4
  26. package/dist/{Footer-4LQIBAHJ.js.map → Footer-GANB36WN.js.map} +1 -1
  27. package/dist/{Header-VQTPIQPS.js → Header-IZ3UWIEO.js} +8 -8
  28. package/dist/{Header-VQTPIQPS.js.map → Header-IZ3UWIEO.js.map} +1 -1
  29. package/dist/{LiveEditorBar-DOSRO35J.js → LiveEditorBar-4AWOAJYX.js} +58 -9
  30. package/dist/LiveEditorBar-4AWOAJYX.js.map +1 -0
  31. package/dist/{LoyaltyPage-NSHSLS4O.js → LoyaltyPage-BNJO3BTK.js} +15 -15
  32. package/dist/{LoyaltyPage-NSHSLS4O.js.map → LoyaltyPage-BNJO3BTK.js.map} +1 -1
  33. package/dist/{LoyaltyPointsPage-7CUUKDLR.js → LoyaltyPointsPage-2OGOGII3.js} +6 -6
  34. package/dist/{LoyaltyPointsPage-7CUUKDLR.js.map → LoyaltyPointsPage-2OGOGII3.js.map} +1 -1
  35. package/dist/{MainMenu-NTSSUK6R.js → MainMenu-56OTUHET.js} +5 -5
  36. package/dist/{MainMenu-NTSSUK6R.js.map → MainMenu-56OTUHET.js.map} +1 -1
  37. package/dist/{MasterLayout-ZOT7XICQ.js → MasterLayout-DWXUEODB.js} +15 -15
  38. package/dist/{MasterLayout-ZOT7XICQ.js.map → MasterLayout-DWXUEODB.js.map} +1 -1
  39. package/dist/{MobileMenu-RBTT3KLS.js → MobileMenu-JJA7PHVS.js} +16 -16
  40. package/dist/{MobileMenu-RBTT3KLS.js.map → MobileMenu-JJA7PHVS.js.map} +1 -1
  41. package/dist/{NotificationsPage-T775PMFX.js → NotificationsPage-L57HNZRC.js} +15 -15
  42. package/dist/{NotificationsPage-T775PMFX.js.map → NotificationsPage-L57HNZRC.js.map} +1 -1
  43. package/dist/{OrderSinglePage-T5SKWUNW.js → OrderSinglePage-5FWWZ4TJ.js} +16 -16
  44. package/dist/{OrderSinglePage-T5SKWUNW.js.map → OrderSinglePage-5FWWZ4TJ.js.map} +1 -1
  45. package/dist/{OrdersPage-PGAD6DDY.js → OrdersPage-AE674QJO.js} +15 -15
  46. package/dist/{OrdersPage-PGAD6DDY.js.map → OrdersPage-AE674QJO.js.map} +1 -1
  47. package/dist/{PageSingle-6W7U5YLG.js → PageSingle-N5G42IIX.js} +3 -3
  48. package/dist/{PageSingle-6W7U5YLG.js.map → PageSingle-N5G42IIX.js.map} +1 -1
  49. package/dist/{ProductDetails-JFOFLMLV.js → ProductDetails-FWN3T7H7.js} +4 -4
  50. package/dist/{ProductDetails-JFOFLMLV.js.map → ProductDetails-FWN3T7H7.js.map} +1 -1
  51. package/dist/{ProfilePage-2HZYDJBM.js → ProfilePage-BXZJY55Z.js} +15 -15
  52. package/dist/{ProfilePage-2HZYDJBM.js.map → ProfilePage-BXZJY55Z.js.map} +1 -1
  53. package/dist/{ReviewsPage-FYAZU7FT.js → ReviewsPage-A7OXTEXY.js} +3 -3
  54. package/dist/{ReviewsPage-FYAZU7FT.js.map → ReviewsPage-A7OXTEXY.js.map} +1 -1
  55. package/dist/{SeoCartWidget-7SUVC6MT.js → SeoCartWidget-N3MOUSW7.js} +15 -15
  56. package/dist/{SeoCartWidget-7SUVC6MT.js.map → SeoCartWidget-N3MOUSW7.js.map} +1 -1
  57. package/dist/{SettingsPage-IBWVB4ZJ.js → SettingsPage-DFHGU5OH.js} +15 -15
  58. package/dist/{SettingsPage-IBWVB4ZJ.js.map → SettingsPage-DFHGU5OH.js.map} +1 -1
  59. package/dist/{StoreClosedNotification-CMOHA4LU.js → StoreClosedNotification-GNSQYWDS.js} +16 -16
  60. package/dist/{StoreClosedNotification-CMOHA4LU.js.map → StoreClosedNotification-GNSQYWDS.js.map} +1 -1
  61. package/dist/{TestimonialsPage-WJMIDBRM.js → TestimonialsPage-26OBKQAG.js} +3 -3
  62. package/dist/{TestimonialsPage-WJMIDBRM.js.map → TestimonialsPage-26OBKQAG.js.map} +1 -1
  63. package/dist/{ThankYouPage-NILOPG4H.js → ThankYouPage-7C3OC6P5.js} +15 -15
  64. package/dist/{ThankYouPage-NILOPG4H.js.map → ThankYouPage-7C3OC6P5.js.map} +1 -1
  65. package/dist/{WalletPage-5O553SIT.js → WalletPage-RA354UQQ.js} +16 -16
  66. package/dist/{WalletPage-5O553SIT.js.map → WalletPage-RA354UQQ.js.map} +1 -1
  67. package/dist/{WishlistPage-JPLKEMDX.js → WishlistPage-NTJW33VF.js} +17 -17
  68. package/dist/{WishlistPage-JPLKEMDX.js.map → WishlistPage-NTJW33VF.js.map} +1 -1
  69. package/dist/api/advertisement.js +2 -2
  70. package/dist/api/apps.js +2 -2
  71. package/dist/api/blog.js +3 -3
  72. package/dist/api/brands.js +3 -3
  73. package/dist/api/cart.js +3 -3
  74. package/dist/api/category.js +3 -3
  75. package/dist/api/client.js +1 -1
  76. package/dist/api/home.js +2 -2
  77. package/dist/api/loyalty.js +3 -3
  78. package/dist/api/menu.js +2 -2
  79. package/dist/api/notification.js +2 -2
  80. package/dist/api/order.js +3 -3
  81. package/dist/api/page.js +3 -3
  82. package/dist/api/product.js +3 -3
  83. package/dist/api/profile.js +1 -1
  84. package/dist/api/store.js +2 -2
  85. package/dist/api/translations.js +2 -2
  86. package/dist/api/user.js +2 -2
  87. package/dist/api/wallet.js +2 -2
  88. package/dist/api/wishlist.js +4 -4
  89. package/dist/{chunk-WYWI77EA.js → chunk-2Z7XKCT3.js} +3 -3
  90. package/dist/{chunk-WYWI77EA.js.map → chunk-2Z7XKCT3.js.map} +1 -1
  91. package/dist/{chunk-AN2PETFM.js → chunk-3FXRE7JW.js} +6 -6
  92. package/dist/{chunk-AN2PETFM.js.map → chunk-3FXRE7JW.js.map} +1 -1
  93. package/dist/{chunk-NLT6YWUD.js → chunk-4YYB4AUZ.js} +4 -4
  94. package/dist/{chunk-NLT6YWUD.js.map → chunk-4YYB4AUZ.js.map} +1 -1
  95. package/dist/{chunk-ITMXD75H.js → chunk-5LOWNXWH.js} +10 -10
  96. package/dist/{chunk-ITMXD75H.js.map → chunk-5LOWNXWH.js.map} +1 -1
  97. package/dist/{chunk-NITRRCQV.js → chunk-67XC4WLH.js} +4 -4
  98. package/dist/{chunk-NITRRCQV.js.map → chunk-67XC4WLH.js.map} +1 -1
  99. package/dist/{chunk-RQ72QOIC.js → chunk-6A42EQCV.js} +7 -7
  100. package/dist/{chunk-RQ72QOIC.js.map → chunk-6A42EQCV.js.map} +1 -1
  101. package/dist/{chunk-672DTSG4.js → chunk-6S2SIUOD.js} +7 -7
  102. package/dist/{chunk-672DTSG4.js.map → chunk-6S2SIUOD.js.map} +1 -1
  103. package/dist/{chunk-D423MW2M.js → chunk-77Z3U5JT.js} +3 -3
  104. package/dist/{chunk-D423MW2M.js.map → chunk-77Z3U5JT.js.map} +1 -1
  105. package/dist/{chunk-QYHNS2KS.js → chunk-B3EKF5HJ.js} +4 -4
  106. package/dist/{chunk-QYHNS2KS.js.map → chunk-B3EKF5HJ.js.map} +1 -1
  107. package/dist/{chunk-4SMWY54W.js → chunk-CBYM3JIG.js} +3 -3
  108. package/dist/{chunk-4SMWY54W.js.map → chunk-CBYM3JIG.js.map} +1 -1
  109. package/dist/{chunk-JLBDDH4N.js → chunk-CR3EY7K7.js} +3 -3
  110. package/dist/{chunk-JLBDDH4N.js.map → chunk-CR3EY7K7.js.map} +1 -1
  111. package/dist/{chunk-K3PQSDGA.js → chunk-DJHYJ2VY.js} +4 -4
  112. package/dist/{chunk-K3PQSDGA.js.map → chunk-DJHYJ2VY.js.map} +1 -1
  113. package/dist/{chunk-YSSJ2CQC.js → chunk-DSJE2TS2.js} +4 -4
  114. package/dist/{chunk-YSSJ2CQC.js.map → chunk-DSJE2TS2.js.map} +1 -1
  115. package/dist/{chunk-AIPIJWOC.js → chunk-EAKEYWYL.js} +3 -3
  116. package/dist/{chunk-AIPIJWOC.js.map → chunk-EAKEYWYL.js.map} +1 -1
  117. package/dist/{chunk-I5XU5BQH.js → chunk-ECMFNYPW.js} +3 -3
  118. package/dist/{chunk-I5XU5BQH.js.map → chunk-ECMFNYPW.js.map} +1 -1
  119. package/dist/{chunk-KME6DTES.js → chunk-FU52JCUN.js} +7 -7
  120. package/dist/{chunk-KME6DTES.js.map → chunk-FU52JCUN.js.map} +1 -1
  121. package/dist/{chunk-CGDUSBLK.js → chunk-GHACVKKD.js} +16 -16
  122. package/dist/{chunk-CGDUSBLK.js.map → chunk-GHACVKKD.js.map} +1 -1
  123. package/dist/{chunk-FHAHE46U.js → chunk-H2QBHOF2.js} +2 -2
  124. package/dist/{chunk-FHAHE46U.js.map → chunk-H2QBHOF2.js.map} +1 -1
  125. package/dist/{chunk-OR6HPFZT.js → chunk-HCCSVECA.js} +4 -4
  126. package/dist/{chunk-OR6HPFZT.js.map → chunk-HCCSVECA.js.map} +1 -1
  127. package/dist/chunk-IXHM24Z4.js +28 -0
  128. package/dist/chunk-IXHM24Z4.js.map +1 -0
  129. package/dist/{chunk-ELARAFMR.js → chunk-J2OPSCWD.js} +3 -3
  130. package/dist/{chunk-ELARAFMR.js.map → chunk-J2OPSCWD.js.map} +1 -1
  131. package/dist/{chunk-54FS47CL.js → chunk-KSGBNVBQ.js} +3 -3
  132. package/dist/{chunk-54FS47CL.js.map → chunk-KSGBNVBQ.js.map} +1 -1
  133. package/dist/{chunk-IUEYRDEI.js → chunk-MYW5QYWO.js} +3 -3
  134. package/dist/{chunk-IUEYRDEI.js.map → chunk-MYW5QYWO.js.map} +1 -1
  135. package/dist/{chunk-EDCRELH3.js → chunk-ONK7RUTK.js} +3 -3
  136. package/dist/{chunk-EDCRELH3.js.map → chunk-ONK7RUTK.js.map} +1 -1
  137. package/dist/{chunk-HH7WFQLN.js → chunk-OSIFK62D.js} +3 -3
  138. package/dist/{chunk-HH7WFQLN.js.map → chunk-OSIFK62D.js.map} +1 -1
  139. package/dist/{chunk-4FYLW5WS.js → chunk-QT5YXTED.js} +3 -3
  140. package/dist/{chunk-4FYLW5WS.js.map → chunk-QT5YXTED.js.map} +1 -1
  141. package/dist/{chunk-RXWWNPCR.js → chunk-R4CQNOSV.js} +27 -12
  142. package/dist/chunk-R4CQNOSV.js.map +1 -0
  143. package/dist/{chunk-52MZ4V5T.js → chunk-R5AR7QRY.js} +4 -4
  144. package/dist/{chunk-52MZ4V5T.js.map → chunk-R5AR7QRY.js.map} +1 -1
  145. package/dist/{chunk-T55LMU5R.js → chunk-RHMJ6VR7.js} +3 -3
  146. package/dist/{chunk-T55LMU5R.js.map → chunk-RHMJ6VR7.js.map} +1 -1
  147. package/dist/{chunk-BSGHOYMT.js → chunk-SOQN5WKL.js} +3 -3
  148. package/dist/{chunk-BSGHOYMT.js.map → chunk-SOQN5WKL.js.map} +1 -1
  149. package/dist/{chunk-5JN6P5L5.js → chunk-TUW2BXB3.js} +6 -6
  150. package/dist/{chunk-5JN6P5L5.js.map → chunk-TUW2BXB3.js.map} +1 -1
  151. package/dist/{chunk-YGCPRUT6.js → chunk-USDRQPA3.js} +3 -3
  152. package/dist/{chunk-YGCPRUT6.js.map → chunk-USDRQPA3.js.map} +1 -1
  153. package/dist/{chunk-SCM4P6QG.js → chunk-VRLPOATQ.js} +3 -3
  154. package/dist/{chunk-SCM4P6QG.js.map → chunk-VRLPOATQ.js.map} +1 -1
  155. package/dist/{chunk-2UQKQTPB.js → chunk-W4OJM7BD.js} +4 -4
  156. package/dist/{chunk-2UQKQTPB.js.map → chunk-W4OJM7BD.js.map} +1 -1
  157. package/dist/chunk-WW6B37EO.js +14 -0
  158. package/dist/{chunk-2A2NODLC.js.map → chunk-WW6B37EO.js.map} +1 -1
  159. package/dist/{chunk-AXPZEXJN.js → chunk-XDPKYHQJ.js} +3 -3
  160. package/dist/{chunk-AXPZEXJN.js.map → chunk-XDPKYHQJ.js.map} +1 -1
  161. package/dist/{chunk-GSI42HHP.js → chunk-XH36I3IM.js} +3 -3
  162. package/dist/{chunk-GSI42HHP.js.map → chunk-XH36I3IM.js.map} +1 -1
  163. package/dist/{chunk-ORBMN52O.js → chunk-Y22HI53V.js} +4 -4
  164. package/dist/{chunk-ORBMN52O.js.map → chunk-Y22HI53V.js.map} +1 -1
  165. package/dist/{chunk-5DVSAKNY.js → chunk-YOJTLXNS.js} +4 -4
  166. package/dist/{chunk-5DVSAKNY.js.map → chunk-YOJTLXNS.js.map} +1 -1
  167. package/dist/{chunk-EZP2KOEL.js → chunk-Z4MMMPKI.js} +4 -4
  168. package/dist/{chunk-EZP2KOEL.js.map → chunk-Z4MMMPKI.js.map} +1 -1
  169. package/dist/{chunk-X4A3D5O4.js → chunk-ZGU7B5F4.js} +3 -3
  170. package/dist/{chunk-X4A3D5O4.js.map → chunk-ZGU7B5F4.js.map} +1 -1
  171. package/dist/components/cart/index.js +1 -1
  172. package/dist/components/common/index.js +1 -1
  173. package/dist/components/drawer/index.js +13 -13
  174. package/dist/components/home/index.js +17 -17
  175. package/dist/components/layout/index.js +4 -4
  176. package/dist/components/live-editor/LiveEditorBar.d.ts.map +1 -1
  177. package/dist/components/live-editor/frame.d.ts +2 -0
  178. package/dist/components/live-editor/frame.d.ts.map +1 -1
  179. package/dist/components/live-editor/moves.d.ts +14 -0
  180. package/dist/components/live-editor/moves.d.ts.map +1 -0
  181. package/dist/components/product/index.js +14 -14
  182. package/dist/components/store/index.js +14 -14
  183. package/dist/dev/editor/index.js +1 -1
  184. package/dist/dev/index.js +1 -1
  185. package/dist/{document-class-2SKG4YZE.js → document-class-ZHPKTBSI.js} +11 -11
  186. package/dist/{document-class-2SKG4YZE.js.map → document-class-ZHPKTBSI.js.map} +1 -1
  187. package/dist/hooks/index.js +13 -13
  188. package/dist/hooks/useGtm.js +13 -13
  189. package/dist/hooks/useMoney.js +13 -13
  190. package/dist/hooks/useStore.js +13 -13
  191. package/dist/hooks/useUser.js +3 -3
  192. package/dist/index.js +13 -13
  193. package/dist/{navigation-WVVYQOOZ.js → navigation-7DJCQ7MJ.js} +5 -5
  194. package/dist/{navigation-WVVYQOOZ.js.map → navigation-7DJCQ7MJ.js.map} +1 -1
  195. package/dist/{navigation-7HBHI524.js → navigation-HC3IK4P7.js} +4 -4
  196. package/dist/{navigation-7HBHI524.js.map → navigation-HC3IK4P7.js.map} +1 -1
  197. package/dist/{not-found-ZN7HOUO4.js → not-found-ANC6EGYO.js} +16 -16
  198. package/dist/{not-found-ZN7HOUO4.js.map → not-found-ANC6EGYO.js.map} +1 -1
  199. package/dist/providers/index.js +13 -13
  200. package/dist/routes/account/orders.js +4 -4
  201. package/dist/routes/account.js +13 -13
  202. package/dist/routes/blog.js +8 -8
  203. package/dist/routes/brands.js +4 -4
  204. package/dist/routes/cart.js +22 -21
  205. package/dist/routes/cart.js.map +1 -1
  206. package/dist/routes/home/HomePage.d.ts.map +1 -1
  207. package/dist/routes/home.js +19 -18
  208. package/dist/routes/index.js +3 -3
  209. package/dist/routes/loyalty.js +5 -5
  210. package/dist/routes/page.js +4 -4
  211. package/dist/routes/product-listing.js +19 -19
  212. package/dist/routes/product.js +17 -17
  213. package/dist/routes/seo-redirects.js +3 -3
  214. package/dist/routes/testimonials.js +2 -2
  215. package/dist/routes/thank-you.js +4 -4
  216. package/dist/skeleton.js +19 -18
  217. package/dist/{store-lookup-KSHMPOFT.js → store-lookup-5SPFTCPN.js} +8 -8
  218. package/dist/{store-lookup-KSHMPOFT.js.map → store-lookup-5SPFTCPN.js.map} +1 -1
  219. package/dist/tanstack.js +11 -11
  220. package/dist/utils/index.js +2 -2
  221. package/package.json +1 -1
  222. package/tailwind/components/live-editor/LiveEditorBar.tsx.txt +80 -8
  223. package/tailwind/components/live-editor/frame.ts.txt +1 -1
  224. package/tailwind/components/live-editor/moves.ts.txt +38 -0
  225. package/tailwind/routes/home/HomePage.tsx.txt +32 -6
  226. package/dist/LiveEditorBar-DOSRO35J.js.map +0 -1
  227. package/dist/chunk-2A2NODLC.js +0 -14
  228. package/dist/chunk-RXWWNPCR.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/translations.ts"],"names":[],"mappings":"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","file":"chunk-4FYLW5WS.js","sourcesContent":["/**\n * @fileoverview Where a storefront's words come from.\n *\n * Two files, merged: the platform's copy for this language, and the merchant's\n * own edits for this language and this store. Both are plain JSON objects on\n * the uploader's CDN, one per language.\n *\n * ```\n * https://cdn.files.salla.network/translations/common/<locale>.json the platform's\n * https://cdn.files.salla.network/translations/<storeId>/<locale>.json the merchant's\n * ```\n *\n * **What this replaces, and why.** Until now the engine read a single global\n * file, `cdn.salla.network/js/translations.json`, holding every language keyed\n * `\"<locale>.trans\"`. Nothing publishes that file: it is an object last written\n * on 2026-03-26, carrying only `ar` and `en` where the platform has 39 locales,\n * 405 keys behind `Languages-Module` and 959 English strings textually\n * different from it. So every React storefront has been serving copy from\n * March, and a key added since has never reached one. It also carried no\n * merchant overrides at all — a merchant editing their theme's wording in the\n * Dashboard changed nothing on a React theme.\n *\n * **Merchant overrides are read, and only when there are any.** Getting here\n * took two corrections worth keeping.\n *\n * The first is the address. A merchant's own wording lives at\n * `translations/<storeId>/<locale>.json`, keyed by `store()->getRouteKey()` —\n * the Optimus-encoded numeric id. An early version addressed it with\n * `resolveStoreIdentifier()`, on the claim that the two are the same string.\n * That is true of the `store-identifier` *header*, which accepts a host, a\n * username or an id, and false of the R2 key: on a custom domain the resolver\n * returns `reefperfumes.com` and on a shared host a username like\n * `mtgr-alaatr-2`. Both 404, both then read as \"this store has no overrides\",\n * and the merchant's wording silently never appears — so the feature would have\n * worked under `?storeId=` alone, which is preview and localhost. It is\n * `settings.store.id` now, which is known only after the settings query.\n *\n * The second is when to ask at all. Most stores have never customised a word,\n * and a miss is an uncached round trip (`cf-cache-status: DYNAMIC` on the 404)\n * on the critical path of every SSR render. So the request is made only when\n * `settings.languages[<ISO>].has_custom_translations` says there is something\n * to get — a flag `Languages-Module` writes when a merchant saves a\n * translation. A store without overrides pays nothing, which is what made this\n * shippable at all.\n *\n * ⚠️ The flag is written on save, so a store whose wording predates it reads as\n * `false` until someone edits a translation or the backfill runs. That is a\n * store keeping today's behaviour, not a regression — React themes have never\n * read merchant overrides — but it does mean the feature is only as complete as\n * the backfill.\n *\n * **Rollout is by fallback, not by flag.** `translations/common/` is written by\n * a sync in the theme build service that may not have run yet, and a hard switch\n * would leave every storefront with no platform strings at all. A missing common\n * file therefore falls back to the old global one, which is exactly today's\n * behaviour — so this is safe to ship before the bucket is populated, and stops\n * using the fallback on its own once it is.\n */\nimport { queryOptions } from '@tanstack/react-query';\nimport { cdn, filesCdn } from './client';\nimport { storeTranslationsQueryKey, translationsQueryKey } from './translations-key';\nimport { composeMessages, isPlainObject, type Messages } from './messages';\nimport type { TranslationMessages } from '../providers/I18nProvider';\n\n/** The global file this used to be the only reader of. See the file comment. */\nconst LEGACY_GLOBAL_FILE = 'js/translations.json';\n\n/** One language of platform copy, shared by every store. */\nexport function commonTranslationsPath(locale: string): string {\n return `translations/common/${locale}.json`;\n}\n\n/**\n * One language of a single merchant's own wording.\n *\n * `storeId` is `settings.store.id`, which is the value `Languages-Module` names\n * the object with (`store()->getRouteKey()`, the Optimus-encoded numeric id).\n * It is **not** `resolveStoreIdentifier()`: that returns a hostname on a custom\n * domain and a username on a shared host, both of which 404 here and would read\n * as \"this merchant has no overrides\" — silently, on every store but a preview.\n */\nexport function storeTranslationsPath(storeId: string | number, locale: string): string {\n return `translations/${storeId}/${locale}.json`;\n}\n\n/**\n * Reads one language file, or `null` when there is nothing to read.\n *\n * A 404 is the ordinary answer, not a failure: most stores have never had a\n * word customised, so their file does not exist. Distinguishing it from a real\n * error matters only for the log — both end in `null` — but a warning on every\n * page load of every uncustomised store is a warning nobody will read.\n */\nasync function readLocaleFile(\n path: string,\n { failLoudly = false }: { failLoudly?: boolean } = {}\n): Promise<Messages | null> {\n /** A 404 always means \"absent\"; everything else is a failure to read. */\n const unreadable = (reason: string, cause?: unknown): null => {\n if (failLoudly) throw new Error(`[translations] ${path}: ${reason}`, { cause });\n console.warn('[translations]', reason, path, cause ?? '');\n return null;\n };\n\n try {\n const response = await filesCdn.get(path, { throwHttpErrors: false, timeout: 5000 });\n if (response.status === 404) return null;\n\n if (!response.ok) {\n return unreadable(`answered ${response.status}`);\n }\n\n const data: unknown = await response.json();\n if (!isPlainObject(data)) {\n return unreadable('is not a JSON object');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith('[translations]')) throw error;\n return unreadable('could not be read', error);\n }\n}\n\n/**\n * The pre-CDN global file, sliced to one language.\n *\n * Only reached when `translations/common/<locale>.json` is missing, which is\n * the state of the bucket until the sync has run once.\n */\nasync function readLegacyGlobal(locale: string): Promise<Messages | null> {\n try {\n const data = await cdn.get(LEGACY_GLOBAL_FILE, { timeout: 5000 }).json<TranslationMessages>();\n const forLocale = data?.[`${locale}.trans`];\n return isPlainObject(forLocale) ? forLocale : null;\n } catch {\n console.warn('[translations] the legacy global file could not be read either');\n return null;\n }\n}\n\nexport const translations = {\n /**\n * The platform's copy for `locale`.\n *\n * One file, so one request. See the file comment for why the merchant's own\n * wording is not merged in here yet and what it is waiting on.\n */\n get: async (locale: string): Promise<TranslationMessages | null> => {\n const common = await readLocaleFile(commonTranslationsPath(locale));\n const base = common ?? (await readLegacyGlobal(locale));\n if (!base) return null;\n\n // Still wrapped in the `<locale>.trans` shape the rest of the engine reads.\n // `createI18nInstance` slices by that key and so does the SDK bridge in\n // `I18nProvider`; changing the envelope here would be a second change for\n // no gain, since one language is all any of them ever take out of it.\n return { [`${locale}.trans`]: base as Record<string, string> };\n },\n\n /**\n * This merchant's own wording for `locale`, or `null` if they have none.\n *\n * Only worth calling when `settings.languages[<ISO>].has_custom_translations`\n * says there is something to get. Most stores have never customised a word,\n * and a miss here is an uncached round trip — `cf-cache-status: DYNAMIC` on a\n * 404 — on the critical path of an SSR render. The flag is what makes this\n * free for everyone who does not use it.\n *\n * Returned unwrapped, unlike {@link translations.get}: this is merged into\n * that one's messages rather than handed to i18next on its own.\n */\n forStore: async (storeId: string | number, locale: string): Promise<Messages | null> =>\n // `failLoudly`, unlike the platform file: this is only ever called because\n // the settings said overrides exist, so a 500, a timeout or a body that is\n // not JSON is a failure to read them — not a store that has none. Returning\n // `null` there would cache \"no overrides\" as a success, skip the query's\n // retry, and serve Salla's wording in place of the merchant's until the\n // entry expired. A 404 still means absent, and `rootBeforeLoad` catches the\n // throw and keeps the platform copy, so the worst case is unchanged.\n readLocaleFile(storeTranslationsPath(storeId, locale), { failLoudly: true }),\n\n /**\n * The platform's copy for `locale` with this merchant's wording laid over it.\n *\n * Takes the two as values rather than fetching them, so the caller decides\n * whether the second request happens at all and both stay separately cached.\n */\n /**\n * The platform's copy for `locale` with this merchant's wording over it.\n *\n * Delegates to `composeMessages`, which every other reader of these two\n * entries also uses — see `api/messages.ts` for why there is exactly one.\n */\n merge: (\n common: TranslationMessages | null,\n overrides: Messages | null,\n locale: string\n ): TranslationMessages | null => composeMessages(common, overrides, locale) ?? null,\n\n queries: {\n /**\n * @param locale taken as an argument rather than read from the twilight\n * context, and that is load-bearing. This key is built on the server, on\n * hydration, and again lazily from the context accessor; if any of the\n * three read a locale the others had not been given yet, the hydrated page\n * would miss the dehydrated entry and refetch both files it was just\n * handed. Every caller already has the locale in hand.\n *\n * The store is deliberately **not** in the key. One document serves one\n * store — a request that names a different one is redirected with\n * `reloadDocument`, so the client never changes store under a live cache —\n * and adding a value that resolves from the request on the server and from\n * the injected env on the client is how a key stops matching across\n * hydration.\n */\n byLocale: (locale: string) =>\n queryOptions({\n queryKey: translationsQueryKey(locale),\n queryFn: () => translations.get(locale),\n }),\n\n /**\n * This merchant's overrides, cached apart from the platform's copy.\n *\n * Its own entry rather than a wider `byLocale` key, so the common file is\n * fetched and dehydrated once per language whatever the store does, and a\n * store with no overrides never has an entry at all. Both sides compute the\n * key from the settings payload, so the hydrated page finds what the server\n * dehydrated instead of refetching it.\n */\n byStore: (storeId: string | number, locale: string) =>\n queryOptions({\n queryKey: storeTranslationsQueryKey(storeId, locale),\n queryFn: () => translations.forStore(storeId, locale),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/translations.ts"],"names":[],"mappings":"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","file":"chunk-QT5YXTED.js","sourcesContent":["/**\n * @fileoverview Where a storefront's words come from.\n *\n * Two files, merged: the platform's copy for this language, and the merchant's\n * own edits for this language and this store. Both are plain JSON objects on\n * the uploader's CDN, one per language.\n *\n * ```\n * https://cdn.files.salla.network/translations/common/<locale>.json the platform's\n * https://cdn.files.salla.network/translations/<storeId>/<locale>.json the merchant's\n * ```\n *\n * **What this replaces, and why.** Until now the engine read a single global\n * file, `cdn.salla.network/js/translations.json`, holding every language keyed\n * `\"<locale>.trans\"`. Nothing publishes that file: it is an object last written\n * on 2026-03-26, carrying only `ar` and `en` where the platform has 39 locales,\n * 405 keys behind `Languages-Module` and 959 English strings textually\n * different from it. So every React storefront has been serving copy from\n * March, and a key added since has never reached one. It also carried no\n * merchant overrides at all — a merchant editing their theme's wording in the\n * Dashboard changed nothing on a React theme.\n *\n * **Merchant overrides are read, and only when there are any.** Getting here\n * took two corrections worth keeping.\n *\n * The first is the address. A merchant's own wording lives at\n * `translations/<storeId>/<locale>.json`, keyed by `store()->getRouteKey()` —\n * the Optimus-encoded numeric id. An early version addressed it with\n * `resolveStoreIdentifier()`, on the claim that the two are the same string.\n * That is true of the `store-identifier` *header*, which accepts a host, a\n * username or an id, and false of the R2 key: on a custom domain the resolver\n * returns `reefperfumes.com` and on a shared host a username like\n * `mtgr-alaatr-2`. Both 404, both then read as \"this store has no overrides\",\n * and the merchant's wording silently never appears — so the feature would have\n * worked under `?storeId=` alone, which is preview and localhost. It is\n * `settings.store.id` now, which is known only after the settings query.\n *\n * The second is when to ask at all. Most stores have never customised a word,\n * and a miss is an uncached round trip (`cf-cache-status: DYNAMIC` on the 404)\n * on the critical path of every SSR render. So the request is made only when\n * `settings.languages[<ISO>].has_custom_translations` says there is something\n * to get — a flag `Languages-Module` writes when a merchant saves a\n * translation. A store without overrides pays nothing, which is what made this\n * shippable at all.\n *\n * ⚠️ The flag is written on save, so a store whose wording predates it reads as\n * `false` until someone edits a translation or the backfill runs. That is a\n * store keeping today's behaviour, not a regression — React themes have never\n * read merchant overrides — but it does mean the feature is only as complete as\n * the backfill.\n *\n * **Rollout is by fallback, not by flag.** `translations/common/` is written by\n * a sync in the theme build service that may not have run yet, and a hard switch\n * would leave every storefront with no platform strings at all. A missing common\n * file therefore falls back to the old global one, which is exactly today's\n * behaviour — so this is safe to ship before the bucket is populated, and stops\n * using the fallback on its own once it is.\n */\nimport { queryOptions } from '@tanstack/react-query';\nimport { cdn, filesCdn } from './client';\nimport { storeTranslationsQueryKey, translationsQueryKey } from './translations-key';\nimport { composeMessages, isPlainObject, type Messages } from './messages';\nimport type { TranslationMessages } from '../providers/I18nProvider';\n\n/** The global file this used to be the only reader of. See the file comment. */\nconst LEGACY_GLOBAL_FILE = 'js/translations.json';\n\n/** One language of platform copy, shared by every store. */\nexport function commonTranslationsPath(locale: string): string {\n return `translations/common/${locale}.json`;\n}\n\n/**\n * One language of a single merchant's own wording.\n *\n * `storeId` is `settings.store.id`, which is the value `Languages-Module` names\n * the object with (`store()->getRouteKey()`, the Optimus-encoded numeric id).\n * It is **not** `resolveStoreIdentifier()`: that returns a hostname on a custom\n * domain and a username on a shared host, both of which 404 here and would read\n * as \"this merchant has no overrides\" — silently, on every store but a preview.\n */\nexport function storeTranslationsPath(storeId: string | number, locale: string): string {\n return `translations/${storeId}/${locale}.json`;\n}\n\n/**\n * Reads one language file, or `null` when there is nothing to read.\n *\n * A 404 is the ordinary answer, not a failure: most stores have never had a\n * word customised, so their file does not exist. Distinguishing it from a real\n * error matters only for the log — both end in `null` — but a warning on every\n * page load of every uncustomised store is a warning nobody will read.\n */\nasync function readLocaleFile(\n path: string,\n { failLoudly = false }: { failLoudly?: boolean } = {}\n): Promise<Messages | null> {\n /** A 404 always means \"absent\"; everything else is a failure to read. */\n const unreadable = (reason: string, cause?: unknown): null => {\n if (failLoudly) throw new Error(`[translations] ${path}: ${reason}`, { cause });\n console.warn('[translations]', reason, path, cause ?? '');\n return null;\n };\n\n try {\n const response = await filesCdn.get(path, { throwHttpErrors: false, timeout: 5000 });\n if (response.status === 404) return null;\n\n if (!response.ok) {\n return unreadable(`answered ${response.status}`);\n }\n\n const data: unknown = await response.json();\n if (!isPlainObject(data)) {\n return unreadable('is not a JSON object');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error && error.message.startsWith('[translations]')) throw error;\n return unreadable('could not be read', error);\n }\n}\n\n/**\n * The pre-CDN global file, sliced to one language.\n *\n * Only reached when `translations/common/<locale>.json` is missing, which is\n * the state of the bucket until the sync has run once.\n */\nasync function readLegacyGlobal(locale: string): Promise<Messages | null> {\n try {\n const data = await cdn.get(LEGACY_GLOBAL_FILE, { timeout: 5000 }).json<TranslationMessages>();\n const forLocale = data?.[`${locale}.trans`];\n return isPlainObject(forLocale) ? forLocale : null;\n } catch {\n console.warn('[translations] the legacy global file could not be read either');\n return null;\n }\n}\n\nexport const translations = {\n /**\n * The platform's copy for `locale`.\n *\n * One file, so one request. See the file comment for why the merchant's own\n * wording is not merged in here yet and what it is waiting on.\n */\n get: async (locale: string): Promise<TranslationMessages | null> => {\n const common = await readLocaleFile(commonTranslationsPath(locale));\n const base = common ?? (await readLegacyGlobal(locale));\n if (!base) return null;\n\n // Still wrapped in the `<locale>.trans` shape the rest of the engine reads.\n // `createI18nInstance` slices by that key and so does the SDK bridge in\n // `I18nProvider`; changing the envelope here would be a second change for\n // no gain, since one language is all any of them ever take out of it.\n return { [`${locale}.trans`]: base as Record<string, string> };\n },\n\n /**\n * This merchant's own wording for `locale`, or `null` if they have none.\n *\n * Only worth calling when `settings.languages[<ISO>].has_custom_translations`\n * says there is something to get. Most stores have never customised a word,\n * and a miss here is an uncached round trip — `cf-cache-status: DYNAMIC` on a\n * 404 — on the critical path of an SSR render. The flag is what makes this\n * free for everyone who does not use it.\n *\n * Returned unwrapped, unlike {@link translations.get}: this is merged into\n * that one's messages rather than handed to i18next on its own.\n */\n forStore: async (storeId: string | number, locale: string): Promise<Messages | null> =>\n // `failLoudly`, unlike the platform file: this is only ever called because\n // the settings said overrides exist, so a 500, a timeout or a body that is\n // not JSON is a failure to read them — not a store that has none. Returning\n // `null` there would cache \"no overrides\" as a success, skip the query's\n // retry, and serve Salla's wording in place of the merchant's until the\n // entry expired. A 404 still means absent, and `rootBeforeLoad` catches the\n // throw and keeps the platform copy, so the worst case is unchanged.\n readLocaleFile(storeTranslationsPath(storeId, locale), { failLoudly: true }),\n\n /**\n * The platform's copy for `locale` with this merchant's wording laid over it.\n *\n * Takes the two as values rather than fetching them, so the caller decides\n * whether the second request happens at all and both stay separately cached.\n */\n /**\n * The platform's copy for `locale` with this merchant's wording over it.\n *\n * Delegates to `composeMessages`, which every other reader of these two\n * entries also uses — see `api/messages.ts` for why there is exactly one.\n */\n merge: (\n common: TranslationMessages | null,\n overrides: Messages | null,\n locale: string\n ): TranslationMessages | null => composeMessages(common, overrides, locale) ?? null,\n\n queries: {\n /**\n * @param locale taken as an argument rather than read from the twilight\n * context, and that is load-bearing. This key is built on the server, on\n * hydration, and again lazily from the context accessor; if any of the\n * three read a locale the others had not been given yet, the hydrated page\n * would miss the dehydrated entry and refetch both files it was just\n * handed. Every caller already has the locale in hand.\n *\n * The store is deliberately **not** in the key. One document serves one\n * store — a request that names a different one is redirected with\n * `reloadDocument`, so the client never changes store under a live cache —\n * and adding a value that resolves from the request on the server and from\n * the injected env on the client is how a key stops matching across\n * hydration.\n */\n byLocale: (locale: string) =>\n queryOptions({\n queryKey: translationsQueryKey(locale),\n queryFn: () => translations.get(locale),\n }),\n\n /**\n * This merchant's overrides, cached apart from the platform's copy.\n *\n * Its own entry rather than a wider `byLocale` key, so the common file is\n * fetched and dehydrated once per language whatever the store does, and a\n * store with no overrides never has an entry at all. Both sides compute the\n * key from the settings payload, so the hydrated page finds what the server\n * dehydrated instead of refetching it.\n */\n byStore: (storeId: string | number, locale: string) =>\n queryOptions({\n queryKey: storeTranslationsQueryKey(storeId, locale),\n queryFn: () => translations.forStore(storeId, locale),\n }),\n },\n};\n"]}
@@ -1,11 +1,12 @@
1
- import { HomeComponentRenderer, ReorderProducts } from './chunk-AN2PETFM.js';
2
- import { home } from './chunk-T55LMU5R.js';
3
- import { useDevHomeBlocks } from './chunk-SCM4P6QG.js';
1
+ import { reorder, useLiveBlockMoves } from './chunk-IXHM24Z4.js';
2
+ import { HomeComponentRenderer, ReorderProducts } from './chunk-3FXRE7JW.js';
3
+ import { home } from './chunk-RHMJ6VR7.js';
4
+ import { useDevHomeBlocks } from './chunk-VRLPOATQ.js';
4
5
  import { storePageUrl, buildHreflangAlternates } from './chunk-OM2GRPDH.js';
5
6
  import { RouteId } from './chunk-OUW6WESU.js';
6
7
  import { HookSlot } from './chunk-5XDPAKF5.js';
7
8
  import { getTwilightContext } from './chunk-7VNVCHID.js';
8
- import { memo } from 'react';
9
+ import { memo, useState, useCallback } from 'react';
9
10
  import { Pulse } from '@salla.sa/twilight-components-react';
10
11
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
11
12
 
@@ -36,17 +37,31 @@ var HomeSkeleton = memo(function HomeSkeleton2() {
36
37
  ] })
37
38
  ] });
38
39
  });
40
+ var storeOrder = (blocks) => Array.from(blocks, (_, at) => at);
39
41
  var HomePage = memo(function HomePage2({ components = [] }) {
40
42
  const renderedComponents = useDevHomeBlocks(components);
43
+ const [moved, setMoved] = useState(null);
44
+ const order = moved?.source === renderedComponents ? moved.order : null;
45
+ const onMove = useCallback(
46
+ (from, to) => setMoved((prev) => ({
47
+ source: renderedComponents,
48
+ order: reorder(
49
+ prev?.source === renderedComponents ? prev.order : storeOrder(renderedComponents),
50
+ from,
51
+ to
52
+ )
53
+ })),
54
+ [renderedComponents]
55
+ );
56
+ useLiveBlockMoves(onMove);
57
+ const placed = order ?? storeOrder(renderedComponents);
41
58
  return /* @__PURE__ */ jsxs(Fragment, { children: [
42
59
  /* @__PURE__ */ jsx(HookSlot, { name: "home:start" }),
43
60
  /* @__PURE__ */ jsx(HookSlot, { name: "home:content" }),
44
- renderedComponents.map((data, index) => (
45
- // `data.key` is the twilight.json catalog id, shared by every placement
46
- // of that block. Platform blocks send null. Position is unique; a dev
47
- // layout block keeps its own id so a reorder doesn't remount the rest.
48
- /* @__PURE__ */ jsx(HomeComponentRenderer, { data, index }, data.__dev_id ?? index)
49
- )),
61
+ placed.map((at, index) => {
62
+ const data = renderedComponents[at];
63
+ return /* @__PURE__ */ jsx(HomeComponentRenderer, { data, index }, data.__dev_id ?? at);
64
+ }),
50
65
  /* @__PURE__ */ jsx(HookSlot, { name: "home:end" }),
51
66
  /* @__PURE__ */ jsx(ReorderProducts, {})
52
67
  ] });
@@ -87,5 +102,5 @@ function head(ctx) {
87
102
  var Home = { id: RouteId.INDEX, loader, head, Component: HomePage };
88
103
 
89
104
  export { Home, HomeSkeleton, homeLoader };
90
- //# sourceMappingURL=chunk-RXWWNPCR.js.map
91
- //# sourceMappingURL=chunk-RXWWNPCR.js.map
105
+ //# sourceMappingURL=chunk-R4CQNOSV.js.map
106
+ //# sourceMappingURL=chunk-R4CQNOSV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routes/home/loader.ts","../src/routes/home/HomePage.tsx","../src/routes/home/index.tsx"],"names":["HomeSkeleton","HomePage"],"mappings":"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","file":"chunk-R4CQNOSV.js","sourcesContent":["import { getTwilightContext } from '../../twilight/context';\nimport { home } from '../../api/home';\nimport type { HomeComponentData } from '../../types';\nimport { RouteId } from '../../router/route-ids';\n\nexport interface HomeLoaderData {\n locale: string;\n components: HomeComponentData[];\n page: { slug: string };\n}\n\nexport async function homeLoader(ctx?: { locale?: string }): Promise<HomeLoaderData> {\n const { queryClient } = getTwilightContext();\n const components = await queryClient.ensureQueryData(home.queries.components());\n const result = {\n locale: ctx?.locale || 'ar',\n components: components.map((comp) => ({\n ...comp,\n path: comp.path?.replace('home.', '') || comp.path,\n })),\n page: { slug: RouteId.INDEX },\n };\n return result;\n}\n","import { memo, useCallback, useState } from 'react';\nimport { useDevHomeBlocks } from '../../dev/dev-settings-store';\nimport { HookSlot } from '../../hooks';\nimport { HomeComponentRenderer, ReorderProducts } from '../../components/home';\nimport { reorder, useLiveBlockMoves } from '../../components/live-editor/moves';\nimport type { HomePageProps } from './types';\nimport type { HomeComponentData } from '../../types';\nimport { Pulse } from '@salla.sa/twilight-components-react';\n\nexport const HomeSkeleton = memo(function HomeSkeleton() {\n return (\n <>\n <div className=\"s-block container skeleton-block-hero\">\n <Pulse className=\"h-64 sm:h-80 rounded-md\" />\n </div>\n <div className=\"s-block container skeleton-block-products\">\n <Pulse className=\"h-10 w-48 mb-4\" />\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n {[1, 2, 3, 4].map((i) => (\n <Pulse key={i} className=\"h-56\" />\n ))}\n </div>\n </div>\n <div className=\"s-block container skeleton-block-products\">\n <Pulse className=\"h-10 w-48 mb-4\" />\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n {[1, 2, 3, 4].map((i) => (\n <Pulse key={i} className=\"h-56\" />\n ))}\n </div>\n </div>\n </>\n );\n});\n\n/** The blocks' places in the store's order: 0, 1, 2… */\nconst storeOrder = (blocks: readonly unknown[]) => Array.from(blocks, (_, at) => at);\n\nexport const HomePage = memo(function HomePage({ components = [] }: HomePageProps) {\n // Dev-mode only: the dev editor's layout replaces the store's blocks while it\n // is on. No-op passthrough in production builds.\n const renderedComponents = useDevHomeBlocks(components);\n // The theme editor's preview moves blocks in place while the editor saves the\n // order; blocks from the server (a new page, a reload) start over from theirs.\n const [moved, setMoved] = useState<{ source: HomeComponentData[]; order: number[] } | null>(null);\n const order = moved?.source === renderedComponents ? moved.order : null;\n const onMove = useCallback(\n (from: number, to: number) =>\n setMoved((prev) => ({\n source: renderedComponents,\n order: reorder(\n prev?.source === renderedComponents ? prev.order : storeOrder(renderedComponents),\n from,\n to\n ),\n })),\n [renderedComponents]\n );\n useLiveBlockMoves(onMove);\n const placed = order ?? storeOrder(renderedComponents);\n\n return (\n <>\n <HookSlot name=\"home:start\" />\n <HookSlot name=\"home:content\" />\n {placed.map((at, index) => {\n const data = renderedComponents[at];\n // `data.key` is the twilight.json catalog id, shared by every placement\n // of that block. Platform blocks send null. The block's place in the\n // store's order is unique and stays with it when the preview moves it, so\n // a move keeps its state; a dev layout block keeps its own id.\n return <HomeComponentRenderer key={data.__dev_id ?? at} data={data} index={index} />;\n })}\n <HookSlot name=\"home:end\" />\n <ReorderProducts />\n </>\n );\n});\n\nexport { HomePage as default };\n","import type { HeadDescriptor } from '../../utils/head';\nimport { buildHreflangAlternates, storePageUrl } from '../../utils/baseHead';\nimport type { HomeLoaderData } from './loader';\nimport { homeLoader } from './loader';\nimport type { TwilightContext } from '../../twilight/context';\nimport { HomePage } from './HomePage';\nimport { RouteId } from '../../router/route-ids';\n\nexport { HomeSkeleton } from './HomePage';\nexport { registerHomeComponents, DefaultHomeComponents } from '../../components/home/register';\nexport { registerHomeComponentConfig } from '../../components/home';\nexport type { HomePageProps } from './types';\nexport type { HomeLoaderData } from './loader';\nexport type {\n HomeComponentsProps,\n AnyHomeComponent,\n HomeComponentConfig,\n} from '../../components/home';\n\nfunction loader(_ctx?: { locale?: string }): Promise<HomeLoaderData> {\n return homeLoader({ locale: _ctx?.locale });\n}\n\nfunction head(ctx: TwilightContext): HeadDescriptor {\n const store = ctx.settings?.store;\n if (!store) return {};\n\n const title = store.meta?.title ?? store.name;\n const description = store.meta?.description ?? store.description;\n const keywords = store.meta?.keywords;\n // `/ar`, like Twig, where store.url reads `/ar/`.\n const url = storePageUrl(ctx.settings, ctx.location.pathname) ?? store.url;\n\n return {\n title,\n description,\n keywords,\n canonical: url,\n openGraph: {\n type: 'website',\n title,\n description,\n images: store.logo,\n url,\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: store.logo,\n },\n alternateLanguages: buildHreflangAlternates(ctx.settings, ctx.location.pathname),\n };\n}\n\nexport const Home = { id: RouteId.INDEX, loader, head, Component: HomePage } as const;\n\nexport { homeLoader };\n"]}
@@ -1,5 +1,5 @@
1
- import { orThrow } from './chunk-WYWI77EA.js';
2
- import { api } from './chunk-BSGHOYMT.js';
1
+ import { orThrow } from './chunk-2Z7XKCT3.js';
2
+ import { api } from './chunk-SOQN5WKL.js';
3
3
  import { queryOptions } from '@tanstack/react-query';
4
4
 
5
5
  var page = {
@@ -17,5 +17,5 @@ var page = {
17
17
  };
18
18
 
19
19
  export { page };
20
- //# sourceMappingURL=chunk-52MZ4V5T.js.map
21
- //# sourceMappingURL=chunk-52MZ4V5T.js.map
20
+ //# sourceMappingURL=chunk-R5AR7QRY.js.map
21
+ //# sourceMappingURL=chunk-R5AR7QRY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/page.ts"],"names":[],"mappings":";;;;AAKO,IAAM,IAAA,GAAO;AAAA,EAClB,IAAA,EAAM,OAAO,IAAA,KAA2C;AACtD,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,MAAA,EAAS,IAAI,CAAA,CAAE,CAAA,CAAE,IAAA,EAAgC;AAChF,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAAA,EAEA,aAAa,CAAC,IAAA,KAA2C,QAAQ,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EAEhF,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,CAAC,IAAA,KACP,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,OAAA,EAAS,QAAA,EAAU,IAAI,CAAA;AAAA,MAClC,OAAA,EAAS,MAAM,IAAA,CAAK,IAAA,CAAK,IAAI;AAAA,KAC9B;AAAA;AAEP","file":"chunk-52MZ4V5T.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\nimport type { ApiPageResponse } from '../routes/page/types';\nimport { orThrow } from '../providers/NavigationProvider';\n\nexport const page = {\n find: async (slug: string): Promise<ApiPageResponse> => {\n const { data } = await api.get(`pages/${slug}`).json<{ data: ApiPageResponse }>();\n return data;\n },\n\n findOrThrow: (slug: string): Promise<ApiPageResponse> => orThrow(page.find(slug)),\n\n queries: {\n detail: (slug: string) =>\n queryOptions({\n queryKey: ['pages', 'detail', slug],\n queryFn: () => page.find(slug),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/page.ts"],"names":[],"mappings":";;;;AAKO,IAAM,IAAA,GAAO;AAAA,EAClB,IAAA,EAAM,OAAO,IAAA,KAA2C;AACtD,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,MAAA,EAAS,IAAI,CAAA,CAAE,CAAA,CAAE,IAAA,EAAgC;AAChF,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAAA,EAEA,aAAa,CAAC,IAAA,KAA2C,QAAQ,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EAEhF,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,CAAC,IAAA,KACP,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,OAAA,EAAS,QAAA,EAAU,IAAI,CAAA;AAAA,MAClC,OAAA,EAAS,MAAM,IAAA,CAAK,IAAA,CAAK,IAAI;AAAA,KAC9B;AAAA;AAEP","file":"chunk-R5AR7QRY.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api } from './client';\nimport type { ApiPageResponse } from '../routes/page/types';\nimport { orThrow } from '../providers/NavigationProvider';\n\nexport const page = {\n find: async (slug: string): Promise<ApiPageResponse> => {\n const { data } = await api.get(`pages/${slug}`).json<{ data: ApiPageResponse }>();\n return data;\n },\n\n findOrThrow: (slug: string): Promise<ApiPageResponse> => orThrow(page.find(slug)),\n\n queries: {\n detail: (slug: string) =>\n queryOptions({\n queryKey: ['pages', 'detail', slug],\n queryFn: () => page.find(slug),\n }),\n },\n};\n"]}
@@ -1,4 +1,4 @@
1
- import { getActiveScope, api } from './chunk-BSGHOYMT.js';
1
+ import { getActiveScope, api } from './chunk-SOQN5WKL.js';
2
2
  import { queryOptions } from '@tanstack/react-query';
3
3
 
4
4
  async function list(params) {
@@ -45,5 +45,5 @@ var home = {
45
45
  };
46
46
 
47
47
  export { home };
48
- //# sourceMappingURL=chunk-T55LMU5R.js.map
49
- //# sourceMappingURL=chunk-T55LMU5R.js.map
48
+ //# sourceMappingURL=chunk-RHMJ6VR7.js.map
49
+ //# sourceMappingURL=chunk-RHMJ6VR7.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/home.ts"],"names":[],"mappings":";;;AAQA,eAAe,KAAK,MAAA,EAA+D;AACjF,EAAA,MAAM,KAAA,GAAQ,SAAS,CAAA,CAAA,EAAI,IAAI,gBAAgB,MAAM,CAAA,CAAE,QAAA,EAAU,CAAA,CAAA,GAAK,EAAA;AACtE,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAA,CAAE,CAAA,CAAE,IAAA,EAAoC;AAC7F,EAAA,OAAO,QAAQ,EAAC;AAClB;AAGA,SAAS,OAAA,CAAQ,QAA6B,QAAA,EAAoD;AAChG,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAQ,OAAO,MAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAC,KAAA,KAAU,KAAA,CAAM,IAAI,CAAC,CAAA;AACzD,EAAA,MAAM,IAAA,GAAO,SAAS,GAAA,CAAI,CAAC,UAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAC1D,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU;AAC9B,IAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,KAAA,CAAM,IAAI,GAAG,OAAO,IAAA;AACnC,IAAA,MAAM,QAAQ,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAChD,IAAA,IAAI,KAAA,KAAU,IAAI,OAAO,IAAA;AACzB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAO,CAAC,CAAA;AACpB,IAAA,OAAO,KAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEO,IAAM,IAAA,GAAO;AAAA,EAClB,YAAY,YAA0C;AAEpD,IAAA,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI,CAAC,IAAA,EAAK,EAAG,KAAK,EAAE,OAAA,EAAS,OAAA,EAAS,CAAC,CAAC,CAAA;AACnF,IAAA,OAAO,OAAA,CAAQ,QAAQ,UAAU,CAAA;AAAA,EACnC,CAAA;AAAA;AAAA,EAGA,MAAA,EAAQ,OAAO,IAAA,EAAc,KAAA,KAAoD;AAC/E,IAAA,MAAM,cAAc,MAAA,CAAO,WAAA;AAAA,MACzB,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,EAAE,MAAM,CAAC,GAAA,EAAK,MAAA,CAAO,EAAE,CAAC,CAAC;AAAA,KAC5D;AACA,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,EAAE,OAAO,IAAA,EAAM,GAAG,aAAa,CAAA;AACzD,IAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,EAAE,GAAE,CAAE,CAAA;AAAA,EACpF,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,UAAA,EAAY,MACV,YAAA,CAAa;AAAA;AAAA,MAEX,QAAA,EAAU,CAAC,MAAA,EAAQ,YAAA,EAAc,EAAE,KAAA,EAAO,cAAA,IAAkB,CAAA;AAAA,MAC5D,OAAA,EAAS,MAAM,IAAA,CAAK,UAAA;AAAW,KAChC,CAAA;AAAA,IAEH,MAAA,EAAQ,CAAC,IAAA,EAAc,KAAA,KACrB,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,QAAA,EAAU,MAAM,KAAK,CAAA;AAAA,MACxC,OAAA,EAAS,MAAM,IAAA,CAAK,MAAA,CAAO,MAAM,KAAK;AAAA,KACvC;AAAA;AAEP","file":"chunk-T55LMU5R.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { HomeComponentData } from '../types';\n\n/** The page a hook's blocks render on; blocks can target specific products, categories or pages. */\nexport type BlockScope =\n { product_id: number | string } | { category_id: number | string } | { page_id: number | string };\n\nasync function list(params?: Record<string, string>): Promise<HomeComponentData[]> {\n const query = params ? `?${new URLSearchParams(params).toString()}` : '';\n const { data } = await api.get(`component/list${query}`).json<{ data: HomeComponentData[] }>();\n return data ?? [];\n}\n\n/** `blocks` minus each of `excluded`, matched by content: the API sends no id or order to match on. */\nfunction without(blocks: HomeComponentData[], excluded: HomeComponentData[]): HomeComponentData[] {\n if (!excluded.length) return blocks;\n const paths = new Set(excluded.map((block) => block.path));\n const left = excluded.map((block) => JSON.stringify(block));\n return blocks.filter((block) => {\n if (!paths.has(block.path)) return true;\n const index = left.indexOf(JSON.stringify(block));\n if (index === -1) return true;\n left.splice(index, 1);\n return false;\n });\n}\n\nexport const home = {\n components: async (): Promise<HomeComponentData[]> => {\n // The unfiltered list also has the product, category and page blocks, which the home leaves out.\n const [blocks, pageBlocks] = await Promise.all([list(), list({ show_in: 'pages' })]);\n return without(blocks, pageBlocks);\n },\n\n /** The blocks the merchant placed at `hook` on a product, category or page. */\n blocks: async (hook: string, scope: BlockScope): Promise<HomeComponentData[]> => {\n const scopeParams = Object.fromEntries(\n Object.entries(scope).map(([key, id]) => [key, String(id)])\n );\n const blocks = await list({ hooks: hook, ...scopeParams });\n return blocks.map((block) => ({ ...block, path: block.path.replace('home.', '') }));\n },\n\n queries: {\n components: () =>\n queryOptions({\n // Each market (scope) has its own theme version, and its own home page with it.\n queryKey: ['home', 'components', { scope: getActiveScope() }],\n queryFn: () => home.components(),\n }),\n\n blocks: (hook: string, scope: BlockScope) =>\n queryOptions({\n queryKey: ['home', 'blocks', hook, scope],\n queryFn: () => home.blocks(hook, scope),\n }),\n },\n};\n"]}
1
+ {"version":3,"sources":["../src/api/home.ts"],"names":[],"mappings":";;;AAQA,eAAe,KAAK,MAAA,EAA+D;AACjF,EAAA,MAAM,KAAA,GAAQ,SAAS,CAAA,CAAA,EAAI,IAAI,gBAAgB,MAAM,CAAA,CAAE,QAAA,EAAU,CAAA,CAAA,GAAK,EAAA;AACtE,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,GAAA,CAAI,IAAI,CAAA,cAAA,EAAiB,KAAK,CAAA,CAAE,CAAA,CAAE,IAAA,EAAoC;AAC7F,EAAA,OAAO,QAAQ,EAAC;AAClB;AAGA,SAAS,OAAA,CAAQ,QAA6B,QAAA,EAAoD;AAChG,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAQ,OAAO,MAAA;AAC7B,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAC,KAAA,KAAU,KAAA,CAAM,IAAI,CAAC,CAAA;AACzD,EAAA,MAAM,IAAA,GAAO,SAAS,GAAA,CAAI,CAAC,UAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAC1D,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU;AAC9B,IAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,KAAA,CAAM,IAAI,GAAG,OAAO,IAAA;AACnC,IAAA,MAAM,QAAQ,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAChD,IAAA,IAAI,KAAA,KAAU,IAAI,OAAO,IAAA;AACzB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAO,CAAC,CAAA;AACpB,IAAA,OAAO,KAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEO,IAAM,IAAA,GAAO;AAAA,EAClB,YAAY,YAA0C;AAEpD,IAAA,MAAM,CAAC,MAAA,EAAQ,UAAU,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI,CAAC,IAAA,EAAK,EAAG,KAAK,EAAE,OAAA,EAAS,OAAA,EAAS,CAAC,CAAC,CAAA;AACnF,IAAA,OAAO,OAAA,CAAQ,QAAQ,UAAU,CAAA;AAAA,EACnC,CAAA;AAAA;AAAA,EAGA,MAAA,EAAQ,OAAO,IAAA,EAAc,KAAA,KAAoD;AAC/E,IAAA,MAAM,cAAc,MAAA,CAAO,WAAA;AAAA,MACzB,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,EAAE,MAAM,CAAC,GAAA,EAAK,MAAA,CAAO,EAAE,CAAC,CAAC;AAAA,KAC5D;AACA,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,EAAE,OAAO,IAAA,EAAM,GAAG,aAAa,CAAA;AACzD,IAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,EAAE,GAAE,CAAE,CAAA;AAAA,EACpF,CAAA;AAAA,EAEA,OAAA,EAAS;AAAA,IACP,UAAA,EAAY,MACV,YAAA,CAAa;AAAA;AAAA,MAEX,QAAA,EAAU,CAAC,MAAA,EAAQ,YAAA,EAAc,EAAE,KAAA,EAAO,cAAA,IAAkB,CAAA;AAAA,MAC5D,OAAA,EAAS,MAAM,IAAA,CAAK,UAAA;AAAW,KAChC,CAAA;AAAA,IAEH,MAAA,EAAQ,CAAC,IAAA,EAAc,KAAA,KACrB,YAAA,CAAa;AAAA,MACX,QAAA,EAAU,CAAC,MAAA,EAAQ,QAAA,EAAU,MAAM,KAAK,CAAA;AAAA,MACxC,OAAA,EAAS,MAAM,IAAA,CAAK,MAAA,CAAO,MAAM,KAAK;AAAA,KACvC;AAAA;AAEP","file":"chunk-RHMJ6VR7.js","sourcesContent":["import { queryOptions } from '@tanstack/react-query';\nimport { api, getActiveScope } from './client';\nimport type { HomeComponentData } from '../types';\n\n/** The page a hook's blocks render on; blocks can target specific products, categories or pages. */\nexport type BlockScope =\n { product_id: number | string } | { category_id: number | string } | { page_id: number | string };\n\nasync function list(params?: Record<string, string>): Promise<HomeComponentData[]> {\n const query = params ? `?${new URLSearchParams(params).toString()}` : '';\n const { data } = await api.get(`component/list${query}`).json<{ data: HomeComponentData[] }>();\n return data ?? [];\n}\n\n/** `blocks` minus each of `excluded`, matched by content: the API sends no id or order to match on. */\nfunction without(blocks: HomeComponentData[], excluded: HomeComponentData[]): HomeComponentData[] {\n if (!excluded.length) return blocks;\n const paths = new Set(excluded.map((block) => block.path));\n const left = excluded.map((block) => JSON.stringify(block));\n return blocks.filter((block) => {\n if (!paths.has(block.path)) return true;\n const index = left.indexOf(JSON.stringify(block));\n if (index === -1) return true;\n left.splice(index, 1);\n return false;\n });\n}\n\nexport const home = {\n components: async (): Promise<HomeComponentData[]> => {\n // The unfiltered list also has the product, category and page blocks, which the home leaves out.\n const [blocks, pageBlocks] = await Promise.all([list(), list({ show_in: 'pages' })]);\n return without(blocks, pageBlocks);\n },\n\n /** The blocks the merchant placed at `hook` on a product, category or page. */\n blocks: async (hook: string, scope: BlockScope): Promise<HomeComponentData[]> => {\n const scopeParams = Object.fromEntries(\n Object.entries(scope).map(([key, id]) => [key, String(id)])\n );\n const blocks = await list({ hooks: hook, ...scopeParams });\n return blocks.map((block) => ({ ...block, path: block.path.replace('home.', '') }));\n },\n\n queries: {\n components: () =>\n queryOptions({\n // Each market (scope) has its own theme version, and its own home page with it.\n queryKey: ['home', 'components', { scope: getActiveScope() }],\n queryFn: () => home.components(),\n }),\n\n blocks: (hook: string, scope: BlockScope) =>\n queryOptions({\n queryKey: ['home', 'blocks', hook, scope],\n queryFn: () => home.blocks(hook, scope),\n }),\n },\n};\n"]}
@@ -7,7 +7,7 @@ import { createIsomorphicFn } from '@tanstack/react-start';
7
7
  import { getCookie } from '@tanstack/react-start/server';
8
8
 
9
9
  // src/utils/engine-version.ts
10
- var ENGINE_VERSION = "1.0.130" ;
10
+ var ENGINE_VERSION = "1.0.131" ;
11
11
  var DEV_SETTINGS_TTL_MS = 60 * 6e4;
12
12
  var HIT_HEADER = "x-twilight-dev-cache";
13
13
  var FETCHED_AT_HEADER = "x-twilight-dev-fetched-at";
@@ -242,5 +242,5 @@ var filesCdn = ky.extend({
242
242
  });
243
243
 
244
244
  export { ENGINE_VERSION, STORE_IDENTIFIER_HEADER, api, cdn, devSettingsFetchedAt, filesCdn, getActiveCurrency, getActiveScope, getActiveScopeId, getAuthToken };
245
- //# sourceMappingURL=chunk-BSGHOYMT.js.map
246
- //# sourceMappingURL=chunk-BSGHOYMT.js.map
245
+ //# sourceMappingURL=chunk-SOQN5WKL.js.map
246
+ //# sourceMappingURL=chunk-SOQN5WKL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/engine-version.ts","../src/api/dev-settings-cache.ts","../src/api/client.ts"],"names":["entry","createIsomorphicFn","getCookie"],"mappings":"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","file":"chunk-BSGHOYMT.js","sourcesContent":["/**\n * The engine's own build version, injected by tsup `define` when dist is\n * built. Falls back to 'dev' when the source runs unbundled (vitest, direct\n * src imports in the monorepo).\n *\n * Exposed at runtime as `salla.versions.engine` by `useTwilightInit` so a\n * storefront can always be asked which engine build rendered it.\n */\nexport const ENGINE_VERSION: string =\n typeof __TWILIGHT_ENGINE_VERSION__ !== 'undefined' ? __TWILIGHT_ENGINE_VERSION__ : 'dev';\n","import type { AfterResponseHook, BeforeRequestHook } from 'ky';\nimport { createIsomorphicFn } from '@tanstack/react-start';\nimport { getCookie } from '@tanstack/react-start/server';\nimport { DEV_SETTINGS_REFRESH_COOKIE } from '../utils/dev-settings-refresh';\n\n/**\n * A dev server reuses a store's settings for up to an hour.\n *\n * Every server render asks the API for `store/settings`, and a developer clicking\n * around a theme renders dozens of pages a minute. The API answers a burst of\n * settings requests for one store from one address with a challenge, which a\n * server-side fetch cannot pass, so the dev server rendered \"Store Unavailable\"\n * (6.05k challenged `(development; ssr)` calls in the 7 days to 2026-10-25). In\n * development, on the server, the same request within {@link DEV_SETTINGS_TTL_MS}\n * is answered from memory instead. An hour because the API counts settings\n * requests per hour, so one fetch an hour can never reach its limit; the theme\n * editor's \"Fetch fresh store data\" fetches sooner, and says how old the settings\n * are. A production build never runs it: `import.meta.env.DEV` is statically\n * false there.\n */\nexport const DEV_SETTINGS_TTL_MS = 60 * 60_000;\n\n/** Marks an answer from memory, so the store step does not file it again. */\nconst HIT_HEADER = 'x-twilight-dev-cache';\n\n/** When the answer was really fetched from the API (epoch ms), on fresh answers and reused ones alike. */\nconst FETCHED_AT_HEADER = 'x-twilight-dev-fetched-at';\n\n/**\n * When the dev server fetched these settings from the API, read off the answer the\n * cache handed back; `undefined` when the cache did not handle the call (a\n * production build, the browser, a test), so nothing new reaches the settings there.\n */\nexport function devSettingsFetchedAt(headers: Headers | undefined): number | undefined {\n const at = Number(headers?.get(FETCHED_AT_HEADER));\n return Number.isFinite(at) && at > 0 ? at : undefined;\n}\n\n/**\n * Not carried over to an answer from memory: the body is stored decoded, so its\n * original encoding and length no longer describe it.\n */\nconst DROPPED_HEADERS = new Set(['content-encoding', 'content-length']);\n\ninterface Entry {\n body: string;\n status: number;\n statusText: string;\n headers: [string, string][];\n fetchedAt: number;\n /** The refresh cookie's value when this answer was fetched. */\n refresh: string | null;\n}\n\nexport interface DevSettingsCacheOptions {\n /** Whether this call may use the cache at all. */\n enabled: () => boolean;\n /** The current value of {@link DEV_SETTINGS_REFRESH_COOKIE}, or null. */\n refreshToken: () => string | null;\n now?: () => number;\n ttlMs?: number;\n /** Called the first time an answer comes from memory. */\n onFirstHit?: () => void;\n}\n\nfunction isSettingsRequest(request: Request): boolean {\n if (request.method !== 'GET') return false;\n try {\n return new URL(request.url).pathname.endsWith('/store/settings');\n } catch {\n return false;\n }\n}\n\n/**\n * An answer `requestSettings` accepts: JSON carrying `data`. A 200 without it is\n * refused there as \"Store Unavailable\"; kept here, it would be refused for the next\n * hour too, after the API had recovered.\n */\nfunction hasSettings(body: string): boolean {\n try {\n return Boolean((JSON.parse(body) as { data?: unknown } | null)?.data);\n } catch {\n return false;\n }\n}\n\n/**\n * The request as the API receives it: method, URL and every header the client's\n * hooks set. Keyed on the request itself rather than on the inputs that build it,\n * so a header added to the client later cannot be missing from the key.\n */\nfunction keyOf(request: Request): string {\n const headers = [...request.headers].map(([name, value]) => `${name}: ${value}`).join('\\n');\n return `${request.method} ${request.url}\\n${headers}`;\n}\n\n/**\n * The two ky hooks behind the cache: `lookup` runs last among `beforeRequest`, once\n * every header is set, and `store` among `afterResponse`. Only an answer with\n * settings in it is kept, so a timeout, a 429, a challenge or an empty 200 is asked\n * again on the next render.\n */\nexport function createDevSettingsCache(options: DevSettingsCacheOptions) {\n const {\n enabled,\n refreshToken,\n now = Date.now,\n ttlMs = DEV_SETTINGS_TTL_MS,\n onFirstHit,\n } = options;\n const entries = new Map<string, Entry>();\n let announced = false;\n\n const isFresh = (entry: Entry): boolean =>\n now() - entry.fetchedAt < ttlMs && entry.refresh === refreshToken();\n\n const answerOf = (entry: Entry, hit: boolean): Response => {\n const headers = new Headers(entry.headers);\n headers.set(FETCHED_AT_HEADER, String(entry.fetchedAt));\n if (hit) headers.set(HIT_HEADER, 'hit');\n return new Response(entry.body, {\n status: entry.status,\n statusText: entry.statusText,\n headers,\n });\n };\n\n const lookup: BeforeRequestHook = ({ request }) => {\n if (!enabled() || !isSettingsRequest(request)) return;\n const key = keyOf(request);\n const entry = entries.get(key);\n if (!entry) return;\n if (!isFresh(entry)) {\n entries.delete(key);\n return;\n }\n if (!announced) {\n announced = true;\n onFirstHit?.();\n }\n return answerOf(entry, true);\n };\n\n const store: AfterResponseHook = async ({ request, response }) => {\n if (!enabled() || !isSettingsRequest(request) || !response.ok) return;\n if (response.headers.has(HIT_HEADER)) return;\n // ky hands each hook a clone, so reading it leaves the answer it returns intact.\n const body = await response.text();\n if (!hasSettings(body)) return;\n for (const [key, entry] of entries) {\n if (now() - entry.fetchedAt >= ttlMs) entries.delete(key);\n }\n const entry: Entry = {\n body,\n status: response.status,\n statusText: response.statusText,\n headers: [...response.headers].filter(([name]) => !DROPPED_HEADERS.has(name)),\n fetchedAt: now(),\n refresh: refreshToken(),\n };\n entries.set(keyOf(request), entry);\n // Handed on in place of the API's own answer, so it carries its fetch time too.\n return answerOf(entry, false);\n };\n\n return { lookup, store, clear: () => entries.clear() };\n}\n\nconst readRefreshCookie = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getCookie(DEV_SETTINGS_REFRESH_COOKIE) ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => null);\n\nexport const devSettingsCache = createDevSettingsCache({\n // A dev server's render only. A production build has `DEV` statically false,\n // the browser keeps the settings it was handed in its query cache, and vitest\n // runs in `test` mode, where every test wants the request it mocked.\n enabled: () =>\n import.meta.env.DEV && import.meta.env.MODE !== 'test' && typeof document === 'undefined',\n refreshToken: readRefreshCookie,\n onFirstHit: () =>\n console.warn(\n `[twilight] Store settings are reused for up to ${DEV_SETTINGS_TTL_MS / 60_000} minutes while you develop, to stay under the Salla API's rate limit. To see a change you made in the dashboard, press \"Fetch fresh store data\" in the theme editor's side panel: it also says when they were last fetched.`\n ),\n});\n","import ky from 'ky';\nimport { createIsomorphicFn } from '@tanstack/react-start';\nimport { getCookie } from '@tanstack/react-start/server';\nimport { getStoreIdentifier } from '../utils/sdk-helpers';\nimport { resolveThemeVersionId } from '../utils/theme-version';\nimport { getInjectedRuntimeEnv, readEnv } from '../utils/runtime-env';\nimport { getTwilightContext } from '../twilight/context';\nimport { ENGINE_VERSION } from '../utils/engine-version';\nimport { devSettingsCache } from './dev-settings-cache';\nimport {\n AUTH_TOKEN_COOKIE_NAME,\n CURRENCY_COOKIE_NAME,\n extractCurrencyFromCookies,\n extractScopeFromCookies,\n toCurrencyCode,\n extractTokenFromCookies,\n readSdkScope,\n type ActiveScope,\n} from '../utils/cookies';\n\n// The twilight module store doesn't reliably carry authToken into every scope: on the\n// SERVER workerd has no AsyncLocalStorage, and on BOTH sides this api client can live in a\n// different module instance than the one rootBeforeLoad populates (engine subpath import vs\n// engine-internal relative import). So `getTwilightContext().authToken` is often null even\n// for logged-in users → API calls (orders/customer/…) return `token_not_provided` (400).\n// Read the token directly from the request cookie (server) or document.cookie / salla.storage\n// (client) as a fallback. The server-only import is stripped from the client bundle by\n// createIsomorphicFn.\nconst readFallbackToken = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getCookie(AUTH_TOKEN_COOKIE_NAME) ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => {\n const fromCookie =\n typeof document !== 'undefined'\n ? extractTokenFromCookies(document.cookie, AUTH_TOKEN_COOKIE_NAME)\n : null;\n if (fromCookie) return fromCookie;\n const storage = typeof window !== 'undefined' ? window.salla?.storage : undefined;\n const fromStorage =\n typeof storage?.get === 'function' ? storage.get(AUTH_TOKEN_COOKIE_NAME) : null;\n if (typeof fromStorage === 'string' && fromStorage) return fromStorage;\n // `?token=` webview injection lands only on the SDK's axios instance\n const fromSdkApi = typeof window !== 'undefined' ? window.salla?.api?.token : undefined;\n return typeof fromSdkApi === 'string' && fromSdkApi ? fromSdkApi : null;\n });\n\n/**\n * The auth token as the api client sees it: twilight context first, cookie/storage fallback.\n * Use this (not `getTwilightContext().authToken`, which is often null for logged-in users —\n * see the note above) to decide whether an authenticated-only query should run.\n */\nexport const getAuthToken = (): string | null =>\n getTwilightContext().authToken ?? readFallbackToken();\n\nconst readRequestCurrency = createIsomorphicFn()\n .server((): string | null => {\n try {\n return toCurrencyCode(getCookie(CURRENCY_COOKIE_NAME));\n } catch {\n return null;\n }\n })\n .client((): string | null => null);\n\n/**\n * The currency the visitor chose, from the `s-curr` cookie the SDK writes: the API\n * answers in the store's own currency unless the request names one.\n */\nexport function getActiveCurrency(): string | null;\nexport function getActiveCurrency(fallback: string): string;\nexport function getActiveCurrency(fallback: string | null = null): string | null {\n const chosen =\n typeof document !== 'undefined'\n ? extractCurrencyFromCookies(document.cookie)\n : readRequestCurrency();\n return chosen ?? fallback;\n}\n\nconst API_HEADERS = {\n ACCEPT: 'accept',\n ACCEPT_LANGUAGE: 'accept-language',\n APP_OS: 's-app-os',\n APP_VERSION: 's-app-version',\n RAY: 's-ray',\n SOURCE: 's-source',\n THEME_TYPE: 's-theme-type',\n STORE_API_VERSION: 's-store-api-version',\n REQUESTED_WITH: 'x-requested-with',\n CF_PROXY_WHITELIST: 's-cf-proxy-whitelist-id',\n STORE_IDENTIFIER: 'store-identifier',\n CURRENCY: 'currency',\n AUTHORIZATION: 'Authorization',\n VERSION_ID: 's-version-id',\n SCOPE_ID: 's-scope-id',\n SCOPE_TYPE: 's-scope-type',\n SCOPE_ALLOCATION_TYPE: 's-scope-allocation-type',\n SCOPE_ALLOCATION_ID: 's-scope-allocation-id',\n USER_AGENT: 'user-agent',\n} as const;\n\n/**\n * The header every Salla API call is answered by store.\n *\n * Exported because a caller that already knows which store it is asking about\n * must be able to say so on the request itself — see `store.settings`. Without\n * it the only way to name a store is the ambient resolver, and \"the identifier\n * I checked\" and \"the identifier that was sent\" become two different things.\n */\nexport const STORE_IDENTIFIER_HEADER = API_HEADERS.STORE_IDENTIFIER;\n\n/**\n * Active scope: the market plus its branch allocation, as the SDK stores it. On the\n * client it comes from `salla.storage.get('scope')`; before the SDK hydrates storage\n * it falls back to the `scope` cookie the theme mirrors that selection into (see\n * writeScopeCookie), then to the scope twilightMiddleware seeded from the same\n * cookie on the server. Requests vary by the `s-scope-*` headers, so React Query\n * keys must include this to avoid serving another branch's cached categories/products.\n *\n * The cookie step matters for hydration: the SDK is not guaranteed to have\n * populated `salla.storage` by the time the client rebuilds a dehydrated query\n * key, and without it the client would compute null against a scoped SSR key.\n */\nexport const getActiveScope = (): ActiveScope | null => {\n // `!== undefined`, not `!= null`: a null here is the SDK authoritatively saying \"no branch\n // selected\", which must beat a cookie left over from the previous selection. Only a\n // not-yet-ready storage API (undefined) falls through to the cookie.\n const fromStorage = readSdkScope();\n if (fromStorage !== undefined) return fromStorage;\n\n if (typeof document !== 'undefined') {\n const fromCookie = extractScopeFromCookies(document.cookie);\n if (fromCookie != null) return fromCookie;\n }\n\n try {\n return getTwilightContext().scope;\n } catch {\n return null;\n }\n};\n\n/** {@link getActiveScope} reduced to the market id. */\nexport const getActiveScopeId = (): string | null => getActiveScope()?.id ?? null;\n\nconst sharedHeaders = (locale: string) => ({\n [API_HEADERS.ACCEPT]: 'application/json' as const,\n [API_HEADERS.ACCEPT_LANGUAGE]: locale,\n [API_HEADERS.APP_OS]: 'browser',\n [API_HEADERS.APP_VERSION]: '2.14.363',\n [API_HEADERS.RAY]: '50',\n [API_HEADERS.SOURCE]: 'twilight',\n [API_HEADERS.THEME_TYPE]: 'react',\n [API_HEADERS.STORE_API_VERSION]: 'swoole',\n [API_HEADERS.REQUESTED_WITH]: 'XMLHttpRequest',\n [API_HEADERS.CF_PROXY_WHITELIST]: '019a2f78-a64c-7edb-proxy-whitelist-id-9a3a-17afda90f03a',\n});\n\n/**\n * Who a server-rendered call says it is.\n *\n * Every theme worker reaches api.salla.dev from Cloudflare's one Workers address, so\n * salla.dev's per-IP rate limits counted every React store as a single client and\n * refused the calls each page makes (`store/settings` among them: \"Store Unavailable\").\n * The zone skips rate limiting for a User-Agent shaped `Salla-<Name>/<N.N.N> (<env>; <meta>)`\n * from Cloudflare's or AWS's networks, the convention Salla's other services already send.\n *\n * Built from fixed parts: the zone's pattern takes only digits and dots for the version,\n * so a prerelease suffix is dropped, and an unbundled engine (`dev`) reads as `0.0.0`.\n */\nconst SERVER_USER_AGENT = `Salla-TwilightReact/${\n /^\\d+(?:\\.\\d+)*/.exec(ENGINE_VERSION)?.[0] ?? '0.0.0'\n} (${import.meta.env.DEV ? 'development' : 'production'}; ssr)`;\n\n/**\n * Store API base. `VITE_API_URL` override points a preview at a branch backend; unset → prod\n * `api.salla.dev`. Resolution order matters: the value the SSR worker resolved (published into\n * the head, since worker `vars` are server-only `process.env` and never reach the browser\n * bundle) wins, so the hydrated client keeps talking to the backend that rendered the page.\n */\n\nconst STORE_API_BASE =\n getInjectedRuntimeEnv().apiBase || readEnv('VITE_API_URL') || 'https://api.salla.dev/store/v1';\n\nexport const api = ky.extend({\n prefix: STORE_API_BASE,\n timeout: 8000,\n hooks: {\n beforeRequest: [\n ({ request }) => {\n const { locale, authToken } = getTwilightContext();\n const headers = sharedHeaders(locale);\n for (const [key, value] of Object.entries(headers)) {\n request.headers.set(key, value);\n }\n // Only when the caller did not say. `headers.set` here would otherwise\n // overwrite a per-request identifier with the ambient one, which is a\n // silent way to answer a question about one store with another's data.\n if (!request.headers.get(API_HEADERS.STORE_IDENTIFIER)) {\n request.headers.set(API_HEADERS.STORE_IDENTIFIER, getStoreIdentifier());\n }\n\n // Server only. A browser call comes from the shopper's own address and is\n // counted against it, which is what the zone's limits are for.\n if (typeof document === 'undefined') {\n request.headers.set(API_HEADERS.USER_AGENT, SERVER_USER_AGENT);\n }\n\n const scope = getActiveScope();\n\n // The version the request asked for, else the one the settings named for\n // this scope. Absent means \"whatever is live\", which is what an ordinary\n // storefront visit wants — so a null is left off rather than sent empty.\n const versionId = resolveThemeVersionId(scope?.id ?? null);\n if (versionId) {\n request.headers.set(API_HEADERS.VERSION_ID, versionId);\n }\n\n const currency = getActiveCurrency();\n if (currency) request.headers.set(API_HEADERS.CURRENCY, currency);\n\n const token = authToken ?? readFallbackToken();\n if (token) {\n request.headers.set(API_HEADERS.AUTHORIZATION, `Bearer ${token}`);\n }\n\n // The same four the SDK's own client sends. The API resolves stock per\n // allocation: id alone asks about the market, not the branch the shopper chose.\n if (scope) {\n request.headers.set(API_HEADERS.SCOPE_ID, scope.id);\n if (scope.type) request.headers.set(API_HEADERS.SCOPE_TYPE, scope.type);\n if (scope.allocation_type)\n request.headers.set(API_HEADERS.SCOPE_ALLOCATION_TYPE, scope.allocation_type);\n if (scope.allocation_id)\n request.headers.set(API_HEADERS.SCOPE_ALLOCATION_ID, scope.allocation_id);\n }\n },\n // Last, so it keys on the request with every header above set.\n devSettingsCache.lookup,\n ],\n afterResponse: [devSettingsCache.store],\n },\n});\n\nexport const cdn = ky.extend({\n prefix: 'https://cdn.salla.network',\n timeout: 5000,\n});\n\n/**\n * The merchant uploader's public bucket, `admin-uploader-prod`.\n *\n * A different host from {@link cdn} and a different thing behind it: this one\n * is an R2 custom domain, so a read never passes through a worker. Storefront\n * translations live here, per language, under `translations/` — see\n * `api/translations.ts`.\n */\nexport const filesCdn = ky.extend({\n prefix: 'https://cdn.files.salla.network',\n timeout: 5000,\n});\n"]}
1
+ {"version":3,"sources":["../src/utils/engine-version.ts","../src/api/dev-settings-cache.ts","../src/api/client.ts"],"names":["entry","createIsomorphicFn","getCookie"],"mappings":"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","file":"chunk-SOQN5WKL.js","sourcesContent":["/**\n * The engine's own build version, injected by tsup `define` when dist is\n * built. Falls back to 'dev' when the source runs unbundled (vitest, direct\n * src imports in the monorepo).\n *\n * Exposed at runtime as `salla.versions.engine` by `useTwilightInit` so a\n * storefront can always be asked which engine build rendered it.\n */\nexport const ENGINE_VERSION: string =\n typeof __TWILIGHT_ENGINE_VERSION__ !== 'undefined' ? __TWILIGHT_ENGINE_VERSION__ : 'dev';\n","import type { AfterResponseHook, BeforeRequestHook } from 'ky';\nimport { createIsomorphicFn } from '@tanstack/react-start';\nimport { getCookie } from '@tanstack/react-start/server';\nimport { DEV_SETTINGS_REFRESH_COOKIE } from '../utils/dev-settings-refresh';\n\n/**\n * A dev server reuses a store's settings for up to an hour.\n *\n * Every server render asks the API for `store/settings`, and a developer clicking\n * around a theme renders dozens of pages a minute. The API answers a burst of\n * settings requests for one store from one address with a challenge, which a\n * server-side fetch cannot pass, so the dev server rendered \"Store Unavailable\"\n * (6.05k challenged `(development; ssr)` calls in the 7 days to 2026-10-25). In\n * development, on the server, the same request within {@link DEV_SETTINGS_TTL_MS}\n * is answered from memory instead. An hour because the API counts settings\n * requests per hour, so one fetch an hour can never reach its limit; the theme\n * editor's \"Fetch fresh store data\" fetches sooner, and says how old the settings\n * are. A production build never runs it: `import.meta.env.DEV` is statically\n * false there.\n */\nexport const DEV_SETTINGS_TTL_MS = 60 * 60_000;\n\n/** Marks an answer from memory, so the store step does not file it again. */\nconst HIT_HEADER = 'x-twilight-dev-cache';\n\n/** When the answer was really fetched from the API (epoch ms), on fresh answers and reused ones alike. */\nconst FETCHED_AT_HEADER = 'x-twilight-dev-fetched-at';\n\n/**\n * When the dev server fetched these settings from the API, read off the answer the\n * cache handed back; `undefined` when the cache did not handle the call (a\n * production build, the browser, a test), so nothing new reaches the settings there.\n */\nexport function devSettingsFetchedAt(headers: Headers | undefined): number | undefined {\n const at = Number(headers?.get(FETCHED_AT_HEADER));\n return Number.isFinite(at) && at > 0 ? at : undefined;\n}\n\n/**\n * Not carried over to an answer from memory: the body is stored decoded, so its\n * original encoding and length no longer describe it.\n */\nconst DROPPED_HEADERS = new Set(['content-encoding', 'content-length']);\n\ninterface Entry {\n body: string;\n status: number;\n statusText: string;\n headers: [string, string][];\n fetchedAt: number;\n /** The refresh cookie's value when this answer was fetched. */\n refresh: string | null;\n}\n\nexport interface DevSettingsCacheOptions {\n /** Whether this call may use the cache at all. */\n enabled: () => boolean;\n /** The current value of {@link DEV_SETTINGS_REFRESH_COOKIE}, or null. */\n refreshToken: () => string | null;\n now?: () => number;\n ttlMs?: number;\n /** Called the first time an answer comes from memory. */\n onFirstHit?: () => void;\n}\n\nfunction isSettingsRequest(request: Request): boolean {\n if (request.method !== 'GET') return false;\n try {\n return new URL(request.url).pathname.endsWith('/store/settings');\n } catch {\n return false;\n }\n}\n\n/**\n * An answer `requestSettings` accepts: JSON carrying `data`. A 200 without it is\n * refused there as \"Store Unavailable\"; kept here, it would be refused for the next\n * hour too, after the API had recovered.\n */\nfunction hasSettings(body: string): boolean {\n try {\n return Boolean((JSON.parse(body) as { data?: unknown } | null)?.data);\n } catch {\n return false;\n }\n}\n\n/**\n * The request as the API receives it: method, URL and every header the client's\n * hooks set. Keyed on the request itself rather than on the inputs that build it,\n * so a header added to the client later cannot be missing from the key.\n */\nfunction keyOf(request: Request): string {\n const headers = [...request.headers].map(([name, value]) => `${name}: ${value}`).join('\\n');\n return `${request.method} ${request.url}\\n${headers}`;\n}\n\n/**\n * The two ky hooks behind the cache: `lookup` runs last among `beforeRequest`, once\n * every header is set, and `store` among `afterResponse`. Only an answer with\n * settings in it is kept, so a timeout, a 429, a challenge or an empty 200 is asked\n * again on the next render.\n */\nexport function createDevSettingsCache(options: DevSettingsCacheOptions) {\n const {\n enabled,\n refreshToken,\n now = Date.now,\n ttlMs = DEV_SETTINGS_TTL_MS,\n onFirstHit,\n } = options;\n const entries = new Map<string, Entry>();\n let announced = false;\n\n const isFresh = (entry: Entry): boolean =>\n now() - entry.fetchedAt < ttlMs && entry.refresh === refreshToken();\n\n const answerOf = (entry: Entry, hit: boolean): Response => {\n const headers = new Headers(entry.headers);\n headers.set(FETCHED_AT_HEADER, String(entry.fetchedAt));\n if (hit) headers.set(HIT_HEADER, 'hit');\n return new Response(entry.body, {\n status: entry.status,\n statusText: entry.statusText,\n headers,\n });\n };\n\n const lookup: BeforeRequestHook = ({ request }) => {\n if (!enabled() || !isSettingsRequest(request)) return;\n const key = keyOf(request);\n const entry = entries.get(key);\n if (!entry) return;\n if (!isFresh(entry)) {\n entries.delete(key);\n return;\n }\n if (!announced) {\n announced = true;\n onFirstHit?.();\n }\n return answerOf(entry, true);\n };\n\n const store: AfterResponseHook = async ({ request, response }) => {\n if (!enabled() || !isSettingsRequest(request) || !response.ok) return;\n if (response.headers.has(HIT_HEADER)) return;\n // ky hands each hook a clone, so reading it leaves the answer it returns intact.\n const body = await response.text();\n if (!hasSettings(body)) return;\n for (const [key, entry] of entries) {\n if (now() - entry.fetchedAt >= ttlMs) entries.delete(key);\n }\n const entry: Entry = {\n body,\n status: response.status,\n statusText: response.statusText,\n headers: [...response.headers].filter(([name]) => !DROPPED_HEADERS.has(name)),\n fetchedAt: now(),\n refresh: refreshToken(),\n };\n entries.set(keyOf(request), entry);\n // Handed on in place of the API's own answer, so it carries its fetch time too.\n return answerOf(entry, false);\n };\n\n return { lookup, store, clear: () => entries.clear() };\n}\n\nconst readRefreshCookie = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getCookie(DEV_SETTINGS_REFRESH_COOKIE) ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => null);\n\nexport const devSettingsCache = createDevSettingsCache({\n // A dev server's render only. A production build has `DEV` statically false,\n // the browser keeps the settings it was handed in its query cache, and vitest\n // runs in `test` mode, where every test wants the request it mocked.\n enabled: () =>\n import.meta.env.DEV && import.meta.env.MODE !== 'test' && typeof document === 'undefined',\n refreshToken: readRefreshCookie,\n onFirstHit: () =>\n console.warn(\n `[twilight] Store settings are reused for up to ${DEV_SETTINGS_TTL_MS / 60_000} minutes while you develop, to stay under the Salla API's rate limit. To see a change you made in the dashboard, press \"Fetch fresh store data\" in the theme editor's side panel: it also says when they were last fetched.`\n ),\n});\n","import ky from 'ky';\nimport { createIsomorphicFn } from '@tanstack/react-start';\nimport { getCookie } from '@tanstack/react-start/server';\nimport { getStoreIdentifier } from '../utils/sdk-helpers';\nimport { resolveThemeVersionId } from '../utils/theme-version';\nimport { getInjectedRuntimeEnv, readEnv } from '../utils/runtime-env';\nimport { getTwilightContext } from '../twilight/context';\nimport { ENGINE_VERSION } from '../utils/engine-version';\nimport { devSettingsCache } from './dev-settings-cache';\nimport {\n AUTH_TOKEN_COOKIE_NAME,\n CURRENCY_COOKIE_NAME,\n extractCurrencyFromCookies,\n extractScopeFromCookies,\n toCurrencyCode,\n extractTokenFromCookies,\n readSdkScope,\n type ActiveScope,\n} from '../utils/cookies';\n\n// The twilight module store doesn't reliably carry authToken into every scope: on the\n// SERVER workerd has no AsyncLocalStorage, and on BOTH sides this api client can live in a\n// different module instance than the one rootBeforeLoad populates (engine subpath import vs\n// engine-internal relative import). So `getTwilightContext().authToken` is often null even\n// for logged-in users → API calls (orders/customer/…) return `token_not_provided` (400).\n// Read the token directly from the request cookie (server) or document.cookie / salla.storage\n// (client) as a fallback. The server-only import is stripped from the client bundle by\n// createIsomorphicFn.\nconst readFallbackToken = createIsomorphicFn()\n .server((): string | null => {\n try {\n return getCookie(AUTH_TOKEN_COOKIE_NAME) ?? null;\n } catch {\n return null;\n }\n })\n .client((): string | null => {\n const fromCookie =\n typeof document !== 'undefined'\n ? extractTokenFromCookies(document.cookie, AUTH_TOKEN_COOKIE_NAME)\n : null;\n if (fromCookie) return fromCookie;\n const storage = typeof window !== 'undefined' ? window.salla?.storage : undefined;\n const fromStorage =\n typeof storage?.get === 'function' ? storage.get(AUTH_TOKEN_COOKIE_NAME) : null;\n if (typeof fromStorage === 'string' && fromStorage) return fromStorage;\n // `?token=` webview injection lands only on the SDK's axios instance\n const fromSdkApi = typeof window !== 'undefined' ? window.salla?.api?.token : undefined;\n return typeof fromSdkApi === 'string' && fromSdkApi ? fromSdkApi : null;\n });\n\n/**\n * The auth token as the api client sees it: twilight context first, cookie/storage fallback.\n * Use this (not `getTwilightContext().authToken`, which is often null for logged-in users —\n * see the note above) to decide whether an authenticated-only query should run.\n */\nexport const getAuthToken = (): string | null =>\n getTwilightContext().authToken ?? readFallbackToken();\n\nconst readRequestCurrency = createIsomorphicFn()\n .server((): string | null => {\n try {\n return toCurrencyCode(getCookie(CURRENCY_COOKIE_NAME));\n } catch {\n return null;\n }\n })\n .client((): string | null => null);\n\n/**\n * The currency the visitor chose, from the `s-curr` cookie the SDK writes: the API\n * answers in the store's own currency unless the request names one.\n */\nexport function getActiveCurrency(): string | null;\nexport function getActiveCurrency(fallback: string): string;\nexport function getActiveCurrency(fallback: string | null = null): string | null {\n const chosen =\n typeof document !== 'undefined'\n ? extractCurrencyFromCookies(document.cookie)\n : readRequestCurrency();\n return chosen ?? fallback;\n}\n\nconst API_HEADERS = {\n ACCEPT: 'accept',\n ACCEPT_LANGUAGE: 'accept-language',\n APP_OS: 's-app-os',\n APP_VERSION: 's-app-version',\n RAY: 's-ray',\n SOURCE: 's-source',\n THEME_TYPE: 's-theme-type',\n STORE_API_VERSION: 's-store-api-version',\n REQUESTED_WITH: 'x-requested-with',\n CF_PROXY_WHITELIST: 's-cf-proxy-whitelist-id',\n STORE_IDENTIFIER: 'store-identifier',\n CURRENCY: 'currency',\n AUTHORIZATION: 'Authorization',\n VERSION_ID: 's-version-id',\n SCOPE_ID: 's-scope-id',\n SCOPE_TYPE: 's-scope-type',\n SCOPE_ALLOCATION_TYPE: 's-scope-allocation-type',\n SCOPE_ALLOCATION_ID: 's-scope-allocation-id',\n USER_AGENT: 'user-agent',\n} as const;\n\n/**\n * The header every Salla API call is answered by store.\n *\n * Exported because a caller that already knows which store it is asking about\n * must be able to say so on the request itself — see `store.settings`. Without\n * it the only way to name a store is the ambient resolver, and \"the identifier\n * I checked\" and \"the identifier that was sent\" become two different things.\n */\nexport const STORE_IDENTIFIER_HEADER = API_HEADERS.STORE_IDENTIFIER;\n\n/**\n * Active scope: the market plus its branch allocation, as the SDK stores it. On the\n * client it comes from `salla.storage.get('scope')`; before the SDK hydrates storage\n * it falls back to the `scope` cookie the theme mirrors that selection into (see\n * writeScopeCookie), then to the scope twilightMiddleware seeded from the same\n * cookie on the server. Requests vary by the `s-scope-*` headers, so React Query\n * keys must include this to avoid serving another branch's cached categories/products.\n *\n * The cookie step matters for hydration: the SDK is not guaranteed to have\n * populated `salla.storage` by the time the client rebuilds a dehydrated query\n * key, and without it the client would compute null against a scoped SSR key.\n */\nexport const getActiveScope = (): ActiveScope | null => {\n // `!== undefined`, not `!= null`: a null here is the SDK authoritatively saying \"no branch\n // selected\", which must beat a cookie left over from the previous selection. Only a\n // not-yet-ready storage API (undefined) falls through to the cookie.\n const fromStorage = readSdkScope();\n if (fromStorage !== undefined) return fromStorage;\n\n if (typeof document !== 'undefined') {\n const fromCookie = extractScopeFromCookies(document.cookie);\n if (fromCookie != null) return fromCookie;\n }\n\n try {\n return getTwilightContext().scope;\n } catch {\n return null;\n }\n};\n\n/** {@link getActiveScope} reduced to the market id. */\nexport const getActiveScopeId = (): string | null => getActiveScope()?.id ?? null;\n\nconst sharedHeaders = (locale: string) => ({\n [API_HEADERS.ACCEPT]: 'application/json' as const,\n [API_HEADERS.ACCEPT_LANGUAGE]: locale,\n [API_HEADERS.APP_OS]: 'browser',\n [API_HEADERS.APP_VERSION]: '2.14.363',\n [API_HEADERS.RAY]: '50',\n [API_HEADERS.SOURCE]: 'twilight',\n [API_HEADERS.THEME_TYPE]: 'react',\n [API_HEADERS.STORE_API_VERSION]: 'swoole',\n [API_HEADERS.REQUESTED_WITH]: 'XMLHttpRequest',\n [API_HEADERS.CF_PROXY_WHITELIST]: '019a2f78-a64c-7edb-proxy-whitelist-id-9a3a-17afda90f03a',\n});\n\n/**\n * Who a server-rendered call says it is.\n *\n * Every theme worker reaches api.salla.dev from Cloudflare's one Workers address, so\n * salla.dev's per-IP rate limits counted every React store as a single client and\n * refused the calls each page makes (`store/settings` among them: \"Store Unavailable\").\n * The zone skips rate limiting for a User-Agent shaped `Salla-<Name>/<N.N.N> (<env>; <meta>)`\n * from Cloudflare's or AWS's networks, the convention Salla's other services already send.\n *\n * Built from fixed parts: the zone's pattern takes only digits and dots for the version,\n * so a prerelease suffix is dropped, and an unbundled engine (`dev`) reads as `0.0.0`.\n */\nconst SERVER_USER_AGENT = `Salla-TwilightReact/${\n /^\\d+(?:\\.\\d+)*/.exec(ENGINE_VERSION)?.[0] ?? '0.0.0'\n} (${import.meta.env.DEV ? 'development' : 'production'}; ssr)`;\n\n/**\n * Store API base. `VITE_API_URL` override points a preview at a branch backend; unset → prod\n * `api.salla.dev`. Resolution order matters: the value the SSR worker resolved (published into\n * the head, since worker `vars` are server-only `process.env` and never reach the browser\n * bundle) wins, so the hydrated client keeps talking to the backend that rendered the page.\n */\n\nconst STORE_API_BASE =\n getInjectedRuntimeEnv().apiBase || readEnv('VITE_API_URL') || 'https://api.salla.dev/store/v1';\n\nexport const api = ky.extend({\n prefix: STORE_API_BASE,\n timeout: 8000,\n hooks: {\n beforeRequest: [\n ({ request }) => {\n const { locale, authToken } = getTwilightContext();\n const headers = sharedHeaders(locale);\n for (const [key, value] of Object.entries(headers)) {\n request.headers.set(key, value);\n }\n // Only when the caller did not say. `headers.set` here would otherwise\n // overwrite a per-request identifier with the ambient one, which is a\n // silent way to answer a question about one store with another's data.\n if (!request.headers.get(API_HEADERS.STORE_IDENTIFIER)) {\n request.headers.set(API_HEADERS.STORE_IDENTIFIER, getStoreIdentifier());\n }\n\n // Server only. A browser call comes from the shopper's own address and is\n // counted against it, which is what the zone's limits are for.\n if (typeof document === 'undefined') {\n request.headers.set(API_HEADERS.USER_AGENT, SERVER_USER_AGENT);\n }\n\n const scope = getActiveScope();\n\n // The version the request asked for, else the one the settings named for\n // this scope. Absent means \"whatever is live\", which is what an ordinary\n // storefront visit wants — so a null is left off rather than sent empty.\n const versionId = resolveThemeVersionId(scope?.id ?? null);\n if (versionId) {\n request.headers.set(API_HEADERS.VERSION_ID, versionId);\n }\n\n const currency = getActiveCurrency();\n if (currency) request.headers.set(API_HEADERS.CURRENCY, currency);\n\n const token = authToken ?? readFallbackToken();\n if (token) {\n request.headers.set(API_HEADERS.AUTHORIZATION, `Bearer ${token}`);\n }\n\n // The same four the SDK's own client sends. The API resolves stock per\n // allocation: id alone asks about the market, not the branch the shopper chose.\n if (scope) {\n request.headers.set(API_HEADERS.SCOPE_ID, scope.id);\n if (scope.type) request.headers.set(API_HEADERS.SCOPE_TYPE, scope.type);\n if (scope.allocation_type)\n request.headers.set(API_HEADERS.SCOPE_ALLOCATION_TYPE, scope.allocation_type);\n if (scope.allocation_id)\n request.headers.set(API_HEADERS.SCOPE_ALLOCATION_ID, scope.allocation_id);\n }\n },\n // Last, so it keys on the request with every header above set.\n devSettingsCache.lookup,\n ],\n afterResponse: [devSettingsCache.store],\n },\n});\n\nexport const cdn = ky.extend({\n prefix: 'https://cdn.salla.network',\n timeout: 5000,\n});\n\n/**\n * The merchant uploader's public bucket, `admin-uploader-prod`.\n *\n * A different host from {@link cdn} and a different thing behind it: this one\n * is an R2 custom domain, so a read never passes through a worker. Storefront\n * translations live here, per language, under `translations/` — see\n * `api/translations.ts`.\n */\nexport const filesCdn = ky.extend({\n prefix: 'https://cdn.files.salla.network',\n timeout: 5000,\n});\n"]}
@@ -1,9 +1,9 @@
1
1
  import { registry } from './chunk-Y32RHCOH.js';
2
- import { useMoney, useNumber } from './chunk-CGDUSBLK.js';
2
+ import { useMoney, useNumber } from './chunk-GHACVKKD.js';
3
3
  import { useAsset } from './chunk-Z653O7MX.js';
4
4
  import { useWishlist } from './chunk-JGVEGQHJ.js';
5
5
  import { useTranslation } from './chunk-TYNZ5B2B.js';
6
- import { Image } from './chunk-IUEYRDEI.js';
6
+ import { Image } from './chunk-MYW5QYWO.js';
7
7
  import { LazyImageModal } from './chunk-7V5HOZW4.js';
8
8
  import { isNativeApp } from './chunk-2TLIULJZ.js';
9
9
  import { useTwilight } from './chunk-DF6FBKDN.js';
@@ -15,10 +15,10 @@ import { jsxs, jsx } from 'react/jsx-runtime';
15
15
  import { SallaSlider } from '@salla.sa/twilight-components-react/slider';
16
16
 
17
17
  var LazyProductDetails = lazy(
18
- () => import('./ProductDetails-JFOFLMLV.js').then((m) => ({ default: m.ProductDetails }))
18
+ () => import('./ProductDetails-FWN3T7H7.js').then((m) => ({ default: m.ProductDetails }))
19
19
  );
20
20
  var LazyAddToCartForm = lazy(
21
- () => import('./AddToCartForm-ZJIIU4I4.js').then((m) => ({ default: m.AddToCartForm }))
21
+ () => import('./AddToCartForm-S73TIRFL.js').then((m) => ({ default: m.AddToCartForm }))
22
22
  );
23
23
  var PRODUCT_CARD_KEY = "product:card";
24
24
  var PRODUCT_IMAGE_SRCSET_WIDTHS = [150, 300, 450, 600];
@@ -421,5 +421,5 @@ function ThumbSlide({ image, index }) {
421
421
  }
422
422
 
423
423
  export { LazyAddToCartForm, LazyProductDetails, ProductCard, ProductGallery };
424
- //# sourceMappingURL=chunk-5JN6P5L5.js.map
425
- //# sourceMappingURL=chunk-5JN6P5L5.js.map
424
+ //# sourceMappingURL=chunk-TUW2BXB3.js.map
425
+ //# sourceMappingURL=chunk-TUW2BXB3.js.map