medusa-storefront-data 1.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 (105) hide show
  1. package/dist/config.d.ts +3 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +31 -0
  4. package/dist/cookies.d.ts +23 -0
  5. package/dist/cookies.d.ts.map +1 -0
  6. package/dist/cookies.js +140 -0
  7. package/dist/server/cart.d.ts +92 -0
  8. package/dist/server/cart.d.ts.map +1 -0
  9. package/dist/server/cart.js +827 -0
  10. package/dist/server/categories.d.ts +3 -0
  11. package/dist/server/categories.d.ts.map +1 -0
  12. package/dist/server/categories.js +71 -0
  13. package/dist/server/collections.d.ts +8 -0
  14. package/dist/server/collections.d.ts.map +1 -0
  15. package/dist/server/collections.js +84 -0
  16. package/dist/server/customer-registration.d.ts +142 -0
  17. package/dist/server/customer-registration.d.ts.map +1 -0
  18. package/dist/server/customer-registration.js +295 -0
  19. package/dist/server/customer.d.ts +48 -0
  20. package/dist/server/customer.d.ts.map +1 -0
  21. package/dist/server/customer.js +462 -0
  22. package/dist/server/dynamic-config.d.ts +125 -0
  23. package/dist/server/dynamic-config.d.ts.map +1 -0
  24. package/dist/server/dynamic-config.js +263 -0
  25. package/dist/server/fulfillment.d.ts +4 -0
  26. package/dist/server/fulfillment.d.ts.map +1 -0
  27. package/dist/server/fulfillment.js +72 -0
  28. package/dist/server/guest.d.ts +109 -0
  29. package/dist/server/guest.d.ts.map +1 -0
  30. package/dist/server/guest.js +304 -0
  31. package/dist/server/index.d.ts +21 -0
  32. package/dist/server/index.d.ts.map +1 -0
  33. package/dist/server/index.js +20 -0
  34. package/dist/server/locale-actions.d.ts +14 -0
  35. package/dist/server/locale-actions.d.ts.map +1 -0
  36. package/dist/server/locale-actions.js +63 -0
  37. package/dist/server/locales.d.ts +10 -0
  38. package/dist/server/locales.d.ts.map +1 -0
  39. package/dist/server/locales.js +20 -0
  40. package/dist/server/notifications.d.ts +2 -0
  41. package/dist/server/notifications.d.ts.map +1 -0
  42. package/dist/server/notifications.js +20 -0
  43. package/dist/server/onboarding.d.ts +2 -0
  44. package/dist/server/onboarding.d.ts.map +1 -0
  45. package/dist/server/onboarding.js +8 -0
  46. package/dist/server/orders.d.ts +69 -0
  47. package/dist/server/orders.d.ts.map +1 -0
  48. package/dist/server/orders.js +371 -0
  49. package/dist/server/payment-details.d.ts +5 -0
  50. package/dist/server/payment-details.d.ts.map +1 -0
  51. package/dist/server/payment-details.js +53 -0
  52. package/dist/server/payment.d.ts +2 -0
  53. package/dist/server/payment.d.ts.map +1 -0
  54. package/dist/server/payment.js +25 -0
  55. package/dist/server/products.d.ts +58 -0
  56. package/dist/server/products.d.ts.map +1 -0
  57. package/dist/server/products.js +285 -0
  58. package/dist/server/regions.d.ts +5 -0
  59. package/dist/server/regions.d.ts.map +1 -0
  60. package/dist/server/regions.js +54 -0
  61. package/dist/server/returns.d.ts +29 -0
  62. package/dist/server/returns.d.ts.map +1 -0
  63. package/dist/server/returns.js +236 -0
  64. package/dist/server/swaps.d.ts +14 -0
  65. package/dist/server/swaps.d.ts.map +1 -0
  66. package/dist/server/swaps.js +123 -0
  67. package/dist/server/variants.d.ts +3 -0
  68. package/dist/server/variants.d.ts.map +1 -0
  69. package/dist/server/variants.js +26 -0
  70. package/dist/util/get-locale-header.d.ts +4 -0
  71. package/dist/util/get-locale-header.d.ts.map +1 -0
  72. package/dist/util/get-locale-header.js +7 -0
  73. package/dist/util/medusa-error.d.ts +2 -0
  74. package/dist/util/medusa-error.d.ts.map +1 -0
  75. package/dist/util/medusa-error.js +18 -0
  76. package/package.json +152 -0
  77. package/src/config.ts +39 -0
  78. package/src/cookies.ts +171 -0
  79. package/src/middleware.ts +2 -0
  80. package/src/server/cart.ts +1054 -0
  81. package/src/server/categories.ts +94 -0
  82. package/src/server/collections.ts +113 -0
  83. package/src/server/customer-registration.ts +349 -0
  84. package/src/server/customer.ts +581 -0
  85. package/src/server/dynamic-config.ts +403 -0
  86. package/src/server/fulfillment.ts +97 -0
  87. package/src/server/guest.ts +333 -0
  88. package/src/server/index.ts +21 -0
  89. package/src/server/locale-actions.ts +74 -0
  90. package/src/server/locales.ts +28 -0
  91. package/src/server/notifications.ts +22 -0
  92. package/src/server/onboarding.ts +9 -0
  93. package/src/server/orders.ts +467 -0
  94. package/src/server/payment-details.ts +69 -0
  95. package/src/server/payment.ts +35 -0
  96. package/src/server/products.ts +378 -0
  97. package/src/server/regions.ts +66 -0
  98. package/src/server/returns.ts +294 -0
  99. package/src/server/swaps.ts +150 -0
  100. package/src/server/variants.ts +38 -0
  101. package/src/server/wishlist.ts +64 -0
  102. package/src/services/middleware.ts +54 -0
  103. package/src/util/get-locale-header.ts +8 -0
  104. package/src/util/medusa-error.ts +19 -0
  105. package/src/util/sort-products.ts +47 -0
