medusa-storefront-data 2.4.0 → 2.5.3

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 (214) hide show
  1. package/HOMEPAGE_CONFIG.md +113 -6
  2. package/package.json +6 -116
  3. package/src/server/brand-pillars-from-categories.ts +156 -0
  4. package/src/server/cart.ts +21 -21
  5. package/src/server/customer.ts +11 -11
  6. package/src/server/dynamic-config.ts +130 -181
  7. package/src/server/fulfillment.ts +3 -3
  8. package/src/server/help-faq-section-defaults.json +92 -0
  9. package/src/server/help-sections/help-faq.ts +25 -0
  10. package/src/server/help-sections/index.ts +8 -0
  11. package/src/server/home.ts +36 -211
  12. package/src/server/homepage-config.types.ts +24 -0
  13. package/src/server/homepage-section-defaults.ts +3 -0
  14. package/src/server/normalize-homepage-config.ts +279 -0
  15. package/src/server/orders.ts +6 -6
  16. package/src/server/page-input.ts +3 -1
  17. package/src/server/payment-details.ts +5 -5
  18. package/src/server/payment.ts +2 -2
  19. package/src/server/regions.ts +2 -2
  20. package/src/server/shoppable-looks.ts +1 -1
  21. package/src/util/store-client.ts +0 -3
  22. package/dist/segment-data/default-page-input.json +0 -191
  23. package/dist/src/config.d.ts +0 -3
  24. package/dist/src/config.d.ts.map +0 -1
  25. package/dist/src/config.js +0 -31
  26. package/dist/src/cookies.d.ts +0 -23
  27. package/dist/src/cookies.d.ts.map +0 -1
  28. package/dist/src/cookies.js +0 -140
  29. package/dist/src/edge.d.ts +0 -3
  30. package/dist/src/edge.d.ts.map +0 -1
  31. package/dist/src/edge.js +0 -1
  32. package/dist/src/middleware.d.ts +0 -3
  33. package/dist/src/middleware.d.ts.map +0 -1
  34. package/dist/src/middleware.js +0 -1
  35. package/dist/src/server/cart.d.ts +0 -96
  36. package/dist/src/server/cart.d.ts.map +0 -1
  37. package/dist/src/server/cart.js +0 -797
  38. package/dist/src/server/categories.d.ts +0 -4
  39. package/dist/src/server/categories.d.ts.map +0 -1
  40. package/dist/src/server/categories.js +0 -34
  41. package/dist/src/server/collections.d.ts +0 -8
  42. package/dist/src/server/collections.d.ts.map +0 -1
  43. package/dist/src/server/collections.js +0 -39
  44. package/dist/src/server/config-merge.d.ts +0 -3
  45. package/dist/src/server/config-merge.d.ts.map +0 -1
  46. package/dist/src/server/config-merge.js +0 -31
  47. package/dist/src/server/contact.d.ts +0 -34
  48. package/dist/src/server/contact.d.ts.map +0 -1
  49. package/dist/src/server/contact.js +0 -57
  50. package/dist/src/server/customer-registration.d.ts +0 -142
  51. package/dist/src/server/customer-registration.d.ts.map +0 -1
  52. package/dist/src/server/customer-registration.js +0 -295
  53. package/dist/src/server/customer.d.ts +0 -48
  54. package/dist/src/server/customer.d.ts.map +0 -1
  55. package/dist/src/server/customer.js +0 -413
  56. package/dist/src/server/dynamic-config.d.ts +0 -240
  57. package/dist/src/server/dynamic-config.d.ts.map +0 -1
  58. package/dist/src/server/dynamic-config.js +0 -703
  59. package/dist/src/server/fulfillment.d.ts +0 -5
  60. package/dist/src/server/fulfillment.d.ts.map +0 -1
  61. package/dist/src/server/fulfillment.js +0 -47
  62. package/dist/src/server/guest.d.ts +0 -81
  63. package/dist/src/server/guest.d.ts.map +0 -1
  64. package/dist/src/server/guest.js +0 -183
  65. package/dist/src/server/home-sections/about-brand.d.ts +0 -9
  66. package/dist/src/server/home-sections/about-brand.d.ts.map +0 -1
  67. package/dist/src/server/home-sections/about-brand.js +0 -9
  68. package/dist/src/server/home-sections/baptism-picks.d.ts +0 -10
  69. package/dist/src/server/home-sections/baptism-picks.d.ts.map +0 -1
  70. package/dist/src/server/home-sections/baptism-picks.js +0 -27
  71. package/dist/src/server/home-sections/baptism.d.ts +0 -13
  72. package/dist/src/server/home-sections/baptism.d.ts.map +0 -1
  73. package/dist/src/server/home-sections/baptism.js +0 -43
  74. package/dist/src/server/home-sections/blog-posts.d.ts +0 -9
  75. package/dist/src/server/home-sections/blog-posts.d.ts.map +0 -1
  76. package/dist/src/server/home-sections/blog-posts.js +0 -9
  77. package/dist/src/server/home-sections/brand-marquee.d.ts +0 -8
  78. package/dist/src/server/home-sections/brand-marquee.d.ts.map +0 -1
  79. package/dist/src/server/home-sections/brand-marquee.js +0 -7
  80. package/dist/src/server/home-sections/brand-pillars.d.ts +0 -9
  81. package/dist/src/server/home-sections/brand-pillars.d.ts.map +0 -1
  82. package/dist/src/server/home-sections/brand-pillars.js +0 -9
  83. package/dist/src/server/home-sections/category-pills.d.ts +0 -9
  84. package/dist/src/server/home-sections/category-pills.d.ts.map +0 -1
  85. package/dist/src/server/home-sections/category-pills.js +0 -19
  86. package/dist/src/server/home-sections/celebrity-trust.d.ts +0 -12
  87. package/dist/src/server/home-sections/celebrity-trust.d.ts.map +0 -1
  88. package/dist/src/server/home-sections/celebrity-trust.js +0 -27
  89. package/dist/src/server/home-sections/features.d.ts +0 -9
  90. package/dist/src/server/home-sections/features.d.ts.map +0 -1
  91. package/dist/src/server/home-sections/features.js +0 -9
  92. package/dist/src/server/home-sections/hero.d.ts +0 -9
  93. package/dist/src/server/home-sections/hero.d.ts.map +0 -1
  94. package/dist/src/server/home-sections/hero.js +0 -9
  95. package/dist/src/server/home-sections/instagram-posts.d.ts +0 -9
  96. package/dist/src/server/home-sections/instagram-posts.d.ts.map +0 -1
  97. package/dist/src/server/home-sections/instagram-posts.js +0 -9
  98. package/dist/src/server/home-sections/loved-by-moms.d.ts +0 -12
  99. package/dist/src/server/home-sections/loved-by-moms.d.ts.map +0 -1
  100. package/dist/src/server/home-sections/loved-by-moms.js +0 -20
  101. package/dist/src/server/home-sections/luxe-favourites.d.ts +0 -11
  102. package/dist/src/server/home-sections/luxe-favourites.d.ts.map +0 -1
  103. package/dist/src/server/home-sections/luxe-favourites.js +0 -19
  104. package/dist/src/server/home-sections/new-arrivals-classic.d.ts +0 -8
  105. package/dist/src/server/home-sections/new-arrivals-classic.d.ts.map +0 -1
  106. package/dist/src/server/home-sections/new-arrivals-classic.js +0 -10
  107. package/dist/src/server/home-sections/new-arrivals.d.ts +0 -12
  108. package/dist/src/server/home-sections/new-arrivals.d.ts.map +0 -1
  109. package/dist/src/server/home-sections/new-arrivals.js +0 -28
  110. package/dist/src/server/home-sections/promo-announcements.d.ts +0 -7
  111. package/dist/src/server/home-sections/promo-announcements.d.ts.map +0 -1
  112. package/dist/src/server/home-sections/promo-announcements.js +0 -7
  113. package/dist/src/server/home-sections/promo-countdown.d.ts +0 -6
  114. package/dist/src/server/home-sections/promo-countdown.d.ts.map +0 -1
  115. package/dist/src/server/home-sections/promo-countdown.js +0 -5
  116. package/dist/src/server/home-sections/shared.d.ts +0 -10
  117. package/dist/src/server/home-sections/shared.d.ts.map +0 -1
  118. package/dist/src/server/home-sections/shared.js +0 -29
  119. package/dist/src/server/home-sections/shop-by-age.d.ts +0 -9
  120. package/dist/src/server/home-sections/shop-by-age.d.ts.map +0 -1
  121. package/dist/src/server/home-sections/shop-by-age.js +0 -17
  122. package/dist/src/server/home-sections/shop-by-category.d.ts +0 -10
  123. package/dist/src/server/home-sections/shop-by-category.d.ts.map +0 -1
  124. package/dist/src/server/home-sections/shop-by-category.js +0 -17
  125. package/dist/src/server/home-sections/testimonials.d.ts +0 -9
  126. package/dist/src/server/home-sections/testimonials.d.ts.map +0 -1
  127. package/dist/src/server/home-sections/testimonials.js +0 -9
  128. package/dist/src/server/home-sections/theme-dresses.d.ts +0 -12
  129. package/dist/src/server/home-sections/theme-dresses.d.ts.map +0 -1
  130. package/dist/src/server/home-sections/theme-dresses.js +0 -27
  131. package/dist/src/server/home-sections/video-stories.d.ts +0 -9
  132. package/dist/src/server/home-sections/video-stories.d.ts.map +0 -1
  133. package/dist/src/server/home-sections/video-stories.js +0 -9
  134. package/dist/src/server/home-sections/why-choose-us.d.ts +0 -9
  135. package/dist/src/server/home-sections/why-choose-us.d.ts.map +0 -1
  136. package/dist/src/server/home-sections/why-choose-us.js +0 -9
  137. package/dist/src/server/home.d.ts +0 -62
  138. package/dist/src/server/home.d.ts.map +0 -1
  139. package/dist/src/server/home.js +0 -122
  140. package/dist/src/server/homepage-config.types.d.ts +0 -274
  141. package/dist/src/server/homepage-config.types.d.ts.map +0 -1
  142. package/dist/src/server/homepage-config.types.js +0 -33
  143. package/dist/src/server/homepage-section-defaults.d.ts +0 -188
  144. package/dist/src/server/homepage-section-defaults.d.ts.map +0 -1
  145. package/dist/src/server/homepage-section-defaults.js +0 -188
  146. package/dist/src/server/index.d.ts +0 -25
  147. package/dist/src/server/index.d.ts.map +0 -1
  148. package/dist/src/server/index.js +0 -24
  149. package/dist/src/server/locale-actions.d.ts +0 -14
  150. package/dist/src/server/locale-actions.d.ts.map +0 -1
  151. package/dist/src/server/locale-actions.js +0 -58
  152. package/dist/src/server/locales.d.ts +0 -8
  153. package/dist/src/server/locales.d.ts.map +0 -1
  154. package/dist/src/server/locales.js +0 -12
  155. package/dist/src/server/notifications.d.ts +0 -2
  156. package/dist/src/server/notifications.d.ts.map +0 -1
  157. package/dist/src/server/notifications.js +0 -20
  158. package/dist/src/server/onboarding.d.ts +0 -2
  159. package/dist/src/server/onboarding.d.ts.map +0 -1
  160. package/dist/src/server/onboarding.js +0 -8
  161. package/dist/src/server/orders.d.ts +0 -63
  162. package/dist/src/server/orders.d.ts.map +0 -1
  163. package/dist/src/server/orders.js +0 -230
  164. package/dist/src/server/page-input.d.ts +0 -19
  165. package/dist/src/server/page-input.d.ts.map +0 -1
  166. package/dist/src/server/page-input.js +0 -40
  167. package/dist/src/server/payment-details.d.ts +0 -5
  168. package/dist/src/server/payment-details.d.ts.map +0 -1
  169. package/dist/src/server/payment-details.js +0 -28
  170. package/dist/src/server/payment.d.ts +0 -3
  171. package/dist/src/server/payment.d.ts.map +0 -1
  172. package/dist/src/server/payment.js +0 -13
  173. package/dist/src/server/pincode.d.ts +0 -7
  174. package/dist/src/server/pincode.d.ts.map +0 -1
  175. package/dist/src/server/pincode.js +0 -30
  176. package/dist/src/server/products.d.ts +0 -54
  177. package/dist/src/server/products.d.ts.map +0 -1
  178. package/dist/src/server/products.js +0 -154
  179. package/dist/src/server/regions.d.ts +0 -5
  180. package/dist/src/server/regions.d.ts.map +0 -1
  181. package/dist/src/server/regions.js +0 -57
  182. package/dist/src/server/resolve-home-segment-data.d.ts +0 -25
  183. package/dist/src/server/resolve-home-segment-data.d.ts.map +0 -1
  184. package/dist/src/server/resolve-home-segment-data.js +0 -20
  185. package/dist/src/server/returns.d.ts +0 -29
  186. package/dist/src/server/returns.d.ts.map +0 -1
  187. package/dist/src/server/returns.js +0 -132
  188. package/dist/src/server/shoppable-looks.d.ts +0 -17
  189. package/dist/src/server/shoppable-looks.d.ts.map +0 -1
  190. package/dist/src/server/shoppable-looks.js +0 -136
  191. package/dist/src/server/swaps.d.ts +0 -15
  192. package/dist/src/server/swaps.d.ts.map +0 -1
  193. package/dist/src/server/swaps.js +0 -89
  194. package/dist/src/server/variants.d.ts +0 -3
  195. package/dist/src/server/variants.d.ts.map +0 -1
  196. package/dist/src/server/variants.js +0 -15
  197. package/dist/src/server/wishlist.d.ts +0 -11
  198. package/dist/src/server/wishlist.d.ts.map +0 -1
  199. package/dist/src/server/wishlist.js +0 -49
  200. package/dist/src/util/get-locale-header.d.ts +0 -4
  201. package/dist/src/util/get-locale-header.d.ts.map +0 -1
  202. package/dist/src/util/get-locale-header.js +0 -7
  203. package/dist/src/util/medusa-error.d.ts +0 -2
  204. package/dist/src/util/medusa-error.d.ts.map +0 -1
  205. package/dist/src/util/medusa-error.js +0 -18
  206. package/dist/src/util/revalidate-cart.d.ts +0 -2
  207. package/dist/src/util/revalidate-cart.d.ts.map +0 -1
  208. package/dist/src/util/revalidate-cart.js +0 -8
  209. package/dist/src/util/sort-products.d.ts +0 -3
  210. package/dist/src/util/sort-products.d.ts.map +0 -1
  211. package/dist/src/util/sort-products.js +0 -1
  212. package/dist/src/util/store-client.d.ts +0 -13
  213. package/dist/src/util/store-client.d.ts.map +0 -1
  214. package/dist/src/util/store-client.js +0 -77
