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,6 +1,5 @@
1
1
  "use server"
2
2
 
3
- import { sdk } from "../config"
4
3
  import medusaError from "../util/medusa-error"
5
4
  import { HttpTypes } from "@medusajs/types"
6
5
  import { revalidateTag } from "next/cache"
@@ -8,7 +7,6 @@ import { redirect } from "next/navigation"
8
7
  import { cookies } from "next/headers"
9
8
  import {
10
9
  getAuthHeaders,
11
- getCacheOptions,
12
10
  getCacheTag,
13
11
  getCartId,
14
12
  removeAuthToken,
@@ -17,35 +15,48 @@ import {
17
15
  setAuthToken,
18
16
  setCartId,
19
17
  } from "../cookies"
18
+ import {
19
+ medusaAuthLogin,
20
+ medusaAuthLogout,
21
+ medusaAuthRegister,
22
+ } from "medusa-services/auth"
23
+ import {
24
+ isAccountDeletionPendingError,
25
+ medusaCustomerCreate,
26
+ medusaCustomerCreateAddress,
27
+ medusaCustomerDeleteAddress,
28
+ medusaCustomerRetrieve,
29
+ medusaCustomerUpdate,
30
+ medusaCustomerUpdateAddress,
31
+ } from "medusa-services/customer"
32
+ import { medusaCartMerge, medusaCartTransfer } from "medusa-services/cart"
33
+ import {
34
+ getAuthClientOptions,
35
+ getMedusaBackendUrl,
36
+ getStoreCartClientOptions,
37
+ } from "../util/store-client"
20
38
 
21
39
  import { cache } from "react"
22
40
 
41
+ function throwCustomerError(error: unknown): never {
42
+ if (error && typeof error === "object" && "response" in error) {
43
+ medusaError(error)
44
+ }
45
+ throw error instanceof Error ? error : new Error(String(error))
46
+ }
47
+
23
48
  export const retrieveCustomer = cache(
24
49
  async (): Promise<HttpTypes.StoreCustomer | null> => {
25
50
  const authHeaders = await getAuthHeaders()
26
51
 
27
- if (!authHeaders) return null
28
-
29
- const headers = {
30
- ...authHeaders,
31
- }
52
+ if (!("authorization" in authHeaders)) return null
32
53
 
33
54
  try {
34
- const { customer } = await sdk.client.fetch<{ customer: HttpTypes.StoreCustomer }>(
35
- `/store/customers/me`,
36
- {
37
- method: "GET",
38
- query: { fields: "*addresses" },
39
- headers: headers as Record<string, string>,
40
- cache: "no-store",
41
- }
42
- )
43
- return customer
44
- } catch (error: any) {
45
- const errStr = error.toString().toLowerCase()
46
- // If the error indicates a pending deletion, return a special object
47
- if (errStr.includes("active account deletion request") ||
48
- (error.message && error.message.toLowerCase().includes("active account deletion request"))) {
55
+ const options = await getStoreCartClientOptions()
56
+ const { customer } = await medusaCustomerRetrieve(options, { fields: "*addresses" })
57
+ return customer as unknown as HttpTypes.StoreCustomer
58
+ } catch (error: unknown) {
59
+ if (isAccountDeletionPendingError(error)) {
49
60
  const cookieStore = await cookies()
50
61
  const cookieEmail = cookieStore.get("_medusa_customer_email")?.value
51
62
  return { id: "pending_deletion", email: cookieEmail || "pending" } as any
@@ -56,19 +67,17 @@ export const retrieveCustomer = cache(
56
67
  )
57
68
 
58
69
  export const updateCustomer = async (body: HttpTypes.StoreUpdateCustomer) => {
59
- const headers = {
60
- ...(await getAuthHeaders()),
61
- }
62
-
63
- const updateRes = await sdk.store.customer
64
- .update(body, {}, headers)
65
- .then(({ customer }) => customer)
66
- .catch(medusaError)
70
+ try {
71
+ const options = await getStoreCartClientOptions()
72
+ const { customer } = await medusaCustomerUpdate(body as Record<string, unknown>, options)
67
73
 
68
- const cacheTag = await getCacheTag("customers")
69
- revalidateTag(cacheTag)
74
+ const cacheTag = await getCacheTag("customers")
75
+ revalidateTag(cacheTag)
70
76
 
71
- return updateRes
77
+ return customer as unknown as HttpTypes.StoreCustomer
78
+ } catch (e) {
79
+ throwCustomerError(e)
80
+ }
72
81
  }
73
82
 
74
83
  export async function signup(_currentState: unknown, formData: FormData) {
@@ -81,34 +90,28 @@ export async function signup(_currentState: unknown, formData: FormData) {
81
90
  }
82
91
 
83
92
  try {
84
- const token = await sdk.auth.register("customer", "emailpass", {
85
- email: customerForm.email,
86
- password: password,
87
- })
93
+ const authOptions = await getAuthClientOptions()
94
+ const token = await medusaAuthRegister(
95
+ { email: customerForm.email, password },
96
+ authOptions
97
+ )
88
98
 
89
- await setAuthToken(token as string)
99
+ await setAuthToken(token)
90
100
 
91
- const headers = {
92
- ...(await getAuthHeaders()),
93
- }
101
+ const options = await getStoreCartClientOptions()
102
+ const { customer: createdCustomer } = await medusaCustomerCreate(customerForm, options)
94
103
 
95
- const { customer: createdCustomer } = await sdk.store.customer.create(
96
- customerForm,
97
- {},
98
- headers
104
+ const loginToken = await medusaAuthLogin(
105
+ { email: customerForm.email, password },
106
+ authOptions
99
107
  )
100
108
 
101
- const loginToken = await sdk.auth.login("customer", "emailpass", {
102
- email: customerForm.email,
103
- password,
104
- })
105
-
106
- await setAuthToken(loginToken as string)
109
+ await setAuthToken(loginToken)
107
110
 
108
111
  const customerCacheTag = await getCacheTag("customers")
109
112
  revalidateTag(customerCacheTag)
110
113
 
111
- await transferCart(loginToken as string)
114
+ await transferCart(loginToken)
112
115
 
113
116
  return createdCustomer
114
117
  } catch (error: any) {
@@ -120,8 +123,6 @@ export async function login(_currentState: unknown, formData: FormData) {
120
123
  let email = formData.get("email_or_phone") as string
121
124
  const password = formData.get("password") as string
122
125
 
123
- // Sanitize phone number: remove spaces, dashes, etc if it looks like a phone number
124
- // If it doesn't have '@', we treat it as a potential phone number and clean it
125
126
  if (email && !email.includes("@")) {
126
127
  email = email.replace(/[^\d+]/g, "")
127
128
  }
@@ -130,30 +131,28 @@ export async function login(_currentState: unknown, formData: FormData) {
130
131
  let countryCode = "in"
131
132
 
132
133
  try {
133
- const token = await sdk.auth.login("customer", "emailpass", { email_or_phone: email, password })
134
- await setAuthToken(token as string)
134
+ const authOptions = await getAuthClientOptions()
135
+ const token = await medusaAuthLogin({ email_or_phone: email, password }, authOptions)
136
+ await setAuthToken(token)
135
137
 
136
- // Store email in cookie for deletion flow (needed for cancellation modal)
137
138
  const cookieStore = await cookies()
138
139
  cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
139
140
 
140
- // Force a check to see if we are blocked
141
141
  try {
142
- await sdk.store.customer.retrieve({}, {
143
- authorization: `Bearer ${token}`
142
+ const options = await getStoreCartClientOptions()
143
+ await medusaCustomerRetrieve({
144
+ ...options,
145
+ authorization: `Bearer ${token}`,
144
146
  })
145
- } catch (err: any) {
146
- const errStr = err.toString().toLowerCase()
147
- if (errStr.includes("active account deletion request")) {
147
+ } catch (err: unknown) {
148
+ if (isAccountDeletionPendingError(err)) {
148
149
  return "ACCOUNT_DELETION_PENDING"
149
150
  }
150
- // If it's another error, we might still want to know, but deletion is our priority
151
151
  throw err
152
152
  }
153
153
 
154
- // Transfer cart after login success - Moved here to ensure execution
155
154
  try {
156
- await transferCart(token as string)
155
+ await transferCart(token)
157
156
  } catch (e) {
158
157
  console.error("Transfer cart failed in login:", e)
159
158
  }
@@ -161,43 +160,42 @@ export async function login(_currentState: unknown, formData: FormData) {
161
160
  const customerCacheTag = await getCacheTag("customers")
162
161
  revalidateTag(customerCacheTag)
163
162
 
164
- countryCode = formData.get("country_code") as string || "in"
163
+ countryCode = (formData.get("country_code") as string) || "in"
165
164
  shouldRedirect = true
166
- } catch (error: any) {
167
- const errorStr = error.toString().toLowerCase()
168
-
169
- if (errorStr.includes("active account deletion request") ||
170
- (error.message && error.message.toLowerCase().includes("active account deletion request"))) {
171
- // Still set email cookie even if blocked
165
+ } catch (error: unknown) {
166
+ if (isAccountDeletionPendingError(error)) {
172
167
  const cookieStore = await cookies()
173
168
  cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
174
169
  return "ACCOUNT_DELETION_PENDING"
175
170
  }
176
171
 
172
+ const errorStr = String(error).toLowerCase()
177
173
  if (errorStr.includes("invalid") || errorStr.includes("401") || errorStr.includes("not found")) {
178
174
  return "Invalid credentials. Please try again."
179
175
  }
180
- return error.message || error.toString()
176
+
177
+ return error instanceof Error ? error.message : String(error)
181
178
  }
182
179
 
183
180
  if (shouldRedirect) {
184
181
  const redirectUrl = formData.get("redirect_url") as string
185
-
186
- // Check if it's a "keep-me-here" context (Wishlist or Review Popups)
187
182
  const hasKeepContext = redirectUrl?.includes("login_context=keep")
188
183
 
189
- // Security + Context check
190
184
  if (redirectUrl && redirectUrl.startsWith("/") && hasKeepContext) {
191
185
  redirect(redirectUrl)
192
186
  } else {
193
- // DEFAULT: Always Home Page
194
187
  redirect(`/${countryCode}`)
195
188
  }
196
189
  }
197
190
  }
198
191
 
199
192
  export async function signout(countryCode: string) {
200
- await sdk.auth.logout()
193
+ try {
194
+ const authOptions = await getAuthClientOptions()
195
+ await medusaAuthLogout(authOptions)
196
+ } catch {
197
+ // Continue local cleanup even if remote logout fails
198
+ }
201
199
 
202
200
  await removeAuthToken()
203
201
  await removeCartId()
@@ -216,58 +214,38 @@ export async function signout(countryCode: string) {
216
214
 
217
215
  export async function transferCart(token?: string) {
218
216
  const cartId = await getCartId()
219
- const authHeaders = token
220
- ? { authorization: `Bearer ${token}` }
221
- : await getAuthHeaders()
217
+ const options = await getStoreCartClientOptions()
218
+ const mergeOptions = token
219
+ ? { ...options, authorization: `Bearer ${token}` }
220
+ : options
222
221
 
223
222
  console.log("--- TransferCart Debug ---")
224
223
  console.log("Token provided:", !!token)
225
224
  console.log("Guest Cart ID:", cartId)
226
225
 
227
- const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
228
- const backendUrl = process.env.MEDUSA_BACKEND_URL || process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL || "http://localhost:9000"
229
-
230
226
  try {
231
227
  console.log("Calling merge API (always)...")
232
-
233
- const response = await fetch(`${backendUrl}/store/carts/merge`, {
234
- method: "POST",
235
- headers: {
236
- "Content-Type": "application/json",
237
- "x-publishable-api-key": publishableKey || "",
238
- ...(authHeaders as any),
239
- },
240
- // Only include body if cartId exists
241
- ...(cartId ? { body: JSON.stringify({ cart_id: cartId }) } : {}),
242
- cache: "no-store",
243
- })
244
228
 
245
- if (response.ok) {
246
- const data = await response.json()
229
+ const data = await medusaCartMerge(mergeOptions, cartId ?? undefined)
230
+
231
+ if (data) {
247
232
  console.log("--- Login Merge Response (JSON) ---")
248
233
  console.log(JSON.stringify(data, null, 2))
249
234
  console.log("-----------------------------------")
250
-
235
+
251
236
  const activeCartId = data.cart?.id || data.id || data.cart_id
252
-
253
- if (activeCartId) {
237
+
238
+ if (activeCartId && typeof activeCartId === "string") {
254
239
  console.log("Storing Cart ID in cookie:", activeCartId)
255
240
  await setCartId(activeCartId)
256
241
  }
257
- } else if (response.status === 404) {
258
- // 404 is fine - it just means the customer has no active cart yet
259
- console.log("No active cart found for this customer (expected).")
260
242
  } else {
261
- const errorText = await response.text()
262
- console.log(`Merge API Info (${response.status}):`, errorText)
263
- if (cartId) {
264
- await sdk.store.cart.transferCart(cartId, {}, authHeaders).catch(() => { })
265
- }
243
+ console.log("No active cart found for this customer (expected).")
266
244
  }
267
- } catch (error: any) {
268
- console.error("Merge API error:", error.message)
245
+ } catch (error: unknown) {
246
+ console.error("Merge API error:", error instanceof Error ? error.message : error)
269
247
  if (cartId) {
270
- await sdk.store.cart.transferCart(cartId, {}, authHeaders).catch(() => { })
248
+ await medusaCartTransfer(cartId, mergeOptions).catch(() => {})
271
249
  }
272
250
  }
273
251
 
@@ -298,42 +276,34 @@ export const addCustomerAddress = async (
298
276
  is_default_shipping: isDefaultShipping,
299
277
  metadata: {
300
278
  address_type: (formData.get("address_type") as string) || "HOME",
301
- }
279
+ },
302
280
  }
303
281
 
304
- const headers = {
305
- ...(await getAuthHeaders()),
306
- }
282
+ try {
283
+ const options = await getStoreCartClientOptions()
284
+ await medusaCustomerCreateAddress(address, options)
307
285
 
308
- return sdk.store.customer
309
- .createAddress(address, {}, headers)
310
- .then(async ({ customer }) => {
311
- const customerCacheTag = await getCacheTag("customers")
312
- revalidateTag(customerCacheTag)
313
- return { success: true, error: null }
314
- })
315
- .catch((err) => {
316
- return { success: false, error: err.toString() }
317
- })
286
+ const customerCacheTag = await getCacheTag("customers")
287
+ revalidateTag(customerCacheTag)
288
+ return { success: true, error: null }
289
+ } catch (err) {
290
+ return { success: false, error: String(err) }
291
+ }
318
292
  }
319
293
 
320
294
  export const deleteCustomerAddress = async (
321
295
  addressId: string
322
296
  ): Promise<void> => {
323
- const headers = {
324
- ...(await getAuthHeaders()),
325
- }
297
+ try {
298
+ const options = await getStoreCartClientOptions()
299
+ await medusaCustomerDeleteAddress(addressId, options)
326
300
 
327
- await sdk.store.customer
328
- .deleteAddress(addressId, headers)
329
- .then(async () => {
330
- const customerCacheTag = await getCacheTag("customers")
331
- revalidateTag(customerCacheTag)
332
- return { success: true, error: null }
333
- })
334
- .catch((err) => {
335
- return { success: false, error: err.toString() }
336
- })
301
+ const customerCacheTag = await getCacheTag("customers")
302
+ revalidateTag(customerCacheTag)
303
+ return { success: true, error: null } as any
304
+ } catch (err) {
305
+ return { success: false, error: String(err) } as any
306
+ }
337
307
  }
338
308
 
339
309
  export const updateCustomerAddress = async (
@@ -359,7 +329,7 @@ export const updateCustomerAddress = async (
359
329
  country_code: formData.get("country_code") as string,
360
330
  metadata: {
361
331
  address_type: (formData.get("address_type") as string) || "HOME",
362
- }
332
+ },
363
333
  } as any
364
334
 
365
335
  const phone = formData.get("phone") as string
@@ -368,42 +338,34 @@ export const updateCustomerAddress = async (
368
338
  address.phone = phone
369
339
  }
370
340
 
371
- const headers = {
372
- ...(await getAuthHeaders()),
373
- }
341
+ try {
342
+ const options = await getStoreCartClientOptions()
343
+ await medusaCustomerUpdateAddress(addressId, address, options)
374
344
 
375
- return sdk.store.customer
376
- .updateAddress(addressId, address, {}, headers)
377
- .then(async () => {
378
- const customerCacheTag = await getCacheTag("customers")
379
- revalidateTag(customerCacheTag)
380
- return { success: true, error: null }
381
- })
382
- .catch((err) => {
383
- return { success: false, error: err.toString() }
384
- })
345
+ const customerCacheTag = await getCacheTag("customers")
346
+ revalidateTag(customerCacheTag)
347
+ return { success: true, error: null }
348
+ } catch (err) {
349
+ return { success: false, error: String(err) }
350
+ }
385
351
  }
386
352
 
387
353
  export const setDefaultAddress = async (addressId: string) => {
388
- const headers = {
389
- ...(await getAuthHeaders()),
390
- }
354
+ try {
355
+ const options = await getStoreCartClientOptions()
356
+ await medusaCustomerUpdateAddress(addressId, { is_default_shipping: true }, options)
391
357
 
392
- return sdk.store.customer
393
- .updateAddress(addressId, { is_default_shipping: true }, {}, headers)
394
- .then(async () => {
395
- const customerCacheTag = await getCacheTag("customers")
396
- revalidateTag(customerCacheTag)
397
- return { success: true, error: null }
398
- })
399
- .catch((err) => {
400
- return { success: false, error: err.toString() }
401
- })
358
+ const customerCacheTag = await getCacheTag("customers")
359
+ revalidateTag(customerCacheTag)
360
+ return { success: true, error: null }
361
+ } catch (err) {
362
+ return { success: false, error: String(err) }
363
+ }
402
364
  }
403
365
 
404
366
  export async function initiateGoogleAuth() {
405
367
  try {
406
- const backendUrl = process.env.MEDUSA_BACKEND_URL || process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL
368
+ const backendUrl = getMedusaBackendUrl()
407
369
 
408
370
  if (!backendUrl) {
409
371
  return { error: "Backend URL not configured" }
@@ -428,25 +390,19 @@ export async function initiateGoogleAuth() {
428
390
  return { error: "No redirect URL received from Google OAuth" }
429
391
  }
430
392
 
431
- // Fix redirect URL: Remove country code prefix from callback URL if present
432
- // Example: https://chocomelon.in/in/auth/customer/google/callback -> https://chocomelon.in/auth/customer/google/callback
433
393
  try {
434
394
  const url = new URL(redirectUrl)
435
- const pathParts = url.pathname.split('/').filter(Boolean)
395
+ const pathParts = url.pathname.split("/").filter(Boolean)
436
396
 
437
- // Check if path starts with country code pattern (2-3 letter code)
438
397
  if (pathParts.length > 0 && /^[a-z]{2,3}$/i.test(pathParts[0])) {
439
- // Check if next part is 'auth'
440
- if (pathParts.length > 1 && pathParts[1] === 'auth') {
441
- // Remove country code from path
398
+ if (pathParts.length > 1 && pathParts[1] === "auth") {
442
399
  pathParts.shift()
443
- url.pathname = '/' + pathParts.join('/')
400
+ url.pathname = "/" + pathParts.join("/")
444
401
  redirectUrl = url.toString()
445
402
  }
446
403
  }
447
404
  } catch (e) {
448
405
  // If URL parsing fails, use original redirectUrl
449
-
450
406
  }
451
407
 
452
408
  return { redirectUrl }
@@ -461,7 +417,7 @@ export async function handleGoogleAuthCallback(params: Record<string, string>) {
461
417
  return { error: "Missing authentication parameters" }
462
418
  }
463
419
 
464
- const backendUrl = process.env.MEDUSA_BACKEND_URL || process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL
420
+ const backendUrl = getMedusaBackendUrl()
465
421
 
466
422
  if (!backendUrl) {
467
423
  return { error: "Backend URL not configured" }
@@ -502,23 +458,22 @@ export async function handleGoogleCallback(token: string, email?: string, first_
502
458
  }
503
459
 
504
460
  await setAuthToken(token)
505
- await transferCart(token).catch(() => { })
461
+ await transferCart(token).catch(() => {})
506
462
 
507
463
  if (email && typeof email === "string") {
508
464
  const cookieStore = await cookies()
509
465
  cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
510
466
 
511
- const headers = await getAuthHeaders()
512
- if (headers && "authorization" in headers) {
467
+ const options = await getStoreCartClientOptions()
468
+ if (options.authorization) {
513
469
  try {
514
- await sdk.store.customer.create(
470
+ await medusaCustomerCreate(
515
471
  { email, ...(first_name && { first_name }), ...(last_name && { last_name }) },
516
- {},
517
- headers
472
+ options
518
473
  )
519
474
  } catch (err: any) {
520
475
  if (!err.message?.includes("already exists") && !err.message?.includes("duplicate")) {
521
-
476
+ // Ignore duplicate customer errors for OAuth sign-in
522
477
  }
523
478
  }
524
479
  }
@@ -541,7 +496,6 @@ export async function uploadProfileImage(formData: FormData) {
541
496
  return { error: "No image file provided" }
542
497
  }
543
498
 
544
- // Create new FormData with 'files' field as expected by the backend
545
499
  const uploadFormData = new FormData()
546
500
  uploadFormData.append("files", imageFile)
547
501
 
@@ -557,7 +511,6 @@ export async function uploadProfileImage(formData: FormData) {
557
511
  throw new Error("No image URL returned from server")
558
512
  }
559
513
 
560
- // Fetch current customer to preserve existing metadata
561
514
  const currentCustomer = await retrieveCustomer()
562
515
  const existingMetadata = (currentCustomer?.metadata as Record<string, any>) || {}
563
516
  const newMetadata = {
@@ -565,7 +518,6 @@ export async function uploadProfileImage(formData: FormData) {
565
518
  profile_image_url: imageUrl,
566
519
  }
567
520
 
568
- // Update customer metadata
569
521
  await updateCustomer({ metadata: newMetadata })
570
522
 
571
523
  const customerCacheTag = await getCacheTag("customers")
@@ -575,7 +527,6 @@ export async function uploadProfileImage(formData: FormData) {
575
527
 
576
528
  return { success: true, imageUrl }
577
529
  } catch (error: any) {
578
-
579
530
  return { error: error.message || "Failed to upload image" }
580
531
  }
581
532
  }
@@ -260,7 +260,7 @@ export const getFeaturesFromConfig = async (): Promise<{ title: string; features
260
260
 
261
261
  if (!homepageConfig) return null
262
262
 
263
- const title = homepageConfig["why-choose-us-title"] || "Why Choose Chocomelon?"
263
+ const title = homepageConfig["why-choose-us-title"] || "Why Choose Us?"
264
264
  const featuresRaw = homepageConfig["why-choose-us-features"] || []
265
265
 
266
266
  const features = featuresRaw.map((item: any) => {
@@ -293,7 +293,11 @@ export const getContactInfoFromConfig = async (): Promise<{ phone?: string; emai
293
293
 
294
294
  return {
295
295
  phone: contactConfig["contact-phone"],
296
- email: contactConfig["contact-email"],
296
+ email:
297
+ typeof contactConfig["contact-email"] === "string" &&
298
+ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contactConfig["contact-email"].trim())
299
+ ? contactConfig["contact-email"].trim()
300
+ : undefined,
297
301
  address: contactConfig["contact-address"],
298
302
  }
299
303
  } catch (error) {