@@ -0,0 +1,285 @@
1
+ "use server";
2
+ import { sdk } from "../config";
3
+ import { getAuthHeaders, getCacheOptions } from "../cookies";
4
+ import { getRegion, retrieveRegion } from "./regions";
5
+ import Color from "color";
6
+ export const listProducts = async ({ pageParam = 1, queryParams, countryCode, regionId, }) => {
7
+ if (!countryCode && !regionId) {
8
+ throw new Error("Country code or region ID is required");
9
+ }
10
+ const limit = queryParams?.limit || 12;
11
+ const _pageParam = Math.max(pageParam, 1);
12
+ const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit;
13
+ let region;
14
+ if (countryCode) {
15
+ region = await getRegion(countryCode);
16
+ }
17
+ else {
18
+ region = await retrieveRegion(regionId);
19
+ }
20
+ if (!region) {
21
+ return {
22
+ response: { products: [], count: 0 },
23
+ nextPage: null,
24
+ };
25
+ }
26
+ const headers = {
27
+ ...(await getAuthHeaders()),
28
+ };
29
+ const next = {
30
+ ...(await getCacheOptions("products")),
31
+ };
32
+ // 1. Standard Medusa query parameters
33
+ const standardQuery = {
34
+ limit,
35
+ offset,
36
+ region_id: region?.id,
37
+ fields: "*variants.calculated_price,+variants.inventory_quantity,*variants.images,+variants.metadata,+variants.options,+metadata,+tags,+average_rating,+total_rating_count,+total_rating_sum,",
38
+ };
39
+ // 2. Identify advanced filters that require the product-helper API
40
+ const advancedFilterKeys = [
41
+ "metadata", "min_price", "max_price", "q", "collection_id", "category_id",
42
+ "tags", "option_value", "gender", "color", "material", "style", "brand",
43
+ "type", "product_type", "order"
44
+ ];
45
+ const hasAdvancedFilters = !!(queryParams && Object.keys(queryParams).some(key => advancedFilterKeys.includes(key) && queryParams[key] !== undefined));
46
+ const endpoint = hasAdvancedFilters ? "/store/product-helper/products" : "/store/products";
47
+ let finalQuery = { ...standardQuery };
48
+ if (hasAdvancedFilters) {
49
+ // We use URLSearchParams to ensure correct formatting and handle repeated keys if needed
50
+ const params = new URLSearchParams();
51
+ // 1. Add standard params
52
+ params.append("limit", limit.toString());
53
+ params.append("offset", offset.toString());
54
+ if (region?.id)
55
+ params.append("region_id", region.id);
56
+ // Use '*' for helper endpoint to let it resolve necessary relations
57
+ params.append("fields", "*");
58
+ // 2. Map queryParams
59
+ for (const [key, value] of Object.entries(queryParams || {})) {
60
+ if (["metadata", "min_price", "max_price", "limit", "offset", "region_id", "fields"].includes(key))
61
+ continue;
62
+ const values = Array.isArray(value) ? value : [value];
63
+ const lowerKey = key.toLowerCase();
64
+ if (lowerKey === "color") {
65
+ // Map 'color' filter to 'option_value' which backend understands for variants
66
+ values.forEach(v => params.append("option_value[]", String(v)));
67
+ }
68
+ else if (["material", "gender", "product_type", "type", "style", "brand"].includes(lowerKey)) {
69
+ // Map these to metadata as they are defined as metadata in your config
70
+ const metaKey = lowerKey === "type" ? "product_type" : lowerKey;
71
+ values.forEach(v => params.append(`metadata[${metaKey}]`, String(v)));
72
+ }
73
+ else {
74
+ // Standard mapping for others (tags, collection_id, etc.)
75
+ if (Array.isArray(value)) {
76
+ value.forEach(v => params.append(`${key}[]`, String(v)));
77
+ }
78
+ else if (value !== undefined && value !== null) {
79
+ params.append(key, String(value));
80
+ }
81
+ }
82
+ }
83
+ // 3. Map price filters (min_price -> price_min, max_price -> price_max)
84
+ if (queryParams.min_price)
85
+ params.append("price_min", String(queryParams.min_price));
86
+ if (queryParams.max_price)
87
+ params.append("price_max", String(queryParams.max_price));
88
+ // 4. Map metadata filters to metadata[key] format
89
+ if (queryParams.metadata) {
90
+ for (const [key, value] of Object.entries(queryParams.metadata)) {
91
+ const values = Array.isArray(value) ? value : [value];
92
+ values.forEach(v => {
93
+ if (key.toLowerCase() === "color") {
94
+ // Map color in metadata to option_value[]
95
+ params.append("option_value[]", String(v));
96
+ }
97
+ else {
98
+ // Standard metadata format: metadata[key]=value
99
+ params.append(`metadata[${key}]`, String(v));
100
+ }
101
+ });
102
+ }
103
+ }
104
+ finalQuery = params;
105
+ }
106
+ else {
107
+ // Standard endpoint - only merge known safe Medusa keys from queryParams
108
+ // to avoid "Unrecognized fields" errors
109
+ const safeKeys = ["order", "id", "handle", "status", "created_at", "updated_at", "type_id"];
110
+ for (const key of safeKeys) {
111
+ if (queryParams && queryParams[key]) {
112
+ finalQuery[key] = queryParams[key];
113
+ }
114
+ }
115
+ }
116
+ // Use the appended query string to avoid SDK's default serialization issues with brackets
117
+ const requestUrl = hasAdvancedFilters ? `${endpoint}?${finalQuery.toString()}` : endpoint;
118
+ return sdk.client
119
+ .fetch(requestUrl, {
120
+ method: "GET",
121
+ query: hasAdvancedFilters ? undefined : finalQuery,
122
+ headers,
123
+ next: {
124
+ ...next,
125
+ revalidate: 0, // Disable Next.js cache for now to show logs
126
+ },
127
+ cache: "no-store", // Ensure it hits backend every time for testing
128
+ })
129
+ .then(({ products, count }) => {
130
+ const nextPage = count > offset + limit ? _pageParam + 1 : null;
131
+ if (products && products.length > 0) {
132
+ }
133
+ return {
134
+ response: {
135
+ products: products || [],
136
+ count: count || 0,
137
+ },
138
+ nextPage: nextPage,
139
+ queryParams,
140
+ };
141
+ })
142
+ .catch((error) => {
143
+ throw error;
144
+ });
145
+ };
146
+ /**
147
+ * This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
148
+ * It will then return the paginated products based on the page and limit parameters.
149
+ */
150
+ export const listProductsWithSort = async ({ page = 1, queryParams, sortBy = "created_at_desc", countryCode, }) => {
151
+ const limit = queryParams?.limit || 12;
152
+ // Directly fetch from backend with correct pagination
153
+ // This ensures the backend terminal logs the specific request
154
+ const { response: { products, count }, } = await listProducts({
155
+ pageParam: page,
156
+ queryParams: {
157
+ ...queryParams,
158
+ limit,
159
+ },
160
+ countryCode,
161
+ });
162
+ // Sorting is now handled natively by the backend API via the 'order' query param.
163
+ const finalProducts = products;
164
+ const nextPage = count > page * limit ? page + 1 : null;
165
+ return {
166
+ response: {
167
+ products: finalProducts,
168
+ count,
169
+ },
170
+ nextPage,
171
+ queryParams,
172
+ };
173
+ };
174
+ /**
175
+ * Fetch products that have a specific tag value
176
+ */
177
+ export async function getProductsByTag({ tagValue, limit = 12, countryCode, }) {
178
+ try {
179
+ const result = await listProducts({
180
+ queryParams: { tags: [tagValue], limit },
181
+ countryCode,
182
+ });
183
+ return result.response.products;
184
+ }
185
+ catch (error) {
186
+ console.error("Error fetching products by tag:", error);
187
+ return [];
188
+ }
189
+ }
190
+ /**
191
+ * Fetch dynamic filter options from the backend API
192
+ */
193
+ export const getDynamicFilters = async (countryCode) => {
194
+ const backendUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000";
195
+ const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY;
196
+ try {
197
+ if (!publishableKey)
198
+ return { genders: [], productTypes: [], materials: [], colors: [] };
199
+ const response = await fetch(`${backendUrl}/store/product-helper/filters`, {
200
+ method: "GET",
201
+ headers: {
202
+ "Content-Type": "application/json",
203
+ "x-publishable-api-key": publishableKey,
204
+ },
205
+ cache: "no-store",
206
+ });
207
+ if (!response.ok) {
208
+ return { genders: [], productTypes: [], materials: [], colors: [] };
209
+ }
210
+ const data = await response.json();
211
+ const formatLabel = (str) => {
212
+ return str
213
+ .split(/[_-]/)
214
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
215
+ .join(' ');
216
+ };
217
+ const metadata = data.metadata || {};
218
+ const variantOptions = data.variant_options || [];
219
+ // Gather all unique colors from all possible sources
220
+ const colorSet = new Set();
221
+ // 1. From variant options (check all options with title 'color')
222
+ variantOptions.forEach((o) => {
223
+ if (o.option_title.toLowerCase() === 'color' || o.option_title.toLowerCase() === 'colour') {
224
+ o.values?.forEach((v) => {
225
+ if (v)
226
+ colorSet.add(v.trim().toLowerCase());
227
+ });
228
+ }
229
+ });
230
+ // 2. From metadata colors (handle newline/comma separated values)
231
+ if (metadata.color) {
232
+ metadata.color.forEach((c) => {
233
+ if (c) {
234
+ const parts = c.split(/[,/\n\r]+/).map(s => s.trim()).filter(Boolean);
235
+ parts.forEach(p => colorSet.add(p.toLowerCase()));
236
+ }
237
+ });
238
+ }
239
+ return {
240
+ genders: (metadata.gender || []).sort().map((g) => ({
241
+ value: g,
242
+ label: formatLabel(g)
243
+ })),
244
+ productTypes: (data.product_types || []).sort((a, b) => a.label.localeCompare(b.label)).map((t) => ({
245
+ value: t.label,
246
+ label: formatLabel(t.label)
247
+ })),
248
+ materials: (metadata.material || []).sort().map((m) => ({
249
+ value: m,
250
+ label: formatLabel(m)
251
+ })),
252
+ colors: Array.from(colorSet).sort().map((c) => {
253
+ let hex = "";
254
+ try {
255
+ // Try to resolve color hex code using the Color library
256
+ hex = Color(c.replace(/\s+/g, '').toLowerCase()).hex();
257
+ }
258
+ catch (e) {
259
+ try {
260
+ hex = Color(c.toLowerCase()).hex();
261
+ }
262
+ catch (e2) {
263
+ // No hex found
264
+ }
265
+ }
266
+ return {
267
+ value: c,
268
+ label: formatLabel(c),
269
+ hex
270
+ };
271
+ })
272
+ };
273
+ }
274
+ catch (error) {
275
+ console.error("Error fetching dynamic filters:", error);
276
+ return { genders: [], productTypes: [], materials: [], colors: [] };
277
+ }
278
+ };
279
+ /**
280
+ * Fetch a single product by its handle
281
+ */
282
+ export async function getProductByHandle(handle) {
283
+ const result = await sdk.store.product.list({ handle, fields: "*variants.calculated_price,+variants.inventory_quantity,+variants.manage_inventory,+variants.allow_backorder,*variants.options,*options,*options.values,*images,*thumbnail,+metadata" }, { next: { tags: ["products"] } });
284
+ return result.products[0];
285
+ }
@@ -0,0 +1,5 @@
1
+ import { HttpTypes } from "@medusajs/types";
2
+ export declare const listRegions: () => Promise<HttpTypes.StoreRegion[]>;
3
+ export declare const retrieveRegion: (id: string) => Promise<HttpTypes.StoreRegion>;
4
+ export declare const getRegion: (countryCode: string) => Promise<HttpTypes.StoreRegion>;
5
+ //# sourceMappingURL=regions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.d.ts","sourceRoot":"","sources":["../../src/server/regions.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAG3C,eAAO,MAAM,WAAW,wCAavB,CAAA;AAED,eAAO,MAAM,cAAc,GAAU,IAAI,MAAM,mCAa9C,CAAA;AAID,eAAO,MAAM,SAAS,GAAU,aAAa,MAAM,mCA0BlD,CAAA"}
@@ -0,0 +1,54 @@
1
+ "use server";
2
+ import { sdk } from "../config";
3
+ import medusaError from "../util/medusa-error";
4
+ import { getCacheOptions } from "../cookies";
5
+ export const listRegions = async () => {
6
+ const next = {
7
+ ...(await getCacheOptions("regions")),
8
+ };
9
+ return sdk.client
10
+ .fetch(`/store/regions`, {
11
+ method: "GET",
12
+ next,
13
+ cache: "force-cache",
14
+ })
15
+ .then(({ regions }) => regions)
16
+ .catch(medusaError);
17
+ };
18
+ export const retrieveRegion = async (id) => {
19
+ const next = {
20
+ ...(await getCacheOptions(["regions", id].join("-"))),
21
+ };
22
+ return sdk.client
23
+ .fetch(`/store/regions/${id}`, {
24
+ method: "GET",
25
+ next,
26
+ cache: "force-cache",
27
+ })
28
+ .then(({ region }) => region)
29
+ .catch(medusaError);
30
+ };
31
+ const regionMap = new Map();
32
+ export const getRegion = async (countryCode) => {
33
+ try {
34
+ if (regionMap.has(countryCode)) {
35
+ return regionMap.get(countryCode);
36
+ }
37
+ const regions = await listRegions();
38
+ if (!regions) {
39
+ return null;
40
+ }
41
+ regions.forEach((region) => {
42
+ region.countries?.forEach((c) => {
43
+ regionMap.set(c?.iso_2 ?? "", region);
44
+ });
45
+ });
46
+ const region = countryCode
47
+ ? regionMap.get(countryCode)
48
+ : regionMap.get("us");
49
+ return region;
50
+ }
51
+ catch (e) {
52
+ return null;
53
+ }
54
+ };
@@ -0,0 +1,29 @@
1
+ import { HttpTypes } from "@medusajs/types";
2
+ export declare const listReturnReasons: () => Promise<any[] | HttpTypes.StoreReturnReason[]>;
3
+ export declare const listReturnShippingOptions: (cartId: string, regionId?: string, productIds?: string[]) => Promise<HttpTypes.StoreShippingOption[]>;
4
+ export declare const createReturnRequest: (state: {
5
+ success: boolean;
6
+ error: string | null;
7
+ return: HttpTypes.StoreReturn | null;
8
+ }, formData: FormData) => Promise<{
9
+ success: boolean;
10
+ error: string | null;
11
+ return: HttpTypes.StoreReturn | null;
12
+ }>;
13
+ /**
14
+ * Link a payment method to a return (for Refund Destination)
15
+ */
16
+ export declare const updateReturnPayment: (returnId: string, paymentId: string) => Promise<{
17
+ success: boolean;
18
+ data: any;
19
+ error?: undefined;
20
+ } | {
21
+ success: boolean;
22
+ error: any;
23
+ data?: undefined;
24
+ }>;
25
+ /**
26
+ * List returns for an order or customer
27
+ */
28
+ export declare const listReturns: (orderId?: string) => Promise<any>;
29
+ //# sourceMappingURL=returns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"returns.d.ts","sourceRoot":"","sources":["../../src/server/returns.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAK3C,eAAO,MAAM,iBAAiB,sDAkB7B,CAAA;AAED,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,EACd,WAAW,MAAM,EACjB,aAAa,MAAM,EAAE,KACpB,OAAO,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAmEzC,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,OAAO;IACL,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAA;CACrC,EACD,UAAU,QAAQ,KACjB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAA;CACrC,CA2GA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAU,UAAU,MAAM,EAAE,WAAW,MAAM;;;;;;;;EAoB5E,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,iBA4CjD,CAAA"}
@@ -0,0 +1,236 @@
1
+ "use server";
2
+ import { sdk } from "../config";
3
+ import { cookies } from "next/headers";
4
+ import { getAuthHeaders, getCacheOptions } from "../cookies";
5
+ import { revalidateTag } from "next/cache";
6
+ export const listReturnReasons = async () => {
7
+ const headers = {
8
+ ...(await getAuthHeaders()),
9
+ };
10
+ const next = {
11
+ ...(await getCacheOptions("return_reasons")),
12
+ };
13
+ return sdk.client
14
+ .fetch(`/store/return-reasons`, {
15
+ method: "GET",
16
+ headers,
17
+ next,
18
+ cache: "force-cache", // Reasons change rarely
19
+ })
20
+ .then(({ return_reasons }) => return_reasons)
21
+ .catch(() => []);
22
+ };
23
+ export const listReturnShippingOptions = async (cartId, regionId, productIds) => {
24
+ const headers = {
25
+ ...(await getAuthHeaders()),
26
+ };
27
+ const next = {
28
+ ...(await getCacheOptions("fulfillment")),
29
+ };
30
+ // Strategy 1: Try with cart_id (preferred as it has context)
31
+ if (cartId) {
32
+ try {
33
+ const { shipping_options } = await sdk.client.fetch(`/store/shipping-options`, {
34
+ method: "GET",
35
+ query: {
36
+ cart_id: cartId,
37
+ is_return: true,
38
+ },
39
+ headers,
40
+ next,
41
+ cache: "no-store",
42
+ });
43
+ if (shipping_options.length > 0) {
44
+ return shipping_options;
45
+ }
46
+ }
47
+ catch (e) {
48
+ // Fallback strategy
49
+ }
50
+ }
51
+ // Strategy 2: Fallback - Create ephemeral cart if region_id is available
52
+ // This is required because /store/shipping-options STRICTLY requires a cart_id for return options
53
+ if (regionId) {
54
+ try {
55
+ // Create a temporary cart for this region to get valid shipping options
56
+ const { cart } = await sdk.store.cart.create({ region_id: regionId }, {}, headers);
57
+ if (cart?.id) {
58
+ const { shipping_options } = await sdk.client.fetch(`/store/shipping-options`, {
59
+ method: "GET",
60
+ query: {
61
+ cart_id: cart.id,
62
+ is_return: true,
63
+ },
64
+ headers,
65
+ next,
66
+ cache: "no-store",
67
+ });
68
+ return shipping_options;
69
+ }
70
+ }
71
+ catch (e) {
72
+ // Silence error
73
+ }
74
+ }
75
+ return [];
76
+ };
77
+ export const createReturnRequest = async (state, formData) => {
78
+ const orderId = formData.get("order_id");
79
+ const returnShippingOptionId = formData.get("return_shipping_option_id");
80
+ const itemsJson = formData.get("items");
81
+ const note = formData.get("note");
82
+ const locationId = formData.get("location_id");
83
+ if (!orderId)
84
+ return { success: false, error: "Order ID is required", return: null };
85
+ if (!itemsJson)
86
+ return { success: false, error: "Items are required", return: null };
87
+ let items = [];
88
+ try {
89
+ items = JSON.parse(itemsJson);
90
+ }
91
+ catch (e) {
92
+ return { success: false, error: "Invalid items data", return: null };
93
+ }
94
+ if (items.length === 0) {
95
+ return { success: false, error: "At least one item must be selected", return: null };
96
+ }
97
+ const headers = {
98
+ ...(await getAuthHeaders()),
99
+ };
100
+ try {
101
+ // Standard Medusa v2 payload
102
+ const payload = {
103
+ order_id: orderId,
104
+ items: items.map((item) => ({
105
+ id: item.id,
106
+ quantity: item.quantity,
107
+ reason_id: item.return_reason_id || undefined,
108
+ note: (note && note.trim().length > 0) ? note : undefined,
109
+ })),
110
+ ...(returnShippingOptionId ? {
111
+ return_shipping: {
112
+ option_id: returnShippingOptionId,
113
+ location_id: locationId || items[0].location_id || "default_location"
114
+ }
115
+ } : {}),
116
+ // Optional: keep global note if supported
117
+ note: (note && note.trim().length > 0) ? note : "Return request",
118
+ };
119
+ // Double check location_id is NOT nested incorrectly if already set above
120
+ // The plugin expects return_shipping.location_id
121
+ // Check for any available guest tokens
122
+ const cookieStore = await cookies();
123
+ const guestToken = cookieStore.get("_medusa_guest_jwt")?.value
124
+ || cookieStore.get("_medusa_guest_token")?.value
125
+ || cookieStore.get("guest_id")?.value;
126
+ const token = cookieStore.get("_medusa_jwt")?.value;
127
+ let returnData;
128
+ // If we have a guest token, try the guest specific endpoint
129
+ if (guestToken && !token) {
130
+ try {
131
+ const response = await sdk.client.fetch(`/store/guest-orders/${orderId}/returns`, {
132
+ method: "POST",
133
+ body: payload,
134
+ headers: {
135
+ ...headers,
136
+ "Authorization": `Bearer ${guestToken}`
137
+ },
138
+ cache: "no-store",
139
+ });
140
+ returnData = response.return || response;
141
+ }
142
+ catch (e) {
143
+ // Fallback to standard if guest endpoint fails
144
+ const response = await sdk.client.fetch(`/store/returns`, {
145
+ method: "POST",
146
+ body: payload,
147
+ headers,
148
+ cache: "no-store",
149
+ });
150
+ returnData = response.return;
151
+ }
152
+ }
153
+ else {
154
+ // Standard flow
155
+ const response = await sdk.client.fetch(`/store/returns`, {
156
+ method: "POST",
157
+ body: payload,
158
+ headers,
159
+ cache: "no-store",
160
+ });
161
+ returnData = response.return;
162
+ }
163
+ revalidateTag("orders");
164
+ return { success: true, error: null, return: returnData };
165
+ }
166
+ catch (error) {
167
+ return { success: false, error: error.message || "Failed to create return request", return: null };
168
+ }
169
+ };
170
+ /**
171
+ * Link a payment method to a return (for Refund Destination)
172
+ */
173
+ export const updateReturnPayment = async (returnId, paymentId) => {
174
+ const headers = {
175
+ ...(await getAuthHeaders()),
176
+ };
177
+ try {
178
+ const response = await sdk.client.fetch(`/store/refund-payment-mapping/${returnId}`, {
179
+ method: "PUT",
180
+ body: { payment_id: paymentId },
181
+ headers,
182
+ cache: "no-store",
183
+ });
184
+ return { success: true, data: response };
185
+ }
186
+ catch (error) {
187
+ console.error("Update return payment fail:", error);
188
+ return { success: false, error: error.message };
189
+ }
190
+ };
191
+ /**
192
+ * List returns for an order or customer
193
+ */
194
+ export const listReturns = async (orderId) => {
195
+ const headers = {
196
+ ...(await getAuthHeaders()),
197
+ };
198
+ // Authenticated flow
199
+ const authHeaders = headers;
200
+ if (authHeaders.authorization || authHeaders.Authorization) {
201
+ try {
202
+ const response = await sdk.client.fetch(`/store/returns`, {
203
+ method: "GET",
204
+ query: orderId ? { order_id: orderId } : {},
205
+ headers,
206
+ cache: "no-store",
207
+ });
208
+ return response;
209
+ }
210
+ catch (e) {
211
+ return { returns: [], count: 0 };
212
+ }
213
+ }
214
+ // Guest flow
215
+ if (orderId) {
216
+ const cookieStore = await cookies();
217
+ const guestToken = cookieStore.get("_medusa_guest_jwt")?.value || cookieStore.get("_medusa_guest_token")?.value;
218
+ if (guestToken) {
219
+ try {
220
+ const response = await sdk.client.fetch(`/store/guest-orders/${orderId}/returns`, {
221
+ method: "GET",
222
+ headers: {
223
+ ...headers,
224
+ "Authorization": `Bearer ${guestToken}`
225
+ },
226
+ cache: "no-store",
227
+ });
228
+ return response;
229
+ }
230
+ catch (e) {
231
+ return { returns: [], count: 0 };
232
+ }
233
+ }
234
+ }
235
+ return { returns: [], count: 0 };
236
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Create an exchange (swap) request.
3
+ * Supports both authenticated customers and guest users.
4
+ */
5
+ export declare const createSwapRequest: (prevState: any, formData: FormData) => Promise<{
6
+ success: boolean;
7
+ error: string | null;
8
+ swap: any | null;
9
+ }>;
10
+ /**
11
+ * List swaps for an order or customer
12
+ */
13
+ export declare const listSwaps: (orderId?: string) => Promise<any>;
14
+ //# sourceMappingURL=swaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swaps.d.ts","sourceRoot":"","sources":["../../src/server/swaps.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC1B,WAAW,GAAG,EACd,UAAU,QAAQ,KACnB,OAAO,CAAC;IACP,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,EAAE,GAAG,GAAG,IAAI,CAAA;CACnB,CA4FA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,GAAU,UAAU,MAAM,iBAgC/C,CAAA"}