@@ -1,10 +1,48 @@
1
1
  # Homepage config and page input
2
2
 
3
- Storefront **packages do not call** `GET /store/dynamic-config`. Segment copy uses **hardcoded JSON defaults** (`segment-data/default-page-input.json`). The **main project** fetches dynamic config once and passes optional `pageInput` overrides.
3
+ Storefront **packages do not call** `GET /store/dynamic-config`. Each homepage section in `medusa-ui-home` keeps its **default copy in `data.json`** beside the UI. The **main project** fetches dynamic config once and passes optional `pageInput` overrides.
4
+
5
+ ## `medusa-ui-home` section layout
6
+
7
+ Each section id is a folder under `src/home/sections/<id>/`:
8
+
9
+ | File | Role |
10
+ |------|------|
11
+ | `data.json` | Default segment fields for dynamic-config schema |
12
+ | `theme.ts` | Default class names for slots this section uses + `ThemeOverrides` + `mergeSectionTheme()` |
13
+ | `dynamic-config.ts` | `*HomepageSectionField`, `*DynamicConfigStructure`, section id exports |
14
+ | `component/` | Presentational UI (or `component/index.tsx` re-export for shared widgets) |
15
+ | `section.tsx` | Section React wrapper only; optional `theme` prop |
16
+ | `index.ts` | Package export (`medusa-ui-home/sections/<id>`) |
17
+
18
+ Shared widgets used by multiple sections live in `src/home/components/` (`dynamic-banner`, `shoppable-gallery`, `shared/product-grid-section`, etc.).
19
+
20
+ Cross-section slots (e.g. `section`, `sectionPad`, `cardSurface`) live in `src/home/theme/shared.ts` and are composed into `medusa-ui-home/theme` via `defaultHomeThemeClassNames`.
21
+
22
+ ### Per-section theme overrides
23
+
24
+ ```tsx
25
+ import AboutBrandSection, {
26
+ mergeSectionTheme,
27
+ type ThemeOverrides,
28
+ } from "medusa-ui-home/sections/aboutBrand"
29
+
30
+ const aboutBrandTheme: ThemeOverrides = {
31
+ bannerTitle: "text-3xl font-black text-[var(--sf-color-secondary)]",
32
+ }
33
+
34
+ // Page / section instance
35
+ <AboutBrandSection {...data} theme={aboutBrandTheme} />
36
+
37
+ // Or merge into site home theme (Medusa theme-base)
38
+ const homeTheme = mergeThemeSlots(defaultHomeThemeClassNames, {
39
+ ...mergeSectionTheme({ bannerTitle: "..." }),
40
+ })
41
+ ```
4
42
 
