medusa-storefront-data 1.0.0 → 2.0.0

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 (109) hide show
  1. package/dist/cookies.d.ts +2 -2
  2. package/dist/cookies.d.ts.map +1 -1
  3. package/dist/edge.d.ts +3 -0
  4. package/dist/edge.d.ts.map +1 -0
  5. package/dist/edge.js +1 -0
  6. package/dist/middleware.d.ts +3 -0
  7. package/dist/middleware.d.ts.map +1 -0
  8. package/dist/middleware.js +1 -0
  9. package/dist/server/cart.d.ts +9 -5
  10. package/dist/server/cart.d.ts.map +1 -1
  11. package/dist/server/cart.js +164 -194
  12. package/dist/server/categories.d.ts +3 -2
  13. package/dist/server/categories.d.ts.map +1 -1
  14. package/dist/server/categories.js +14 -51
  15. package/dist/server/collections.d.ts.map +1 -1
  16. package/dist/server/collections.js +16 -61
  17. package/dist/server/contact.d.ts +34 -0
  18. package/dist/server/contact.d.ts.map +1 -0
  19. package/dist/server/contact.js +57 -0
  20. package/dist/server/customer.d.ts +7 -7
  21. package/dist/server/customer.d.ts.map +1 -1
  22. package/dist/server/customer.js +95 -145
  23. package/dist/server/dynamic-config.d.ts.map +1 -1
  24. package/dist/server/dynamic-config.js +5 -2
  25. package/dist/server/fulfillment.d.ts +4 -3
  26. package/dist/server/fulfillment.d.ts.map +1 -1
  27. package/dist/server/fulfillment.js +16 -41
  28. package/dist/server/guest.d.ts +35 -63
  29. package/dist/server/guest.d.ts.map +1 -1
  30. package/dist/server/guest.js +81 -202
  31. package/dist/server/home.d.ts +15 -0
  32. package/dist/server/home.d.ts.map +1 -0
  33. package/dist/server/home.js +45 -0
  34. package/dist/server/index.d.ts +2 -0
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +2 -0
  37. package/dist/server/locale-actions.d.ts +1 -1
  38. package/dist/server/locale-actions.d.ts.map +1 -1
  39. package/dist/server/locale-actions.js +8 -13
  40. package/dist/server/locales.d.ts +2 -4
  41. package/dist/server/locales.d.ts.map +1 -1
  42. package/dist/server/locales.js +5 -13
  43. package/dist/server/orders.d.ts +5 -11
  44. package/dist/server/orders.d.ts.map +1 -1
  45. package/dist/server/orders.js +126 -267
  46. package/dist/server/payment-details.d.ts +4 -4
  47. package/dist/server/payment-details.d.ts.map +1 -1
  48. package/dist/server/payment-details.js +17 -42
  49. package/dist/server/payment.d.ts +2 -1
  50. package/dist/server/payment.d.ts.map +1 -1
  51. package/dist/server/payment.js +9 -21
  52. package/dist/server/pincode.d.ts +7 -0
  53. package/dist/server/pincode.d.ts.map +1 -0
  54. package/dist/server/pincode.js +30 -0
  55. package/dist/server/products.d.ts +15 -19
  56. package/dist/server/products.d.ts.map +1 -1
  57. package/dist/server/products.js +47 -178
  58. package/dist/server/regions.d.ts +1 -1
  59. package/dist/server/regions.d.ts.map +1 -1
  60. package/dist/server/regions.js +6 -3
  61. package/dist/server/returns.d.ts +4 -4
  62. package/dist/server/returns.d.ts.map +1 -1
  63. package/dist/server/returns.js +50 -154
  64. package/dist/server/swaps.d.ts +3 -3
  65. package/dist/server/swaps.d.ts.map +1 -1
  66. package/dist/server/swaps.js +22 -56
  67. package/dist/server/variants.d.ts.map +1 -1
  68. package/dist/server/variants.js +11 -22
  69. package/dist/server/wishlist.d.ts +11 -0
  70. package/dist/server/wishlist.d.ts.map +1 -0
  71. package/dist/server/wishlist.js +49 -0
  72. package/dist/util/get-locale-header.d.ts +1 -1
  73. package/dist/util/revalidate-cart.d.ts +2 -0
  74. package/dist/util/revalidate-cart.d.ts.map +1 -0
  75. package/dist/util/revalidate-cart.js +8 -0
  76. package/dist/util/sort-products.d.ts +3 -0
  77. package/dist/util/sort-products.d.ts.map +1 -0
  78. package/dist/util/sort-products.js +1 -0
  79. package/dist/util/store-client.d.ts +13 -0
  80. package/dist/util/store-client.d.ts.map +1 -0
  81. package/dist/util/store-client.js +77 -0
  82. package/package.json +95 -37
  83. package/src/edge.ts +2 -0
  84. package/src/middleware.ts +2 -2
  85. package/src/server/cart.ts +214 -267
  86. package/src/server/categories.ts +19 -72
  87. package/src/server/collections.ts +25 -82
  88. package/src/server/contact.ts +92 -0
  89. package/src/server/customer.ts +140 -189
  90. package/src/server/dynamic-config.ts +6 -2
  91. package/src/server/fulfillment.ts +27 -53
  92. package/src/server/guest.ts +159 -276
  93. package/src/server/home.ts +68 -0
  94. package/src/server/index.ts +1 -0
  95. package/src/server/locale-actions.ts +8 -15
  96. package/src/server/locales.ts +6 -18
  97. package/src/server/orders.ts +167 -337
  98. package/src/server/payment-details.ts +24 -52
  99. package/src/server/payment.ts +8 -28
  100. package/src/server/pincode.ts +49 -0
  101. package/src/server/products.ts +72 -235
  102. package/src/server/regions.ts +10 -6
  103. package/src/server/returns.ts +75 -189
  104. package/src/server/swaps.ts +90 -121
  105. package/src/server/variants.ts +9 -28
  106. package/src/util/revalidate-cart.ts +10 -0
  107. package/src/util/sort-products.ts +2 -47
  108. package/src/util/store-client.ts +93 -0
  109. package/src/services/middleware.ts +0 -54
