medusa-storefront-data 1.0.0 → 2.1.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 (110) 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 +96 -145
  23. package/dist/server/dynamic-config.d.ts.map +1 -1
  24. package/dist/server/dynamic-config.js +38 -12
  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 +7 -6
  65. package/dist/server/swaps.d.ts.map +1 -1
  66. package/dist/server/swaps.js +23 -57
  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 +146 -190
  90. package/src/server/dynamic-config.ts +38 -12
  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 +94 -123
  105. package/src/server/variants.ts +9 -28
  106. package/src/server/wishlist.ts +1 -1
  107. package/src/util/revalidate-cart.ts +10 -0
  108. package/src/util/sort-products.ts +2 -47
  109. package/src/util/store-client.ts +93 -0
  110. package/src/services/middleware.ts +0 -54
@@ -1,11 +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 { revalidateTag, revalidatePath } from "next/cache"
7
8
  import { redirect } from "next/navigation"
8
- import { headers } from "next/headers"
9
+ import { headers as nextHeaders } from "next/headers"
9
10
  import {
10
11
  getAuthHeaders,
11
12
  getCacheOptions,
@@ -20,11 +21,52 @@ import {
20
21
  removeBuyNowCartId,
21
22
  } from "../cookies"
22
23
  import { getRegion } from "./regions"
24
+
25
+ function normalizeCartEmail(email: unknown): string | undefined {
26
+ if (typeof email !== "string") return undefined
27
+ const normalized = email.trim().toLowerCase()
28
+ return normalized || undefined
29
+ }
30
+
31
+ function isValidCartEmail(email: string): boolean {
32
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
33
+ }
23
34
  import { getLocale } from "./locale-actions"
24
35
  import { retrieveCustomer, transferCart } from "./customer"
36
+ import {
37
+ medusaCartCreate,
38
+ medusaCartRetrieve,
39
+ medusaCartUpdate,
40
+ medusaCartAddLineItem,
41
+ medusaCartUpdateLineItem,
42
+ medusaCartRemoveLineItem,
43
+ medusaCartApplyPromotions,
44
+ medusaCartAddShippingMethod,
45
+ medusaCartComplete,
46
+ medusaCartSkipMerge,
47
+ medusaCartDelete,
48
+ medusaCartList,
49
+ medusaShippingOptionsList,
50
+ MEDUSA_STORE_CART_DETAIL_FIELDS,
51
+ } from "medusa-services/cart"
52
+ import {
53
+ medusaCustomerCreateAddress,
54
+ medusaCustomerRetrieve,
55
+ medusaCustomerUpdateAddress,
56
+ } from "medusa-services/customer"
57
+ import { medusaPaymentSessionInitiate } from "medusa-services/payment"
58
+ import { getStoreCartClientOptions } from "../util/store-client"
59
+ import { revalidateCartTags } from "../util/revalidate-cart"
25
60
 
26
61
  import { cache } from "react"
27
62
 
63
+ function throwCartError(error: unknown): never {
64
+ if (error && typeof error === "object" && "response" in error) {
65
+ medusaError(error)
66
+ }
67
+ throw error instanceof Error ? error : new Error(String(error))
68
+ }
69
+
28
70
  /**
29
71
  * Retrieves a cart by its ID. If no ID is provided, it will use the cart ID from the cookies.
30
72
  * @param cartId - optional - The ID of the cart to retrieve.
@@ -39,22 +81,18 @@ export const retrieveCart = cache(
39
81
  // If we're not explicitly asking for a specific cartId and we have an active cart
40
82
  if (!cartId && id) {
41
83
  try {
42
- const headerList = await headers()
84
+ const headerList = await nextHeaders()
43
85
  const pathname = headerList.get("x-pathname") || headerList.get("referer") || ""
44
86
 
45
87
  // Skip metadata check if we are clearly in checkout to avoid extra API call
46
88
  if (!pathname.includes("/checkout")) {
47
- const currentCart = await sdk.client
48
- .fetch<HttpTypes.StoreCartResponse>(`/store/carts/${id}`, {
49
- method: "GET",
50
- query: { fields: "metadata" },
51
- headers: await getAuthHeaders(),
52
- cache: "no-store",
53
- })
89
+ const options = await getStoreCartClientOptions()
90
+ const currentCart = await medusaCartRetrieve(id, options, { fields: "metadata" })
54
91
  .then(({ cart }) => cart)
55
92
  .catch(() => null)
56
93
 
57
- if (currentCart?.metadata?.is_buy_now || currentCart?.metadata?.is_reorder) {
94
+ const cartMeta = currentCart?.metadata as Record<string, unknown> | null | undefined
95
+ if (cartMeta?.is_buy_now || cartMeta?.is_reorder) {
58
96
  await removeBuyNowCartId()
59
97
  id = await getCartId() // Re-fetch ID which will now fall back to the real main cart
60
98
  revalidateTag("carts")
@@ -65,14 +103,13 @@ export const retrieveCart = cache(
65
103
  }
66
104
  }
67
105
 
68
- fields ??=
69
- "*items, *region, *items.product, *items.product.thumbnail, *items.product.images, *items.product.options, *items.product.variants, +items.product.variants.inventory_quantity, +items.product.variants.manage_inventory, +items.product.variants.allow_backorder, *items.product.variants.options, *items.variant, +items.variant.inventory_quantity, +items.variant.manage_inventory, +items.variant.allow_backorder, *items.variant.images, *items.variant.product, *items.variant.product.thumbnail, *items.variant.product.images, *items.variant.options, *items.thumbnail, *items.metadata, +items.total, +items.adjustments, *promotions, +shipping_methods.name, +shipping_methods.adjustments"
106
+ fields ??= MEDUSA_STORE_CART_DETAIL_FIELDS
70
107
 
71
108
  if (!id) {
72
109
  return null
73
110
  }
74
111
 
75
- const headers = {
112
+ const authHeaders = {
76
113
  ...(await getAuthHeaders()),
77
114
  }
78
115
 
@@ -86,10 +123,10 @@ export const retrieveCart = cache(
86
123
  query: {
87
124
  fields,
88
125
  },
89
- headers,
126
+ headers: authHeaders,
90
127
  next,
91
128
  cache: "no-store",
92
- })
129
+ } as FetchArgs & { next?: typeof next; cache?: RequestCache })
93
130
  .then(({ cart }: { cart: HttpTypes.StoreCart }) => {
94
131
  return cart
95
132
  })
@@ -106,19 +143,15 @@ export async function getOrSetCart(countryCode: string) {
106
143
  }
107
144
 
108
145
  let cart = await retrieveCart(undefined, "id,region_id")
109
-
110
- const headers = {
111
- ...(await getAuthHeaders()),
112
- }
146
+ const options = await getStoreCartClientOptions()
113
147
 
114
148
  if (!cart) {
115
149
  const locale = await getLocale()
116
- const cartResp = await sdk.store.cart.create(
117
- { region_id: region.id, locale: locale || undefined },
118
- {},
119
- headers
120
- )
121
- cart = cartResp.cart
150
+ const { cart: createdCart } = await medusaCartCreate(options, {
151
+ region_id: region.id,
152
+ locale: locale || undefined,
153
+ })
154
+ cart = createdCart as unknown as HttpTypes.StoreCart
122
155
 
123
156
  await setCartId(cart.id)
124
157
 
@@ -127,7 +160,7 @@ export async function getOrSetCart(countryCode: string) {
127
160
  }
128
161
 
129
162
  if (cart && cart?.region_id !== region.id) {
130
- await sdk.store.cart.update(cart.id, { region_id: region.id }, {}, headers)
163
+ await medusaCartUpdate(cart.id, { region_id: region.id }, options)
131
164
  const cartCacheTag = await getCacheTag("carts")
132
165
  revalidateTag(cartCacheTag)
133
166
  }
@@ -142,22 +175,14 @@ export async function updateCart(data: HttpTypes.StoreUpdateCart) {
142
175
  throw new Error("No existing cart found, please create one before updating")
143
176
  }
144
177
 
145
- const headers = {
146
- ...(await getAuthHeaders()),
178
+ try {
179
+ const options = await getStoreCartClientOptions()
180
+ const { cart } = await medusaCartUpdate(cartId, data as Record<string, unknown>, options)
181
+ await revalidateCartTags()
182
+ return cart as unknown as HttpTypes.StoreCart
183
+ } catch (e) {
184
+ throwCartError(e)
147
185
  }
148
-
149
- return sdk.store.cart
150
- .update(cartId, data, {}, headers)
151
- .then(async ({ cart }: { cart: HttpTypes.StoreCart }) => {
152
- const cartCacheTag = await getCacheTag("carts")
153
- revalidateTag(cartCacheTag)
154
-
155
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
156
- revalidateTag(fulfillmentCacheTag)
157
-
158
- return cart
159
- })
160
- .catch(medusaError)
161
186
  }
162
187
 
163
188
  export async function addToCart({
@@ -179,28 +204,13 @@ export async function addToCart({
179
204
  throw new Error("Error retrieving or creating cart")
180
205
  }
181
206
 
182
- const headers = {
183
- ...(await getAuthHeaders()),
207
+ try {
208
+ const options = await getStoreCartClientOptions()
209
+ await medusaCartAddLineItem(cart.id, { variant_id: variantId, quantity }, options)
210
+ await revalidateCartTags()
211
+ } catch (e) {
212
+ throwCartError(e)
184
213
  }
185
-
186
- await sdk.store.cart
187
- .createLineItem(
188
- cart.id,
189
- {
190
- variant_id: variantId,
191
- quantity,
192
- },
193
- {},
194
- headers
195
- )
196
- .then(async () => {
197
- const cartCacheTag = await getCacheTag("carts")
198
- revalidateTag(cartCacheTag)
199
-
200
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
201
- revalidateTag(fulfillmentCacheTag)
202
- })
203
- .catch(medusaError)
204
214
  }
205
215
 
206
216
  export async function buyNow({
@@ -222,23 +232,15 @@ export async function buyNow({
222
232
  throw new Error(`Region not found for country code: ${countryCode}`)
223
233
  }
224
234
 
225
- const headers = {
226
- ...(await getAuthHeaders()),
227
- }
228
-
235
+ const options = await getStoreCartClientOptions()
229
236
  const locale = await getLocale()
230
237
 
231
238
  // 1. Create a NEW cart regardless of existing one
232
- const cartResp = await sdk.store.cart.create(
233
- {
234
- region_id: region.id,
235
- locale: locale || undefined,
236
- metadata: { is_buy_now: true }
237
- },
238
- {},
239
- headers
240
- )
241
- const cart = cartResp.cart
239
+ const { cart } = await medusaCartCreate(options, {
240
+ region_id: region.id,
241
+ locale: locale || undefined,
242
+ metadata: { is_buy_now: true },
243
+ })
242
244
 
243
245
  // Save the new cart id in "buy_now_cart_id" cookie
244
246
  await removeBuyNowCartId()
@@ -246,25 +248,13 @@ export async function buyNow({
246
248
 
247
249
  // Ensure this new cart is not merged with existing ones
248
250
  try {
249
- await sdk.client.fetch(`/store/carts/merge/skip`, {
250
- method: "POST",
251
- body: { cart_id: cart.id },
252
- headers,
253
- })
251
+ await medusaCartSkipMerge(cart.id, options)
254
252
  } catch (e) {
255
253
  console.error("Failed to skip cart merge for buy now cart:", e)
256
254
  }
257
255
 
258
256
  // 2. Add the item to this new cart
259
- await sdk.store.cart.createLineItem(
260
- cart.id,
261
- {
262
- variant_id: variantId,
263
- quantity,
264
- },
265
- {},
266
- headers
267
- )
257
+ await medusaCartAddLineItem(cart.id, { variant_id: variantId, quantity }, options)
268
258
 
269
259
  // 3. (REMOVED: No longer overwriting the main cart ID, because getCartId handles buy_now_cart_id priority)
270
260
 
@@ -278,45 +268,43 @@ export async function buyNow({
278
268
  if (defaultAddress) {
279
269
  try {
280
270
  // Set addresses
281
- await sdk.store.cart.update(cart.id, {
282
- shipping_address: {
283
- first_name: defaultAddress.first_name,
284
- last_name: defaultAddress.last_name,
285
- address_1: defaultAddress.address_1,
286
- address_2: defaultAddress.address_2,
287
- city: defaultAddress.city,
288
- country_code: defaultAddress.country_code,
289
- postal_code: defaultAddress.postal_code,
290
- province: defaultAddress.province,
291
- phone: defaultAddress.phone,
292
- company: defaultAddress.company,
293
- },
294
- billing_address: {
295
- first_name: defaultAddress.first_name,
296
- last_name: defaultAddress.last_name,
297
- address_1: defaultAddress.address_1,
298
- address_2: defaultAddress.address_2,
299
- city: defaultAddress.city,
300
- country_code: defaultAddress.country_code,
301
- postal_code: defaultAddress.postal_code,
302
- province: defaultAddress.province,
303
- phone: defaultAddress.phone,
304
- company: defaultAddress.company,
271
+ await medusaCartUpdate(
272
+ cart.id,
273
+ {
274
+ shipping_address: {
275
+ first_name: defaultAddress.first_name,
276
+ last_name: defaultAddress.last_name,
277
+ address_1: defaultAddress.address_1,
278
+ address_2: defaultAddress.address_2,
279
+ city: defaultAddress.city,
280
+ country_code: defaultAddress.country_code,
281
+ postal_code: defaultAddress.postal_code,
282
+ province: defaultAddress.province,
283
+ phone: defaultAddress.phone,
284
+ company: defaultAddress.company,
285
+ },
286
+ billing_address: {
287
+ first_name: defaultAddress.first_name,
288
+ last_name: defaultAddress.last_name,
289
+ address_1: defaultAddress.address_1,
290
+ address_2: defaultAddress.address_2,
291
+ city: defaultAddress.city,
292
+ country_code: defaultAddress.country_code,
293
+ postal_code: defaultAddress.postal_code,
294
+ province: defaultAddress.province,
295
+ phone: defaultAddress.phone,
296
+ company: defaultAddress.company,
297
+ },
298
+ email: customer?.email ?? "",
305
299
  },
306
- email: customer.email
307
- }, {}, headers)
300
+ options
301
+ )
308
302
 
309
303
  // Fetch and set first shipping method
310
- const { shipping_options } = await sdk.client.fetch<{
311
- shipping_options: HttpTypes.StoreCartShippingOption[]
312
- }>("/store/shipping-options", {
313
- query: { cart_id: cart.id },
314
- headers,
315
- cache: "no-store",
316
- })
304
+ const { shipping_options } = await medusaShippingOptionsList(cart.id, options)
317
305
 
318
306
  if (shipping_options?.length > 0) {
319
- await sdk.store.cart.addShippingMethod(cart.id, { option_id: shipping_options[0].id }, {}, headers)
307
+ await medusaCartAddShippingMethod(cart.id, shipping_options[0].id, options)
320
308
  skipToPayment = true
321
309
  }
322
310
  } catch (e) {
@@ -354,20 +342,13 @@ export async function updateLineItem({
354
342
  throw new Error("Missing cart ID when updating line item")
355
343
  }
356
344
 
357
- const headers = {
358
- ...(await getAuthHeaders()),
345
+ try {
346
+ const options = await getStoreCartClientOptions()
347
+ await medusaCartUpdateLineItem(cartId, lineId, { quantity }, options)
348
+ await revalidateCartTags()
349
+ } catch (e) {
350
+ throwCartError(e)
359
351
  }
360
-
361
- await sdk.store.cart
362
- .updateLineItem(cartId, lineId, { quantity }, {}, headers)
363
- .then(async () => {
364
- const cartCacheTag = await getCacheTag("carts")
365
- revalidateTag(cartCacheTag)
366
-
367
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
368
- revalidateTag(fulfillmentCacheTag)
369
- })
370
- .catch(medusaError)
371
352
  }
372
353
 
373
354
  export async function deleteLineItem(lineId: string) {
@@ -381,20 +362,13 @@ export async function deleteLineItem(lineId: string) {
381
362
  throw new Error("Missing cart ID when deleting line item")
382
363
  }
383
364
 
384
- const headers = {
385
- ...(await getAuthHeaders()),
365
+ try {
366
+ const options = await getStoreCartClientOptions()
367
+ await medusaCartRemoveLineItem(cartId, lineId, options)
368
+ await revalidateCartTags()
369
+ } catch (e) {
370
+ throwCartError(e)
386
371
  }
387
-
388
- await sdk.store.cart
389
- .deleteLineItem(cartId, lineId, {}, headers)
390
- .then(async () => {
391
- const cartCacheTag = await getCacheTag("carts")
392
- revalidateTag(cartCacheTag)
393
-
394
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
395
- revalidateTag(fulfillmentCacheTag)
396
- })
397
- .catch(medusaError)
398
372
  }
399
373
 
400
374
  export async function updateLineItemVariant({
@@ -434,17 +408,14 @@ export async function setShippingMethod({
434
408
  cartId: string
435
409
  shippingMethodId: string
436
410
  }) {
437
- const headers = {
438
- ...(await getAuthHeaders()),
411
+ try {
412
+ const options = await getStoreCartClientOptions()
413
+ await medusaCartAddShippingMethod(cartId, shippingMethodId, options)
414
+ const cartCacheTag = await getCacheTag("carts")
415
+ revalidateTag(cartCacheTag)
416
+ } catch (e) {
417
+ throwCartError(e)
439
418
  }
440
-
441
- return sdk.store.cart
442
- .addShippingMethod(cartId, { option_id: shippingMethodId }, {}, headers)
443
- .then(async () => {
444
- const cartCacheTag = await getCacheTag("carts")
445
- revalidateTag(cartCacheTag)
446
- })
447
- .catch(medusaError)
448
419
  }
449
420
 
450
421
  /**
@@ -457,12 +428,9 @@ export async function setShippingMethodSilently({
457
428
  cartId: string
458
429
  shippingMethodId: string
459
430
  }) {
460
- const headers = {
461
- ...(await getAuthHeaders()),
462
- }
463
-
464
431
  try {
465
- await sdk.store.cart.addShippingMethod(cartId, { option_id: shippingMethodId }, {}, headers)
432
+ const options = await getStoreCartClientOptions()
433
+ await medusaCartAddShippingMethod(cartId, shippingMethodId, options)
466
434
  return { success: true }
467
435
  } catch (e) {
468
436
  return { success: false }
@@ -474,10 +442,6 @@ export async function initiatePaymentSession(
474
442
  cart: HttpTypes.StoreCart,
475
443
  data: HttpTypes.StoreInitializePaymentSession
476
444
  ) {
477
- const headers = {
478
- ...(await getAuthHeaders()),
479
- }
480
-
481
445
  // 1. RE-FETCH cart with NO CACHE to ensure we have the latest data from the DB
482
446
  const latestCart = await retrieveCart(cart.id)
483
447
  if (!latestCart) throw new Error("Cart not found")
@@ -526,13 +490,17 @@ export async function initiatePaymentSession(
526
490
  }
527
491
 
528
492
  if (Object.keys(addressUpdates).length > 0) {
529
- await sdk.store.cart.update(latestCart.id, addressUpdates, {}, headers)
493
+ const options = await getStoreCartClientOptions()
494
+ await medusaCartUpdate(latestCart.id, addressUpdates, options)
530
495
  }
531
496
  }
532
497
 
533
- // 3. Final re-fetch (direct SDK call to bypass any lib-level cache)
534
- const cartResponse = await sdk.store.cart.retrieve(cart.id, { fields: "*shipping_address,*billing_address" }, headers)
535
- const finalCart = cartResponse.cart
498
+ // 3. Final re-fetch (direct call to bypass any lib-level cache)
499
+ const options = await getStoreCartClientOptions()
500
+ const { cart: finalCartRaw } = await medusaCartRetrieve(cart.id, options, {
501
+ fields: "*shipping_address,*billing_address",
502
+ })
503
+ const finalCart = finalCartRaw as unknown as HttpTypes.StoreCart
536
504
 
537
505
  // 4. PRE-FLIGHT VALIDATION: Only strictly block for Razorpay, be more lenient for COD
538
506
  const isRazorpayProvider = data.provider_id.includes("razorpay")
@@ -561,17 +529,19 @@ export async function initiatePaymentSession(
561
529
  }
562
530
  }
563
531
 
564
- return sdk.store.payment
565
- .initiatePaymentSession(finalCart, enhancedData, {}, headers)
566
- .then(async (resp) => {
567
- const cartCacheTag = await getCacheTag("carts")
568
- revalidateTag(cartCacheTag)
569
- return resp
570
- })
571
- .catch((e) => {
572
- const errorMsg = e.message || e.response?.data?.message || "Unknown error"
573
- throw new Error(`Razorpay Initialization Failed: ${errorMsg}`)
532
+ try {
533
+ await medusaPaymentSessionInitiate(finalCart.id, enhancedData, options)
534
+ const { cart: refreshedCart } = await medusaCartRetrieve(finalCart.id, options, {
535
+ fields: `${MEDUSA_STORE_CART_DETAIL_FIELDS}, *payment_collection, *payment_collection.payment_sessions`,
574
536
  })
537
+ const cartCacheTag = await getCacheTag("carts")
538
+ revalidateTag(cartCacheTag)
539
+ return refreshedCart as unknown as HttpTypes.StoreCart
540
+ } catch (e: any) {
541
+ const errorMsg = e.message || e.response?.data?.message || "Unknown error"
542
+ const label = isRazorpayProvider ? "Razorpay" : "Payment"
543
+ throw new Error(`${label} initialization failed: ${errorMsg}`)
544
+ }
575
545
  }
576
546
 
577
547
  export async function applyPromotions(codes: string[]) {
@@ -581,22 +551,14 @@ export async function applyPromotions(codes: string[]) {
581
551
  throw new Error("No existing cart found")
582
552
  }
583
553
 
584
- const headers = {
585
- ...(await getAuthHeaders()),
554
+ try {
555
+ const options = await getStoreCartClientOptions()
556
+ const { cart } = await medusaCartApplyPromotions(cartId, codes, options)
557
+ await revalidateCartTags()
558
+ return cart as unknown as HttpTypes.StoreCart
559
+ } catch (e) {
560
+ throwCartError(e)
586
561
  }
587
-
588
- return sdk.store.cart
589
- .update(cartId, { promo_codes: codes }, {}, headers)
590
- .then(async ({ cart }) => {
591
- const cartCacheTag = await getCacheTag("carts")
592
- revalidateTag(cartCacheTag)
593
-
594
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
595
- revalidateTag(fulfillmentCacheTag)
596
-
597
- return cart
598
- })
599
- .catch(medusaError)
600
562
  }
601
563
 
602
564
  export async function applyGiftCard(code: string) {
@@ -693,22 +655,21 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
693
655
 
694
656
  const data = {
695
657
  shipping_address: shippingAddress,
696
- email: formData.get("email"),
658
+ email: normalizeCartEmail(formData.get("email")),
697
659
  } as any
698
660
 
661
+ if (data.email && !isValidCartEmail(data.email)) {
662
+ throw new Error("Please enter a valid email address.")
663
+ }
664
+
699
665
 
700
666
 
701
667
  // Save address to customer profile if logged in
702
668
  const authHeaders = await getAuthHeaders()
703
669
  if (authHeaders && "authorization" in authHeaders) {
704
670
  try {
705
- // Fetch current customer to check if address already exists
706
- const { customer } = await sdk.client.fetch<{ customer: HttpTypes.StoreCustomer }>(`/store/customers/me`, {
707
- method: "GET",
708
- query: { fields: "*addresses" },
709
- headers: authHeaders as Record<string, string>,
710
- cache: "no-store",
711
- })
671
+ const options = await getStoreCartClientOptions()
672
+ const { customer } = await medusaCustomerRetrieve(options, { fields: "*addresses" })
712
673
 
713
674
  const addressExists = customer?.addresses?.some((a: any) =>
714
675
  a.address_1 === shippingAddress.address_1 &&
@@ -719,7 +680,7 @@ export async function setAddresses(currentState: unknown, formData: FormData) {
719
680
  )
720
681
 
721
682
  if (!addressExists) {
722
- await sdk.store.customer.createAddress(shippingAddress, {}, authHeaders as Record<string, string>)
683
+ await medusaCustomerCreateAddress(shippingAddress, options)
723
684
  const customerCacheTag = await getCacheTag("customers")
724
685
  revalidateTag(customerCacheTag)
725
686
  }
@@ -768,22 +729,19 @@ export async function placeOrder(cartId?: string) {
768
729
  throw new Error("No existing cart found when placing an order")
769
730
  }
770
731
 
771
- const headers = {
772
- ...(await getAuthHeaders()),
732
+ let cartRes
733
+ try {
734
+ const options = await getStoreCartClientOptions()
735
+ cartRes = await medusaCartComplete(id, options)
736
+ const cartCacheTag = await getCacheTag("carts")
737
+ revalidateTag(cartCacheTag)
738
+ } catch (e) {
739
+ throwCartError(e)
773
740
  }
774
741
 
775
- const cartRes = await sdk.store.cart
776
- .complete(id, {}, headers)
777
- .then(async (cartRes) => {
778
- const cartCacheTag = await getCacheTag("carts")
779
- revalidateTag(cartCacheTag)
780
- return cartRes
781
- })
782
- .catch(medusaError)
783
-
784
742
  if (cartRes?.type === "order") {
785
- const countryCode =
786
- cartRes.order.shipping_address?.country_code?.toLowerCase()
743
+ const order = cartRes.order as HttpTypes.StoreOrder
744
+ const countryCode = order.shipping_address?.country_code?.toLowerCase()
787
745
 
788
746
  const orderCacheTag = await getCacheTag("orders")
789
747
  revalidateTag(orderCacheTag)
@@ -802,10 +760,10 @@ export async function placeOrder(cartId?: string) {
802
760
  await removeCartId()
803
761
  }
804
762
 
805
- redirect(`/${countryCode}/order/${cartRes?.order.id}/confirmed`)
763
+ redirect(`/${countryCode}/order/${order.id}/confirmed`)
806
764
  }
807
765
 
808
- return cartRes.cart
766
+ return cartRes.cart as unknown as HttpTypes.StoreCart
809
767
  }
810
768
 
811
769
  /**
@@ -852,15 +810,11 @@ export async function listCartOptions() {
852
810
  next,
853
811
  headers,
854
812
  cache: "force-cache",
855
- })
813
+ } as FetchArgs & { next?: typeof next; cache?: RequestCache })
856
814
  }
857
815
 
858
816
  export async function addCustomerAddressToCart(currentState: unknown, formData: FormData) {
859
817
  try {
860
- const headers = {
861
- ...(await getAuthHeaders()),
862
- }
863
-
864
818
  const shippingCountryCode = (formData.get("shipping_address.country_code") as string)?.toLowerCase() || "in"
865
819
 
866
820
  // Parse address data from formData (which uses shipping_address. prefix)
@@ -886,10 +840,11 @@ export async function addCustomerAddressToCart(currentState: unknown, formData:
886
840
  // 1. Add/Update Customer Address Book
887
841
  // We try/catch this separately so if it fails (e.g. user not logged in), we still try to proceed with checkout
888
842
  try {
843
+ const options = await getStoreCartClientOptions()
889
844
  if (addressId) {
890
- await sdk.store.customer.updateAddress(addressId, addressData, {}, headers)
845
+ await medusaCustomerUpdateAddress(addressId, addressData, options)
891
846
  } else {
892
- await sdk.store.customer.createAddress(addressData, {}, headers)
847
+ await medusaCustomerCreateAddress(addressData, options)
893
848
  }
894
849
  const customerCacheTag = await getCacheTag("customers")
895
850
  revalidateTag(customerCacheTag)
@@ -918,9 +873,13 @@ export async function addCustomerAddressToCart(currentState: unknown, formData:
918
873
  country_code: addressData.country_code,
919
874
  phone: addressData.phone,
920
875
  },
921
- email: formData.get("email"),
876
+ email: normalizeCartEmail(formData.get("email")),
922
877
  } as any
923
878
 
879
+ if (cartData.email && !isValidCartEmail(cartData.email)) {
880
+ throw new Error("Please enter a valid email address.")
881
+ }
882
+
924
883
  const sameAsBilling = formData.get("same_as_billing")
925
884
  if (sameAsBilling === "on") {
926
885
  cartData.billing_address = cartData.shipping_address
@@ -949,18 +908,19 @@ export async function updateAddressSilently(data: any) {
949
908
  if (!cartId) return
950
909
 
951
910
  try {
952
- const headers = {
953
- ...(await getAuthHeaders()),
911
+ const payload = { ...data }
912
+ if (payload.email !== undefined) {
913
+ payload.email = normalizeCartEmail(payload.email)
914
+ if (payload.email && !isValidCartEmail(payload.email)) {
915
+ return { success: false, error: "Invalid email address." }
916
+ }
954
917
  }
955
918
 
956
- await sdk.store.cart.update(cartId, data, {}, headers)
919
+ const options = await getStoreCartClientOptions()
920
+ await medusaCartUpdate(cartId, payload, options)
957
921
 
958
922
  // Revalidate tags to ensure CartTotals gets new shipping info
959
- const cartCacheTag = await getCacheTag("carts")
960
- revalidateTag(cartCacheTag)
961
-
962
- const fulfillmentCacheTag = await getCacheTag("fulfillment")
963
- revalidateTag(fulfillmentCacheTag)
923
+ await revalidateCartTags()
964
924
 
965
925
  return { success: true }
966
926
  } catch (e) {
@@ -975,11 +935,8 @@ export async function updateCartMetadataSilently(metadata: any) {
975
935
  if (!cartId) return
976
936
 
977
937
  try {
978
- const headers = {
979
- ...(await getAuthHeaders()),
980
- }
981
-
982
- await sdk.store.cart.update(cartId, { metadata }, {}, headers)
938
+ const options = await getStoreCartClientOptions()
939
+ await medusaCartUpdate(cartId, { metadata }, options)
983
940
  // We intentionally DO NOT call revalidateTag here to prevent page refresh loops
984
941
  return { success: true }
985
942
  } catch (e) {
@@ -988,36 +945,31 @@ export async function updateCartMetadataSilently(metadata: any) {
988
945
  }
989
946
 
990
947
  export async function getAbandonedCarts() {
991
- const headers = {
992
- ...(await getAuthHeaders()),
993
- }
948
+ const authHeaders = await getAuthHeaders()
994
949
 
995
950
  // If no authorization, return empty arrays
996
- if (!headers["authorization"]) {
951
+ if (!("authorization" in authHeaders)) {
997
952
  return { buyNowCarts: [], reorderCarts: [] }
998
953
  }
999
954
 
1000
955
  try {
1001
- // Just fetch all carts for the customer and filter locally
1002
- const res = await sdk.client.fetch<{ carts: HttpTypes.StoreCart[] }>(`/store/carts`, {
1003
- method: "GET",
1004
- query: {
1005
- fields: "*items, *items.product, *items.product.thumbnail, *items.variant, *items.metadata, +total",
1006
- },
1007
- headers,
1008
- cache: "no-store",
956
+ const options = await getStoreCartClientOptions()
957
+ const res = await medusaCartList(options, {
958
+ fields: "*items, *items.product, *items.product.thumbnail, *items.variant, *items.metadata, +total",
1009
959
  }).catch(() => null)
1010
960
 
1011
961
  let buyNowCarts: HttpTypes.StoreCart[] = []
1012
962
  let reorderCarts: HttpTypes.StoreCart[] = []
1013
963
 
1014
964
  if (res && res.carts) {
1015
- // Filter out the main active cart
1016
965
  const currentCartId = await getCartId()
1017
- const filteredCarts = res.carts.filter(c => c.id !== currentCartId)
1018
-
1019
- buyNowCarts = filteredCarts.filter(c => c.metadata?.is_buy_now === true)
1020
- reorderCarts = filteredCarts.filter(c => c.metadata?.is_reorder === true)
966
+ const carts = res.carts as unknown as HttpTypes.StoreCart[]
967
+ const filteredCarts = carts.filter((c) => c.id !== currentCartId)
968
+ const meta = (c: HttpTypes.StoreCart) =>
969
+ c.metadata as Record<string, unknown> | null | undefined
970
+
971
+ buyNowCarts = filteredCarts.filter((c) => meta(c)?.is_buy_now === true)
972
+ reorderCarts = filteredCarts.filter((c) => meta(c)?.is_reorder === true)
1021
973
  }
1022
974
 
1023
975
  return { buyNowCarts, reorderCarts }
@@ -1036,14 +988,9 @@ export async function resumeAbandonedCart(cartId: string, countryCode: string) {
1036
988
  }
1037
989
 
1038
990
  export async function deleteCart(cartId: string) {
1039
- const headers = await getAuthHeaders()
1040
-
1041
991
  try {
1042
- await sdk.client.fetch(`/store/carts/${cartId}`, {
1043
- method: "DELETE",
1044
- headers,
1045
- cache: "no-store",
1046
- })
992
+ const options = await getStoreCartClientOptions()
993
+ await medusaCartDelete(cartId, options)
1047
994
 
1048
995
  revalidateTag("carts")
1049
996
  return { success: true }