5
43
  ## Tree-shakeable imports (one section)
6
44
 
7
- Import **only** the section UI and its loader. No `loadHomePageData`, no `registerAllHomeSections`, no full home barrel.
45
+ Import **only** the section UI and its loader. No full home barrel or global section registry.
8
46
 
9
47
  ```tsx
10
48
  // app/[countryCode]/page.tsx — single hero block
@@ -33,7 +71,7 @@ export default async function Page({
33
71
  | `medusa-ui-home/sections/promoAnnouncements` | `medusa-storefront-data/home/sections/promoAnnouncements` |
34
72
  | … | … (all `HomeSectionId` values) |
35
73
 
36
- Run `node scripts/generate-home-section-exports.mjs` after adding a section.
74
+ Run `node scripts/generate-home-section-exports.mjs` after adding a section (creates `sections/<id>/` export entries in `medusa-ui-home` and loader paths in `medusa-storefront-data`).
37
75
 
38
76
  ## Themed pages (tree-shakeable)
39
77
 
@@ -71,9 +109,29 @@ return (
71
109
  )
72
110
  ```
73
111
 
74
- ### Legacy compose registry
112
+ ### Main project page (no registration)
113
+
114
+ Sections accept props from their matching `load*SectionData` helper — no `adaptHomeSection` or `registerAllHomeSections`:
115
+
116
+ ```tsx
117
+ import HeroSection from "medusa-ui-home/sections/hero"
118
+ import WhyChooseUsSection from "medusa-ui-home/sections/whyChooseUs"
119
+ import { loadHeroSectionData } from "medusa-storefront-data/home/sections/hero"
120
+ import { loadWhyChooseUsSectionData } from "medusa-storefront-data/home/sections/whyChooseUs"
75
121
 
76
- `medusa-ui-home/home/register-sections` and `loadHomePageData` still exist but pull **every** section — avoid for tree-shaking.
122
+ const pageInput = /* optional CMS overrides */
123
+ const [hero, whyChooseUs] = await Promise.all([
124
+ loadHeroSectionData(countryCode, { pageInput }),
125
+ loadWhyChooseUsSectionData(countryCode, { pageInput }),
126
+ ])
127
+
128
+ return (
129
+ <>
130
+ {hero && <HeroSection {...hero} />}
131
+ {whyChooseUs && <WhyChooseUsSection {...whyChooseUs} />}
132
+ </>
133
+ )
134
+ ```
77
135
 