@@ -1,69 +1,41 @@
1
1
  "use server"
2
2
 
3
- import { sdk } from "../config"
4
- import { getAuthHeaders, getCacheOptions } from "../cookies"
3
+ import {
4
+ medusaPaymentDetailCreate,
5
+ medusaPaymentDetailDelete,
6
+ medusaPaymentDetailMakeDefault,
7
+ medusaPaymentDetailsList,
8
+ } from "medusa-services/payment"
9
+ import { getStoreCartClientOptions } from "../util/store-client"
5
10
 
6
11
  export const listPaymentDetails = async () => {
7
- const authHeaders = await getAuthHeaders()
8
-
9
- // If no auth headers (guest user), don't even try to fetch
10
- if (!authHeaders || Object.keys(authHeaders).length === 0) {
11
- return []
12
- }
13
-
14
- const headers = {
15
- ...authHeaders,
12
+ try {
13
+ const options = await getStoreCartClientOptions()
14
+ if (!options.authorization) {
15
+ return []
16
16
  }
17
17
 
18
- const next = {
19
- ...(await getCacheOptions("payment_details")),
20
- }
21
-
22
- return sdk.client
23
- .fetch<any>(`/store/payment-details`, {
24
- method: "GET",
25
- headers,
26
- next,
27
- cache: "no-store",
28
- })
29
- .then((res: any) => res.payment_details || [])
30
- .catch(() => [])
18
+ const { payment_details } = await medusaPaymentDetailsList(options)
19
+ return payment_details ?? []
20
+ } catch {
21
+ return []
22
+ }
31
23
  }
32
24
 
33
25
  export const createPaymentDetail = async (
34
- type: "upi" | "bank" | "card",
35
- detail_json: Record<string, string>
26
+ type: "upi" | "bank" | "card",
27
+ detail_json: Record<string, string>
36
28
  ) => {
37
- const headers = {
38
- ...(await getAuthHeaders()),
39
- }
40
-
41
- return sdk.client.fetch<any>(`/store/payment-details`, {
42
- method: "POST",
43
- headers,
44
- body: { type, detail_json },
45
- })
29
+ const options = await getStoreCartClientOptions()
30
+ return medusaPaymentDetailCreate(type, detail_json, options)
46
31
  }
47
32
 
48
33
  export const makeDefaultPaymentDetail = async (id: string) => {
49
- const headers = {
50
- ...(await getAuthHeaders()),
51
- }
52
-
53
- return sdk.client.fetch<any>(`/store/payment-details/${id}/make-default`, {
54
- method: "POST",
55
- headers,
56
- })
34
+ const options = await getStoreCartClientOptions()
35
+ return medusaPaymentDetailMakeDefault(id, options)
57
36
  }
58
37
 
59
38
  export const deletePaymentDetail = async (id: string) => {
60
- const headers = {
61
- ...(await getAuthHeaders()),
62
- }
63
-
64
- return sdk.client.fetch<any>(`/store/payment-details/${id}`, {
65
- method: "DELETE",
66
- headers,
67
- })
39
+ const options = await getStoreCartClientOptions()
40
+ return medusaPaymentDetailDelete(id, options)
68
41
  }
69
-
@@ -1,35 +1,15 @@
1
1
  "use server"
2
2
 
3
- import { sdk } from "../config"
4
- import { getAuthHeaders, getCacheOptions } from "../cookies"
5
3
  import { HttpTypes } from "@medusajs/types"
4
+ import { medusaPaymentProvidersList } from "medusa-services/payment"
5
+ import { getStoreCartClientOptions } from "../util/store-client"
6
6
 
7
7
  export const listCartPaymentMethods = async (regionId: string) => {
8
- const headers = {
9
- ...(await getAuthHeaders()),
8
+ try {
9
+ const options = await getStoreCartClientOptions()
10
+ const { payment_providers } = await medusaPaymentProvidersList(regionId, options)
11
+ return payment_providers.sort((a, b) => (a.id > b.id ? 1 : -1)) as HttpTypes.StorePaymentProvider[]
12
+ } catch {
13
+ return null
10
14
  }
11
-
12
- const next = {
13
- ...(await getCacheOptions("payment_providers")),
14
- }
15
-
16
- return sdk.client
17
- .fetch<HttpTypes.StorePaymentProviderListResponse>(
18
- `/store/payment-providers`,
19
- {
20
- method: "GET",
21
- query: { region_id: regionId },
22
- headers,
23
- next,
24
- cache: "no-store",
25
- }
26
- )
27
- .then(({ payment_providers }) =>
28
- payment_providers.sort((a, b) => {
29
- return a.id > b.id ? 1 : -1
30
- })
31
- )
32
- .catch(() => {
33
- return null
34
- })
35
15
  }
@@ -0,0 +1,49 @@
1
+ "use server"
2
+
3
+ export type PincodeLookupResult = {
4
+ city: string
5
+ province: string
6
+ }
7
+
8
+ function titleCase(value: string): string {
9
+ return value
10
+ .toLowerCase()
11
+ .replace(/\b\w/g, (char) => char.toUpperCase())
12
+ }
13
+
14
+ /** Resolve Indian pincode to district (city) and state. */
15
+ export async function lookupIndianPincode(
16
+ postalCode: string
17
+ ): Promise<PincodeLookupResult | null> {
18
+ const cleaned = postalCode.replace(/\D/g, "")
19
+ if (cleaned.length !== 6) return null
20
+
21
+ try {
22
+ const response = await fetch(
23
+ `https://postal-pincode-api.vercel.app/api/v1/pincode/${cleaned}`,
24
+ { next: { revalidate: 86400 } } as RequestInit
25
+ )
26
+ if (!response.ok) return null
27
+
28
+ const payload = await response.json()
29
+ const offices = payload?.data as Array<{
30
+ district?: string
31
+ state?: string
32
+ delivery?: boolean
33
+ }> | undefined
34
+
35
+ const match =
36
+ offices?.find((office) => office.delivery) ?? offices?.[0]
37
+
38
+ if (match?.district && match?.state) {
39
+ return {
40
+ city: titleCase(match.district),
41
+ province: titleCase(match.state),
42
+ }
43
+ }
44
+ } catch {
45
+ // ignore network errors
46
+ }
47
+
48
+ return null
49
+ }
@@ -1,11 +1,15 @@
1
1
  "use server"
2
2
 
3
- import { sdk } from "../config"
4
- import { sortProducts, type SortOptions } from "../util/sort-products"
3
+ import { type SortOptions } from "../util/sort-products"
5
4
  import { HttpTypes } from "@medusajs/types"
6
- import { getAuthHeaders, getCacheOptions } from "../cookies"
7
5
  import { getRegion, retrieveRegion } from "./regions"
8
6
  import Color from "color"
7
+ import {
8
+ medusaProductByHandle,
9
+ medusaProductHelperFilters,
10
+ medusaProductList,
11
+ } from "medusa-services/products"
12
+ import { getStoreClientOptions } from "../util/store-client"
9
13
 
10
14
  export const listProducts = async ({
11
15
  pageParam = 1,
@@ -22,24 +26,17 @@ export const listProducts = async ({
22
26
  nextPage: number | null
23
27
  queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams
24
28
  }> => {
25
-
26
-
27
29
  if (!countryCode && !regionId) {
28
-
29
30
  throw new Error("Country code or region ID is required")
30
31
  }
31
32
 
32
33
  const limit = queryParams?.limit || 12
33
- const _pageParam = Math.max(pageParam, 1)
34
- const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit
35
34
 
36
35
  let region: HttpTypes.StoreRegion | undefined | null
37
36
 
38
37
  if (countryCode) {
39
-
40
38
  region = await getRegion(countryCode)
41
39
  } else {
42
-
43
40
  region = await retrieveRegion(regionId!)
44
41
  }
45
42
 
@@ -50,156 +47,24 @@ export const listProducts = async ({
50
47
  }
51
48
  }
52
49
 
53
-
54
-
55
- const headers = {
56
- ...(await getAuthHeaders()),
57
- }
58
-
59
- const next = {
60
- ...(await getCacheOptions("products")),
61
- }
62
-
63
- // 1. Standard Medusa query parameters
64
- const standardQuery: any = {
50
+ const options = await getStoreClientOptions()
51
+ const { products, count, nextPage } = await medusaProductList(options, {
52
+ pageParam,
65
53
  limit,
66
- offset,
67
- region_id: region?.id,
68
- fields:
69
- "*variants.calculated_price,+variants.inventory_quantity,*variants.images,+variants.metadata,+variants.options,+metadata,+tags,+average_rating,+total_rating_count,+total_rating_sum,",
70
- }
71
-
72
- // 2. Identify advanced filters that require the product-helper API
73
- const advancedFilterKeys = [
74
- "metadata", "min_price", "max_price", "q", "collection_id", "category_id",
75
- "tags", "option_value", "gender", "color", "material", "style", "brand",
76
- "type", "product_type", "order"
77
- ]
78
-
79
- const hasAdvancedFilters = !!(queryParams && Object.keys(queryParams).some(key =>
80
- advancedFilterKeys.includes(key) && (queryParams as any)[key] !== undefined
81
- ))
82
-
83
- const endpoint = hasAdvancedFilters ? "/store/product-helper/products" : "/store/products";
84
-
85
- let finalQuery: any = { ...standardQuery }
86
-
87
- if (hasAdvancedFilters) {
88
-
89
-
90
- // We use URLSearchParams to ensure correct formatting and handle repeated keys if needed
91
- const params = new URLSearchParams()
92
-
93
- // 1. Add standard params
94
- params.append("limit", limit.toString())
95
- params.append("offset", offset.toString())
96
- if (region?.id) params.append("region_id", region.id)
97
-
98
- // Use '*' for helper endpoint to let it resolve necessary relations
99
- params.append("fields", "*")
100
-
101
- // 2. Map queryParams
102
- for (const [key, value] of Object.entries(queryParams || {})) {
103
- if (["metadata", "min_price", "max_price", "limit", "offset", "region_id", "fields"].includes(key)) continue
104
-
105
- const values = Array.isArray(value) ? value : [value]
106
- const lowerKey = key.toLowerCase()
107
-
108
- if (lowerKey === "color") {
109
- // Map 'color' filter to 'option_value' which backend understands for variants
110
- values.forEach(v => params.append("option_value[]", String(v)))
111
- } else if (["material", "gender", "product_type", "type", "style", "brand"].includes(lowerKey)) {
112
- // Map these to metadata as they are defined as metadata in your config
113
- const metaKey = lowerKey === "type" ? "product_type" : lowerKey
114
- values.forEach(v => params.append(`metadata[${metaKey}]`, String(v)))
115
- } else {
116
- // Standard mapping for others (tags, collection_id, etc.)
117
- if (Array.isArray(value)) {
118
- value.forEach(v => params.append(`${key}[]`, String(v)))
119
- } else if (value !== undefined && value !== null) {
120
- params.append(key, String(value))
121
- }
122
- }
123
- }
124
-
125
- // 3. Map price filters (min_price -> price_min, max_price -> price_max)
126
- if ((queryParams as any).min_price) params.append("price_min", String((queryParams as any).min_price))
127
- if ((queryParams as any).max_price) params.append("price_max", String((queryParams as any).max_price))
128
-
129
- // 4. Map metadata filters to metadata[key] format
130
- if ((queryParams as any).metadata) {
131
- for (const [key, value] of Object.entries((queryParams as any).metadata)) {
132
- const values = Array.isArray(value) ? value : [value]
133
-
134
- values.forEach(v => {
135
- if (key.toLowerCase() === "color") {
136
- // Map color in metadata to option_value[]
137
- params.append("option_value[]", String(v))
138
- } else {
139
- // Standard metadata format: metadata[key]=value
140
- params.append(`metadata[${key}]`, String(v))
141
- }
142
- })
143
- }
144
- }
145
-
146
- finalQuery = params
54
+ regionId: region.id,
55
+ queryParams: queryParams as Record<string, unknown> | undefined,
56
+ })
147
57
 
148
- } else {
149
- // Standard endpoint - only merge known safe Medusa keys from queryParams
150
- // to avoid "Unrecognized fields" errors
151
- const safeKeys = ["order", "id", "handle", "status", "created_at", "updated_at", "type_id"]
152
- for (const key of safeKeys) {
153
- if (queryParams && (queryParams as any)[key]) {
154
- finalQuery[key] = (queryParams as any)[key]
155
- }
156
- }
58
+ return {
59
+ response: {
60
+ products: products as unknown as HttpTypes.StoreProduct[],
61
+ count,
62
+ },
63
+ nextPage,
64
+ queryParams,
157
65
  }
158
-
159
- // Use the appended query string to avoid SDK's default serialization issues with brackets
160
- const requestUrl = hasAdvancedFilters ? `${endpoint}?${finalQuery.toString()}` : endpoint;
161
-
162
- return sdk.client
163
- .fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
164
- requestUrl,
165
- {
166
- method: "GET",
167
- query: hasAdvancedFilters ? undefined : finalQuery,
168
- headers,
169
- next: {
170
- ...next,
171
- revalidate: 0, // Disable Next.js cache for now to show logs
172
- },
173
- cache: "no-store", // Ensure it hits backend every time for testing
174
- }
175
- )
176
- .then(({ products, count }) => {
177
-
178
-
179
- const nextPage = count > offset + limit ? _pageParam + 1 : null
180
-
181
- if (products && products.length > 0) {
182
-
183
- }
184
-
185
- return {
186
- response: {
187
- products: products || [],
188
- count: count || 0,
189
- },
190
- nextPage: nextPage,
191
- queryParams,
192
- }
193
- })
194
- .catch((error) => {
195
- throw error
196
- })
197
66
  }
198
67
 
199
- /**
200
- * This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
201
- * It will then return the paginated products based on the page and limit parameters.
202
- */
203
68
  export const listProductsWithSort = async ({
204
69
  page = 1,
205
70
  queryParams,
@@ -217,10 +82,9 @@ export const listProductsWithSort = async ({
217
82
  }> => {
218
83
  const limit = queryParams?.limit || 12
219
84
 
220
- // Directly fetch from backend with correct pagination
221
- // This ensures the backend terminal logs the specific request
222
85
  const {
223
86
  response: { products, count },
87
+ nextPage,
224
88
  } = await listProducts({
225
89
  pageParam: page,
226
90
  queryParams: {
@@ -230,14 +94,9 @@ export const listProductsWithSort = async ({
230
94
  countryCode,
231
95
  })
232
96
 
233
- // Sorting is now handled natively by the backend API via the 'order' query param.
234
- const finalProducts = products
235
-
236
- const nextPage = count > page * limit ? page + 1 : null
237
-
238
97
  return {
239
98
  response: {
240
- products: finalProducts,
99
+ products,
241
100
  count,
242
101
  },
243
102
  nextPage,
@@ -245,9 +104,6 @@ export const listProductsWithSort = async ({
245
104
  }
246
105
  }
247
106
 
248
- /**
249
- * Fetch products that have a specific tag value
250
- */
251
107
  export async function getProductsByTag({
252
108
  tagValue,
253
109
  limit = 12,
@@ -259,7 +115,7 @@ export async function getProductsByTag({
259
115
  }) {
260
116
  try {
261
117
  const result = await listProducts({
262
- queryParams: { tags: [tagValue], limit },
118
+ queryParams: { tags: [tagValue], limit } as HttpTypes.FindParams & HttpTypes.StoreProductListParams,
263
119
  countryCode,
264
120
  })
265
121
 
@@ -270,94 +126,81 @@ export async function getProductsByTag({
270
126
  }
271
127
  }
272
128
 
273
- /**
274
- * Fetch dynamic filter options from the backend API
275
- */
276
- export const getDynamicFilters = async (countryCode: string) => {
277
- const backendUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"
278
- const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
279
-
129
+ export const getDynamicFilters = async (_countryCode: string) => {
280
130
  try {
281
- if (!publishableKey) return { genders: [], productTypes: [], materials: [], colors: [] }
282
-
283
- const response = await fetch(`${backendUrl}/store/product-helper/filters`, {
284
- method: "GET",
285
- headers: {
286
- "Content-Type": "application/json",
287
- "x-publishable-api-key": publishableKey,
288
- },
289
- cache: "no-store",
290
- })
291
-
292
- if (!response.ok) {
131
+ const options = await getStoreClientOptions()
132
+ if (!options.publishableApiKey) {
293
133
  return { genders: [], productTypes: [], materials: [], colors: [] }
294
134
  }
295
135
 
296
- const data = await response.json()
297
-
136
+ const data = await medusaProductHelperFilters(options)
137
+
298
138
  const formatLabel = (str: string) => {
299
139
  return str
300
140
  .split(/[_-]/)
301
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
302
- .join(' ')
141
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
142
+ .join(" ")
303
143
  }
304
144
 
305
- const metadata = data.metadata || {}
306
- const variantOptions = data.variant_options || []
145
+ const metadata = (data.metadata as Record<string, string[]>) || {}
146
+ const variantOptions = (data.variant_options as Array<{ option_title: string; values?: string[] }>) || []
307
147
 
308
- // Gather all unique colors from all possible sources
309
148
  const colorSet = new Set<string>()
310
-
311
- // 1. From variant options (check all options with title 'color')
312
- variantOptions.forEach((o: any) => {
313
- if (o.option_title.toLowerCase() === 'color' || o.option_title.toLowerCase() === 'colour') {
314
- o.values?.forEach((v: string) => {
149
+
150
+ variantOptions.forEach((o) => {
151
+ if (o.option_title.toLowerCase() === "color" || o.option_title.toLowerCase() === "colour") {
152
+ o.values?.forEach((v) => {
315
153
  if (v) colorSet.add(v.trim().toLowerCase())
316
154
  })
317
155
  }
318
156
  })
319
157
 
320
- // 2. From metadata colors (handle newline/comma separated values)
321
158
  if (metadata.color) {
322
- metadata.color.forEach((c: string) => {
159
+ metadata.color.forEach((c) => {
323
160
  if (c) {
324
- const parts = c.split(/[,/\n\r]+/).map(s => s.trim()).filter(Boolean)
325
- parts.forEach(p => colorSet.add(p.toLowerCase()))
161
+ const parts = c
162
+ .split(/[,/\n\r]+/)
163
+ .map((s) => s.trim())
164
+ .filter(Boolean)
165
+ parts.forEach((p) => colorSet.add(p.toLowerCase()))
326
166
  }
327
167
  })
328
168
  }
329
169
 
330
170
  return {
331
- genders: (metadata.gender || []).sort().map((g: string) => ({
171
+ genders: (metadata.gender || []).sort().map((g) => ({
332
172
  value: g,
333
- label: formatLabel(g)
334
- })),
335
- productTypes: (data.product_types || []).sort((a: any, b: any) => a.label.localeCompare(b.label)).map((t: any) => ({
336
- value: t.label,
337
- label: formatLabel(t.label)
173
+ label: formatLabel(g),
338
174
  })),
339
- materials: (metadata.material || []).sort().map((m: string) => ({
175
+ productTypes: ((data.product_types as Array<{ label: string }>) || [])
176
+ .sort((a, b) => a.label.localeCompare(b.label))
177
+ .map((t) => ({
178
+ value: t.label,
179
+ label: formatLabel(t.label),
180
+ })),
181
+ materials: (metadata.material || []).sort().map((m) => ({
340
182
  value: m,
341
- label: formatLabel(m)
183
+ label: formatLabel(m),
342
184
  })),
343
- colors: Array.from(colorSet).sort().map((c: string) => {
344
- let hex = ""
345
- try {
346
- // Try to resolve color hex code using the Color library
347
- hex = Color(c.replace(/\s+/g, '').toLowerCase()).hex()
348
- } catch (e) {
185
+ colors: Array.from(colorSet)
186
+ .sort()
187
+ .map((c) => {
188
+ let hex = ""
349
189
  try {
350
- hex = Color(c.toLowerCase()).hex()
351
- } catch (e2) {
352
- // No hex found
190
+ hex = Color(c.replace(/\s+/g, "").toLowerCase()).hex()
191
+ } catch {
192
+ try {
193
+ hex = Color(c.toLowerCase()).hex()
194
+ } catch {
195
+ // no hex
196
+ }
353
197
  }
354
- }
355
- return {
356
- value: c,
357
- label: formatLabel(c),
358
- hex
359
- }
360
- })
198
+ return {
199
+ value: c,
200
+ label: formatLabel(c),
201
+ hex,
202
+ }
203
+ }),
361
204
  }
362
205
  } catch (error) {
363
206
  console.error("Error fetching dynamic filters:", error)
@@ -365,14 +208,8 @@ export const getDynamicFilters = async (countryCode: string) => {
365
208
  }
366
209
  }
367
210
 
368
- /**
369
- * Fetch a single product by its handle
370
- */
371
211
  export async function getProductByHandle(handle: string) {
372
- const result = await sdk.store.product.list(
373
- { handle, fields: "*variants.calculated_price,+variants.inventory_quantity,+variants.manage_inventory,+variants.allow_backorder,*variants.options,*options,*options.values,*images,*thumbnail,+metadata" },
374
- { next: { tags: ["products"] } }
375
- )
376
-
377
- return result.products[0]
212
+ const options = await getStoreClientOptions()
213
+ const product = await medusaProductByHandle(handle, options)
214
+ return product as unknown as HttpTypes.StoreProduct | undefined
378
215
  }
@@ -1,9 +1,12 @@
1
1
  "use server"
2
2
 
3
+ import type { FetchArgs } from "@medusajs/js-sdk"
3
4
  import { sdk } from "../config"
4
5
  import medusaError from "../util/medusa-error"
5
6
  import { HttpTypes } from "@medusajs/types"
6
7
  import { getCacheOptions } from "../cookies"
8
+ import { medusaRegionList } from "medusa-services/regions"
9
+ import { getStoreCartClientOptions } from "../util/store-client"
7
10
 
8
11
  export const listRegions = async () => {
9
12
  const next = {
@@ -15,7 +18,7 @@ export const listRegions = async () => {
15
18
  method: "GET",
16
19
  next,
17
20
  cache: "force-cache",
18
- })
21
+ } as FetchArgs & { next?: typeof next; cache?: RequestCache })
19
22
  .then(({ regions }) => regions)
20
23
  .catch(medusaError)
21
24
  }
@@ -30,7 +33,7 @@ export const retrieveRegion = async (id: string) => {
30
33
  method: "GET",
31
34
  next,
32
35
  cache: "force-cache",
33
- })
36
+ } as FetchArgs & { next?: typeof next; cache?: RequestCache })
34
37
  .then(({ region }) => region)
35
38
  .catch(medusaError)
36
39
  }
@@ -43,15 +46,16 @@ export const getRegion = async (countryCode: string) => {
43
46
  return regionMap.get(countryCode)
44
47
  }
45
48
 
46
- const regions = await listRegions()
49
+ const options = await getStoreCartClientOptions()
50
+ const { regions } = await medusaRegionList(options)
47
51
 
48
- if (!regions) {
52
+ if (!regions?.length) {
49
53
  return null
50
54
  }
51
55
 
52
56
  regions.forEach((region) => {
53
57
  region.countries?.forEach((c) => {
54
- regionMap.set(c?.iso_2 ?? "", region)
58
+ regionMap.set(c?.iso_2 ?? "", region as unknown as HttpTypes.StoreRegion)
55
59
  })
56
60
  })
57
61
 
@@ -59,7 +63,7 @@ export const getRegion = async (countryCode: string) => {
59
63
  ? regionMap.get(countryCode)
60
64
  : regionMap.get("us")
61
65
 
62
- return region
66
+ return region ?? null
63
67
  } catch (e: any) {
64
68
  return null
65
69
  }