78
136
  ## Main project dynamic config
79
137
 
@@ -88,12 +146,61 @@ const pageInput = homepageConfigFromDynamicResponse(await getDynamicConfig())
88
146
 
89
147
  Pass `pageInput` only where you need CMS overrides; omit it to use package JSON defaults.
90
148
 
149
+ ## Medusa backend admin schemas (`medusa-ui-home-config`)
150
+
151
+ Use **`medusa-ui-home-config`** in the Medusa server (CommonJS `require` + ESM `import`). Do not import `medusa-ui-home` in `medusa-config` — that package is ESM-only (React UI).
152
+
153
+ ```js
154
+ const { homepageSectionFields } = require("medusa-ui-home-config")
155
+ const { aboutBrandHomepageSectionField } = require(
156
+ "medusa-ui-home-config/sections/aboutBrand",
157
+ )
158
+ ```
159
+
160
+ ```ts
161
+ import { homepageSectionFields } from "medusa-ui-home-config"
162
+ import { heroHomepageSectionField, bannerSlide } from "medusa-ui-home-config/sections/hero"
163
+ ```
164
+
165
+ Compose `options.configs` from `homepageSectionFields` or individual `*HomepageSectionField` exports. Merge API responses with `homepageConfigFromDynamicResponse` from `medusa-storefront-data/dynamic-config`.
166
+
167
+ Help page FAQs use **`helpFaqHomepageSectionField`** from `medusa-ui-home-config/sections/helpFaq` (also included in `homepageSectionFields`). Store in `homepage-config.sections.helpFaq`:
168
+
169
+ ```json
170
+ {
171
+ "sections": {
172
+ "helpFaq": {
173
+ "eyebrow": "Knowledge Base",
174
+ "title": "Frequently Asked",
175
+ "titleHighlight": "Questions",
176
+ "subtitle": "Browse FAQs by topic.",
177
+ "categories": [
178
+ {
179
+ "category": "Order & Delivery",
180
+ "icon": "🚚",
181
+ "color": "from-blue-500 to-cyan-400",
182
+ "items": [
183
+ { "question": "When will I receive my order?", "answer": "…" }
184
+ ]
185
+ }
186
+ ]
187
+ }
188
+ }
189
+ }
190
+ ```
191
+
192
+ Legacy flat `faq-array` entries are still supported and are grouped by `faq-category`.
193
+
194
+ Storefront UI still imports from `medusa-ui-home/sections/<id>`.
195
+
91
196
  ## API reference
92
197
 
93
198
  | Export | Use |
94
199
  |--------|-----|
95
200
  | `loadHeroSectionData`, `loadNewArrivalsSectionData`, … | **One section** catalog + copy |
96
- | `loadHomePageData` | All sections (legacy) |
201
+ | `loadHelpFaqSectionData` | Help page FAQ (`sections.helpFaq`) |
202
+ | `getHelpFaqFromPageInput(pageInput)` | FAQ categories + section header copy |
97
203
  | `getDynamicConfig()` | **Main project only** |
204
+ | `get*FromPageInput(pageInput)` | Read CMS copy/banners without fetching |
98
205
  | `homepageConfigFromDynamicResponse(raw)` | Merge API → `pageInput` |
99
206
  | `DEFAULT_PAGE_INPUT` | Package defaults |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-storefront-data",
3
- "version": "2.4.0",
3
+ "version": "2.5.3",
4
4
  "type": "module",
5
5
  "description": "Medusa storefront server data layer extracted from Next.js storefront",
6
6
  "license": "MIT",
@@ -123,6 +123,11 @@
123
123
  "import": "./src/server/dynamic-config.ts",
124
124
  "default": "./src/server/dynamic-config.ts"
125
125
  },
126
+ "./help/sections/helpFaq": {
127
+ "types": "./dist/server/help-sections/help-faq.d.ts",
128
+ "import": "./src/server/help-sections/help-faq.ts",
129
+ "default": "./src/server/help-sections/help-faq.ts"
130
+ },
126
131
  "./fulfillment": {
127
132
  "types": "./dist/server/fulfillment.d.ts",
128
133
  "import": "./src/server/fulfillment.ts",
@@ -207,121 +212,6 @@
207
212
  "types": "./dist/server/wishlist.d.ts",
208
213
  "import": "./src/server/wishlist.ts",
209
214
  "default": "./src/server/wishlist.ts"
210
- },
211
- "./home/sections/promoAnnouncements": {
212
- "types": "./dist/server/home-sections/promo-announcements.d.ts",
213
- "import": "./src/server/home-sections/promo-announcements.ts",
214
- "default": "./src/server/home-sections/promo-announcements.ts"
215
- },
216
- "./home/sections/hero": {
217
- "types": "./dist/server/home-sections/hero.d.ts",
218
- "import": "./src/server/home-sections/hero.ts",
219
- "default": "./src/server/home-sections/hero.ts"
220
- },
221
- "./home/sections/categoryPills": {
222
- "types": "./dist/server/home-sections/category-pills.d.ts",
223
- "import": "./src/server/home-sections/category-pills.ts",
224
- "default": "./src/server/home-sections/category-pills.ts"
225
- },
226
- "./home/sections/newArrivals": {
227
- "types": "./dist/server/home-sections/new-arrivals.d.ts",
228
- "import": "./src/server/home-sections/new-arrivals.ts",
229
- "default": "./src/server/home-sections/new-arrivals.ts"
230
- },
231
- "./home/sections/newArrivalsClassic": {
232
- "types": "./dist/server/home-sections/new-arrivals-classic.d.ts",
233
- "import": "./src/server/home-sections/new-arrivals-classic.ts",
234
- "default": "./src/server/home-sections/new-arrivals-classic.ts"
235
- },
236
- "./home/sections/promoCountdown": {
237
- "types": "./dist/server/home-sections/promo-countdown.d.ts",
238
- "import": "./src/server/home-sections/promo-countdown.ts",
239
- "default": "./src/server/home-sections/promo-countdown.ts"
240
- },
241
- "./home/sections/celebrityTrust": {
242
- "types": "./dist/server/home-sections/celebrity-trust.d.ts",
243
- "import": "./src/server/home-sections/celebrity-trust.ts",
244
- "default": "./src/server/home-sections/celebrity-trust.ts"
245
- },
246
- "./home/sections/luxeFavourites": {
247
- "types": "./dist/server/home-sections/luxe-favourites.d.ts",
248
- "import": "./src/server/home-sections/luxe-favourites.ts",
249
- "default": "./src/server/home-sections/luxe-favourites.ts"
250
- },
251
- "./home/sections/shopByCategory": {
252
- "types": "./dist/server/home-sections/shop-by-category.d.ts",
253
- "import": "./src/server/home-sections/shop-by-category.ts",
254
- "default": "./src/server/home-sections/shop-by-category.ts"
255
- },
256
- "./home/sections/baptism": {
257
- "types": "./dist/server/home-sections/baptism.d.ts",
258
- "import": "./src/server/home-sections/baptism.ts",
259
- "default": "./src/server/home-sections/baptism.ts"
260
- },
261
- "./home/sections/baptismPicks": {
262
- "types": "./dist/server/home-sections/baptism-picks.d.ts",
263
- "import": "./src/server/home-sections/baptism-picks.ts",
264
- "default": "./src/server/home-sections/baptism-picks.ts"
265
- },
266
- "./home/sections/themeDresses": {
267
- "types": "./dist/server/home-sections/theme-dresses.d.ts",
268
- "import": "./src/server/home-sections/theme-dresses.ts",
269
- "default": "./src/server/home-sections/theme-dresses.ts"
270
- },
271
- "./home/sections/brandMarquee": {
272
- "types": "./dist/server/home-sections/brand-marquee.d.ts",
273
- "import": "./src/server/home-sections/brand-marquee.ts",
274
- "default": "./src/server/home-sections/brand-marquee.ts"
275
- },
276
- "./home/sections/aboutBrand": {
277
- "types": "./dist/server/home-sections/about-brand.d.ts",
278
- "import": "./src/server/home-sections/about-brand.ts",
279
- "default": "./src/server/home-sections/about-brand.ts"
280
- },
281
- "./home/sections/testimonials": {
282
- "types": "./dist/server/home-sections/testimonials.d.ts",
283
- "import": "./src/server/home-sections/testimonials.ts",
284
- "default": "./src/server/home-sections/testimonials.ts"
285
- },
286
- "./home/sections/brandPillars": {
287
- "types": "./dist/server/home-sections/brand-pillars.d.ts",
288
- "import": "./src/server/home-sections/brand-pillars.ts",
289
- "default": "./src/server/home-sections/brand-pillars.ts"
290
- },
291
- "./home/sections/instagramPosts": {
292
- "types": "./dist/server/home-sections/instagram-posts.d.ts",
293
- "import": "./src/server/home-sections/instagram-posts.ts",
294
- "default": "./src/server/home-sections/instagram-posts.ts"
295
- },
296
- "./home/sections/features": {
297
- "types": "./dist/server/home-sections/features.d.ts",
298
- "import": "./src/server/home-sections/features.ts",
299
- "default": "./src/server/home-sections/features.ts"
300
- },
301
- "./home/sections/shopByAge": {
302
- "types": "./dist/server/home-sections/shop-by-age.d.ts",
303
- "import": "./src/server/home-sections/shop-by-age.ts",
304
- "default": "./src/server/home-sections/shop-by-age.ts"
305
- },
306
- "./home/sections/whyChooseUs": {
307
- "types": "./dist/server/home-sections/why-choose-us.d.ts",
308
- "import": "./src/server/home-sections/why-choose-us.ts",
309
- "default": "./src/server/home-sections/why-choose-us.ts"
310
- },
311
- "./home/sections/lovedByMoms": {
312
- "types": "./dist/server/home-sections/loved-by-moms.d.ts",
313
- "import": "./src/server/home-sections/loved-by-moms.ts",
314
- "default": "./src/server/home-sections/loved-by-moms.ts"
315
- },
316
- "./home/sections/videoStories": {
317
- "types": "./dist/server/home-sections/video-stories.d.ts",
318
- "import": "./src/server/home-sections/video-stories.ts",
319
- "default": "./src/server/home-sections/video-stories.ts"
320
- },
321
- "./home/sections/blogPosts": {
322
- "types": "./dist/server/home-sections/blog-posts.d.ts",
323
- "import": "./src/server/home-sections/blog-posts.ts",
324
- "default": "./src/server/home-sections/blog-posts.ts"
325
215
  }
326
216
  },
327
217
  "main": "./dist/server/index.js",
@@ -0,0 +1,156 @@
1
+ import type { HttpTypes } from "@medusajs/types"
2
+ import type { BrandPillarConfig } from "./dynamic-config"
3
+
4
+ type CategoryMetadata = {
5
+ category_image?: string
6
+ category_description?: string
7
+ category_link?: string
8
+ image?: string
9
+ thumbnail?: string
10
+ description?: string
11
+ }
12
+
13
+ type CollectionMetadata = {
14
+ category_image?: string
15
+ image?: string
16
+ thumbnail?: string
17
+ }
18
+
19
+ function normalizeKey(value: string): string {
20
+ return value
21
+ .toLowerCase()
22
+ .trim()
23
+ .replace(/&/g, "and")
24
+ .replace(/[^a-z0-9]+/g, "-")
25
+ .replace(/^-+|-+$/g, "")
26
+ }
27
+
28
+ function collectionImageForCategory(
29
+ collections: Array<Record<string, unknown>> | undefined,
30
+ category: HttpTypes.StoreProductCategory
31
+ ): string | null {
32
+ if (!collections?.length) return null
33
+
34
+ const handleKey = category.handle ? normalizeKey(category.handle) : ""
35
+ const nameKey = category.name ? normalizeKey(category.name) : ""
36
+
37
+ for (const entry of collections) {
38
+ const meta = (entry.metadata as CollectionMetadata | undefined) ?? {}
39
+ const image = meta.category_image || meta.image || meta.thumbnail
40
+ if (!image) continue
41
+
42
+ const cHandle = (entry.handle as string | undefined) ?? ""
43
+ const cTitle = (entry.title as string | undefined) ?? ""
44
+ if (
45
+ (handleKey && normalizeKey(cHandle) === handleKey) ||
46
+ (nameKey && normalizeKey(cTitle) === nameKey)
47
+ ) {
48
+ return image
49
+ }
50
+ }
51
+
52
+ return null
53
+ }
54
+
55
+ function imageFromCategory(
56
+ category: HttpTypes.StoreProductCategory
57
+ ): string | null {
58
+ const meta = (category.metadata as CategoryMetadata | undefined) ?? {}
59
+ return (
60
+ meta.category_image ||
61
+ meta.image ||
62
+ meta.thumbnail ||
63
+ (category as { thumbnail?: string }).thumbnail ||
64
+ null
65
+ )
66
+ }
67
+
68
+ function resolveCategoryImage(
69
+ category: HttpTypes.StoreProductCategory,
70
+ collections?: Array<Record<string, unknown>>
71
+ ): string | null {
72
+ const fromCategory = imageFromCategory(category)
73
+ if (fromCategory) return fromCategory
74
+
75
+ const parent = (
76
+ category as HttpTypes.StoreProductCategory & {
77
+ parent_category?: HttpTypes.StoreProductCategory
78
+ }
79
+ ).parent_category
80
+ if (parent) {
81
+ const fromParent = imageFromCategory(parent)
82
+ if (fromParent) return fromParent
83
+ }
84
+
85
+ return collectionImageForCategory(collections, category)
86
+ }
87
+
88
+ function categoryDescription(
89
+ category: HttpTypes.StoreProductCategory
90
+ ): string {
91
+ const meta = (category.metadata as CategoryMetadata | undefined) ?? {}
92
+ const native = (category as { description?: string | null }).description
93
+ return String(
94
+ native ?? meta.category_description ?? meta.description ?? ""
95
+ ).trim()
96
+ }
97
+
98
+ function categoryHref(category: HttpTypes.StoreProductCategory): string | undefined {
99
+ const meta = (category.metadata as CategoryMetadata | undefined) ?? {}
100
+ const custom = meta.category_link?.trim()
101
+ if (custom) return custom
102
+ if (category.handle) return `/categories/${category.handle}`
103
+ return undefined
104
+ }
105
+
106
+ function pickBrandPillarCategories(
107
+ categories: HttpTypes.StoreProductCategory[],
108
+ collections: Array<Record<string, unknown>> | undefined,
109
+ limit = 4
110
+ ): HttpTypes.StoreProductCategory[] {
111
+ const valid = (categories ?? []).filter((c) => c.name && c.handle)
112
+ const topLevel = valid.filter((c) => !c.parent_category_id)
113
+ const withImage = topLevel.filter((c) =>
114
+ Boolean(resolveCategoryImage(c, collections))
115
+ )
116
+
117
+ const pool = withImage.length >= 2 ? withImage : topLevel
118
+
119
+ return [...pool]
120
+ .sort(
121
+ (a, b) =>
122
+ Number(Boolean(resolveCategoryImage(b, collections))) -
123
+ Number(Boolean(resolveCategoryImage(a, collections))) ||
124
+ (a.name ?? "").localeCompare(b.name ?? "")
125
+ )
126
+ .slice(0, limit)
127
+ }
128
+
129
+ /** Brand pillar cards from top-level product categories (not CMS pillars array). */
130
+ export function buildBrandPillarsFromCategories(
131
+ categories: HttpTypes.StoreProductCategory[],
132
+ collections: Array<Record<string, unknown>> | undefined,
133
+ sectionTitle: string
134
+ ): { sectionTitle: string; pillars: BrandPillarConfig[] } {
135
+ const pillars = pickBrandPillarCategories(categories, collections).flatMap(
136
+ (category) => {
137
+ const title = (category.name ?? "").trim()
138
+ const image = resolveCategoryImage(category, collections) ?? undefined
139
+ if (!title || !image) return []
140
+
141
+ const description = categoryDescription(category)
142
+ const href = categoryHref(category)
143
+
144
+ return [
145
+ {
146
+ title,
147
+ description,
148
+ image,
149
+ ...(href ? { href } : {}),
150
+ },
151
+ ]
152
+ }
153
+ )
154
+
155
+ return { sectionTitle, pillars }
156
+ }
@@ -55,7 +55,7 @@ import {
55
55
  medusaCustomerUpdateAddress,
56
56
  } from "medusa-services/customer"
57
57
  import { medusaPaymentSessionInitiate } from "medusa-services/payment"
58
- import { getStoreCartClientOptions } from "../util/store-client"
58
+ import { getStoreClientOptions } from "../util/store-client"
59
59
  import { revalidateCartTags } from "../util/revalidate-cart"
60
60
 
61
61
  import { cache } from "react"
@@ -86,7 +86,7 @@ export const retrieveCart = cache(
86
86
 
87
87
  // Skip metadata check if we are clearly in checkout to avoid extra API call
88
88
  if (!pathname.includes("/checkout")) {
89
- const options = await getStoreCartClientOptions()
89
+ const options = await getStoreClientOptions()
90
90
  const currentCart = await medusaCartRetrieve(id, options, { fields: "metadata" })
91
91
  .then(({ cart }) => cart)
92
92
  .catch(() => null)
@@ -143,7 +143,7 @@ export async function getOrSetCart(countryCode: string) {
143
143
  }
144
144
 
145
145
  let cart = await retrieveCart(undefined, "id,region_id")
146
- const options = await getStoreCartClientOptions()
146
+ const options = await getStoreClientOptions()
147
147
 
148
148
  if (!cart) {
149
149
  const locale = await getLocale()
@@ -176,7 +176,7 @@ export async function updateCart(data: HttpTypes.StoreUpdateCart) {
176
176
  }
177
177
 
178
178
  try {
179
- const options = await getStoreCartClientOptions()
179
+ const options = await getStoreClientOptions()
180
180
  const { cart } = await medusaCartUpdate(cartId, data as Record<string, unknown>, options)
181
181
  await revalidateCartTags()
182
182
  return cart as unknown as HttpTypes.StoreCart
@@ -205,7 +205,7 @@ export async function addToCart({
205
205
  }
206
206
 
207
207
  try {
208
- const options = await getStoreCartClientOptions()
208
+ const options = await getStoreClientOptions()
209
209
  await medusaCartAddLineItem(cart.id, { variant_id: variantId, quantity }, options)
210
210
  await revalidateCartTags()
211
211
  } catch (e) {
@@ -232,7 +232,7 @@ export async function buyNow({
232
232
  throw new Error(`Region not found for country code: ${countryCode}`)
233
233
  }
234
234
 
235
- const options = await getStoreCartClientOptions()
235
+ const options = await getStoreClientOptions()
236
236
  const locale = await getLocale()
237
237
 
238
238
  // 1. Create a NEW cart regardless of existing one
@@ -343,7 +343,7 @@ export async function updateLineItem({
343
343
  }
344
344
 
345
345
  try {
346
- const options = await getStoreCartClientOptions()
346
+ const options = await getStoreClientOptions()
347
347
  await medusaCartUpdateLineItem(cartId, lineId, { quantity }, options)
348
348
  await revalidateCartTags()
349
349
  } catch (e) {
@@ -363,7 +363,7 @@ export async function deleteLineItem(lineId: string) {
363
363
  }
364
364
 
365
365
  try {
366
- const options = await getStoreCartClientOptions()
366
+ const options = await getStoreClientOptions()
367
367
  await medusaCartRemoveLineItem(cartId, lineId, options)
368
368
  await revalidateCartTags()
369
369
  } catch (e) {
@@ -409,7 +409,7 @@ export async function setShippingMethod({
409
409
  shippingMethodId: string
410
410
  }) {
411
411
  try {
412
- const options = await getStoreCartClientOptions()
412
+ const options = await getStoreClientOptions()
413
413
  await medusaCartAddShippingMethod(cartId, shippingMethodId, options)
414
414
  const cartCacheTag = await getCacheTag("carts")
415
415
  revalidateTag(cartCacheTag)
@@ -429,7 +429,7 @@ export async function setShippingMethodSilently({
429
429
  shippingMethodId: string
430
430
  }) {
431
431
  try {
432
- const options = await getStoreCartClientOptions()
432
+ const options = await getStoreClientOptions()
433
433
  await medusaCartAddShippingMethod(cartId, shippingMethodId, options)
434
434
  return { success: true }
435
435
  } catch (e) {
@@ -490,13 +490,13 @@ export async function initiatePaymentSession(
490
490
  }
491
491
 
492
492
  if (Object.keys(addressUpdates).length > 0) {
493
- const options = await getStoreCartClientOptions()
493
+ const options = await getStoreClientOptions()
494
494
  await medusaCartUpdate(latestCart.id, addressUpdates, options)
495
495
  }
496
496
  }
497
497
 
498
498
  // 3. Final re-fetch (direct call to bypass any lib-level cache)
499
- const options = await getStoreCartClientOptions()
499
+ const options = await getStoreClientOptions()
500
500
  const { cart: finalCartRaw } = await medusaCartRetrieve(cart.id, options, {
501
501
  fields: "*shipping_address,*billing_address",
502
502
  })
@@ -552,7 +552,7 @@ export async function applyPromotions(codes: string[]) {
552
552
  }
553
553
 
554
554
  try {
555
- const options = await getStoreCartClientOptions()
555
+ const options = await getStoreClientOptions()
556
556
  const { cart } = await medusaCartApplyPromotions(cartId, codes, options)
557
557
  await revalidateCartTags()
558
558
  return cart as unknown as HttpTypes.StoreCart
@@ -668,7 +668,7 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
668
668
  const authHeaders = await getAuthHeaders()
669
669
  if (authHeaders && "authorization" in authHeaders) {
670
670
  try {
671
- const options = await getStoreCartClientOptions()
671
+ const options = await getStoreClientOptions()
672
672
  const { customer } = await medusaCustomerRetrieve(options, { fields: "*addresses" })
673
673
 
674
674
  const addressExists = customer?.addresses?.some((a: any) =>
@@ -731,7 +731,7 @@ export async function placeOrder(cartId?: string) {
731
731
 
732
732
  let cartRes
733
733
  try {
734
- const options = await getStoreCartClientOptions()
734
+ const options = await getStoreClientOptions()
735
735
  cartRes = await medusaCartComplete(id, options)
736
736
  const cartCacheTag = await getCacheTag("carts")
737
737
  revalidateTag(cartCacheTag)
@@ -740,7 +740,7 @@ export async function placeOrder(cartId?: string) {
740
740
  }
741
741
 
742
742
  if (cartRes?.type === "order") {
743
- const order = cartRes.order as HttpTypes.StoreOrder
743
+ const order = cartRes.order as unknown as HttpTypes.StoreOrder
744
744
  const countryCode = order.shipping_address?.country_code?.toLowerCase()
745
745
 
746
746
  const orderCacheTag = await getCacheTag("orders")
@@ -840,7 +840,7 @@ export async function addCustomerAddressToCart(currentState: unknown, formData:
840
840
  // 1. Add/Update Customer Address Book
841
841
  // We try/catch this separately so if it fails (e.g. user not logged in), we still try to proceed with checkout
842
842
  try {
843
- const options = await getStoreCartClientOptions()
843
+ const options = await getStoreClientOptions()
844
844
  if (addressId) {
845
845
  await medusaCustomerUpdateAddress(addressId, addressData, options)
846
846
  } else {
@@ -916,7 +916,7 @@ export async function updateAddressSilently(data: any) {
916
916
  }
917
917
  }
918
918
 
919
- const options = await getStoreCartClientOptions()
919
+ const options = await getStoreClientOptions()
920
920
  await medusaCartUpdate(cartId, payload, options)
921
921
 
922
922
  // Revalidate tags to ensure CartTotals gets new shipping info
@@ -935,7 +935,7 @@ export async function updateCartMetadataSilently(metadata: any) {
935
935
  if (!cartId) return
936
936
 
937
937
  try {
938
- const options = await getStoreCartClientOptions()
938
+ const options = await getStoreClientOptions()
939
939
  await medusaCartUpdate(cartId, { metadata }, options)
940
940
  // We intentionally DO NOT call revalidateTag here to prevent page refresh loops
941
941
  return { success: true }
@@ -953,7 +953,7 @@ export async function getAbandonedCarts() {
953
953
  }
954
954
 
955
955
  try {
956
- const options = await getStoreCartClientOptions()
956
+ const options = await getStoreClientOptions()
957
957
  const res = await medusaCartList(options, {
958
958
  fields: "*items, *items.product, *items.product.thumbnail, *items.variant, *items.metadata, +total",
959
959
  }).catch(() => null)
@@ -989,7 +989,7 @@ export async function resumeAbandonedCart(cartId: string, countryCode: string) {
989
989
 
990
990
  export async function deleteCart(cartId: string) {
991
991
  try {
992
- const options = await getStoreCartClientOptions()
992
+ const options = await getStoreClientOptions()
993
993
  await medusaCartDelete(cartId, options)
994
994
 
995
995
  revalidateTag("carts")