medusa-services 1.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.
- package/dist/auth.d.ts +29 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +80 -0
- package/dist/cart.d.ts +148 -0
- package/dist/cart.d.ts.map +1 -0
- package/dist/cart.js +156 -0
- package/dist/categories.d.ts +20 -0
- package/dist/categories.d.ts.map +1 -0
- package/dist/categories.js +36 -0
- package/dist/collections.d.ts +27 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +36 -0
- package/dist/contact-action.d.ts +18 -0
- package/dist/contact-action.d.ts.map +1 -0
- package/dist/contact-action.js +42 -0
- package/dist/customer.d.ts +59 -0
- package/dist/customer.d.ts.map +1 -0
- package/dist/customer.js +68 -0
- package/dist/facebook-login.d.ts +37 -0
- package/dist/facebook-login.d.ts.map +1 -0
- package/dist/facebook-login.js +146 -0
- package/dist/fulfillment.d.ts +33 -0
- package/dist/fulfillment.d.ts.map +1 -0
- package/dist/fulfillment.js +43 -0
- package/dist/gift-wrap.d.ts +30 -0
- package/dist/gift-wrap.d.ts.map +1 -0
- package/dist/gift-wrap.js +29 -0
- package/dist/google-login.d.ts +37 -0
- package/dist/google-login.d.ts.map +1 -0
- package/dist/google-login.js +150 -0
- package/dist/guest.d.ts +46 -0
- package/dist/guest.d.ts.map +1 -0
- package/dist/guest.js +91 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/locales.d.ts +13 -0
- package/dist/locales.d.ts.map +1 -0
- package/dist/locales.js +13 -0
- package/dist/medusa-auth.d.ts +17 -0
- package/dist/medusa-auth.d.ts.map +1 -0
- package/dist/medusa-auth.js +25 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +36 -0
- package/dist/orders.d.ts +105 -0
- package/dist/orders.d.ts.map +1 -0
- package/dist/orders.js +139 -0
- package/dist/payment.d.ts +55 -0
- package/dist/payment.d.ts.map +1 -0
- package/dist/payment.js +68 -0
- package/dist/product-detail.d.ts +30 -0
- package/dist/product-detail.d.ts.map +1 -0
- package/dist/product-detail.js +94 -0
- package/dist/product-listing.d.ts +81 -0
- package/dist/product-listing.d.ts.map +1 -0
- package/dist/product-listing.js +189 -0
- package/dist/products.d.ts +41 -0
- package/dist/products.d.ts.map +1 -0
- package/dist/products.js +141 -0
- package/dist/recently-viewed.d.ts +14 -0
- package/dist/recently-viewed.d.ts.map +1 -0
- package/dist/recently-viewed.js +59 -0
- package/dist/regions.d.ts +37 -0
- package/dist/regions.d.ts.map +1 -0
- package/dist/regions.js +30 -0
- package/dist/related-products.d.ts +30 -0
- package/dist/related-products.d.ts.map +1 -0
- package/dist/related-products.js +99 -0
- package/dist/returns.d.ts +75 -0
- package/dist/returns.d.ts.map +1 -0
- package/dist/returns.js +105 -0
- package/dist/reviews.d.ts +135 -0
- package/dist/reviews.d.ts.map +1 -0
- package/dist/reviews.js +202 -0
- package/dist/store-api.d.ts +20 -0
- package/dist/store-api.d.ts.map +1 -0
- package/dist/store-api.js +55 -0
- package/dist/swaps.d.ts +33 -0
- package/dist/swaps.d.ts.map +1 -0
- package/dist/swaps.js +39 -0
- package/dist/variants.d.ts +17 -0
- package/dist/variants.d.ts.map +1 -0
- package/dist/variants.js +8 -0
- package/dist/wishlist.d.ts +65 -0
- package/dist/wishlist.d.ts.map +1 -0
- package/dist/wishlist.js +149 -0
- package/middleware.ts +54 -0
- package/package.json +174 -0
package/dist/payment.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { parseStoreErrorMessage, parseStoreJson, storeFetch, } from "./store-api";
|
|
2
|
+
/**
|
|
3
|
+
* GET /store/payment-providers?region_id=
|
|
4
|
+
*/
|
|
5
|
+
export async function medusaPaymentProvidersList(regionId, options) {
|
|
6
|
+
const params = new URLSearchParams();
|
|
7
|
+
params.set("region_id", regionId);
|
|
8
|
+
const response = await storeFetch(`/payment-providers?${params.toString()}`, options, {
|
|
9
|
+
method: "GET",
|
|
10
|
+
});
|
|
11
|
+
return parseStoreJson(response, "Payment providers request");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* POST /store/payment-collections then POST /store/payment-collections/:id/payment-sessions
|
|
15
|
+
* (Medusa v2 — cart-scoped /payment-sessions is not available)
|
|
16
|
+
*/
|
|
17
|
+
export async function medusaPaymentSessionInitiate(cartId, body, options) {
|
|
18
|
+
const collectionResponse = await storeFetch("/payment-collections", options, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
body: JSON.stringify({ cart_id: cartId }),
|
|
21
|
+
});
|
|
22
|
+
const collectionData = await parseStoreJson(collectionResponse, "Payment collection create request");
|
|
23
|
+
const paymentCollectionId = collectionData.payment_collection?.id;
|
|
24
|
+
if (!paymentCollectionId) {
|
|
25
|
+
throw new Error("Could not create payment collection for cart");
|
|
26
|
+
}
|
|
27
|
+
const response = await storeFetch(`/payment-collections/${encodeURIComponent(paymentCollectionId)}/payment-sessions`, options, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
provider_id: body.provider_id,
|
|
31
|
+
data: body.data,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
return parseStoreJson(response, "Payment session initiate request");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* GET /store/payment-details
|
|
38
|
+
*/
|
|
39
|
+
export async function medusaPaymentDetailsList(options) {
|
|
40
|
+
const response = await storeFetch("/payment-details", options, { method: "GET" });
|
|
41
|
+
return parseStoreJson(response, "Payment details list request");
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* POST /store/payment-details
|
|
45
|
+
*/
|
|
46
|
+
export async function medusaPaymentDetailCreate(type, detail_json, options) {
|
|
47
|
+
const response = await storeFetch("/payment-details", options, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
body: JSON.stringify({ type, detail_json }),
|
|
50
|
+
});
|
|
51
|
+
return parseStoreJson(response, "Payment detail create request");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* POST /store/payment-details/:id/make-default
|
|
55
|
+
*/
|
|
56
|
+
export async function medusaPaymentDetailMakeDefault(id, options) {
|
|
57
|
+
const response = await storeFetch(`/payment-details/${encodeURIComponent(id)}/make-default`, options, { method: "POST", body: JSON.stringify({}) });
|
|
58
|
+
return parseStoreJson(response, "Payment detail make-default request");
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* DELETE /store/payment-details/:id
|
|
62
|
+
*/
|
|
63
|
+
export async function medusaPaymentDetailDelete(id, options) {
|
|
64
|
+
const response = await storeFetch(`/payment-details/${encodeURIComponent(id)}`, options, { method: "DELETE" });
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(await parseStoreErrorMessage(response, "Payment detail delete request"));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HttpTypes } from "@medusajs/types";
|
|
2
|
+
/**
|
|
3
|
+
* Service to handle Product Detail API calls
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Fetch a single product by its ID or Handle
|
|
7
|
+
*
|
|
8
|
+
* @param sdk - The Medusa JS Client SDK instance
|
|
9
|
+
* @param identifier - The Product ID or Handle
|
|
10
|
+
* @param isHandle - Set to true if querying by handle instead of ID
|
|
11
|
+
* @param regionId - (Optional) Region ID to fetch regional pricing
|
|
12
|
+
* @param headers - (Optional) Custom headers
|
|
13
|
+
* @returns The fetched product data or null if not found
|
|
14
|
+
*/
|
|
15
|
+
export declare function getProduct({ sdk, identifier, isHandle, regionId, headers, next }: {
|
|
16
|
+
sdk: any;
|
|
17
|
+
identifier: string;
|
|
18
|
+
isHandle?: boolean;
|
|
19
|
+
regionId?: string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
next?: any;
|
|
22
|
+
}): Promise<HttpTypes.StoreProduct | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Format the raw Medusa product response to match the `ProductData` interface expected by `useProduct.ts`
|
|
25
|
+
*
|
|
26
|
+
* @param product - Raw StoreProduct from Medusa
|
|
27
|
+
* @returns Formatted product data compatible with useProduct hook
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatProductData(product: HttpTypes.StoreProduct): any;
|
|
30
|
+
//# sourceMappingURL=product-detail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-detail.d.ts","sourceRoot":"","sources":["../product-detail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C;;GAEG;AAEH;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,EAC7B,GAAG,EACH,UAAU,EACV,QAAgB,EAChB,QAAQ,EACR,OAAY,EACZ,IAAS,EACZ,EAAE;IACC,GAAG,EAAE,GAAG,CAAA;IACR,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb,GAAG,OAAO,CAAC,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,CA4BzC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,YAAY,GAAG,GAAG,CAmDtE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service to handle Product Detail API calls
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Fetch a single product by its ID or Handle
|
|
6
|
+
*
|
|
7
|
+
* @param sdk - The Medusa JS Client SDK instance
|
|
8
|
+
* @param identifier - The Product ID or Handle
|
|
9
|
+
* @param isHandle - Set to true if querying by handle instead of ID
|
|
10
|
+
* @param regionId - (Optional) Region ID to fetch regional pricing
|
|
11
|
+
* @param headers - (Optional) Custom headers
|
|
12
|
+
* @returns The fetched product data or null if not found
|
|
13
|
+
*/
|
|
14
|
+
export async function getProduct({ sdk, identifier, isHandle = false, regionId, headers = {}, next = {} }) {
|
|
15
|
+
try {
|
|
16
|
+
const queryParams = {
|
|
17
|
+
fields: "*variants,*variants.prices,*options,*variants.options,*tags,*categories,*images",
|
|
18
|
+
};
|
|
19
|
+
if (regionId) {
|
|
20
|
+
queryParams.region_id = regionId;
|
|
21
|
+
}
|
|
22
|
+
let response;
|
|
23
|
+
if (isHandle) {
|
|
24
|
+
// Fetch product by handle via product list endpoint
|
|
25
|
+
queryParams.handle = identifier;
|
|
26
|
+
const result = await sdk.store.product.list(queryParams, { next, headers });
|
|
27
|
+
response = result.products?.[0] || null;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Fetch product by ID
|
|
31
|
+
const result = await sdk.store.product.retrieve(identifier, queryParams, { next, headers });
|
|
32
|
+
response = result.product || null;
|
|
33
|
+
}
|
|
34
|
+
return response;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(`❌ Failed to fetch product (Identifier: ${identifier}):`, error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Format the raw Medusa product response to match the `ProductData` interface expected by `useProduct.ts`
|
|
43
|
+
*
|
|
44
|
+
* @param product - Raw StoreProduct from Medusa
|
|
45
|
+
* @returns Formatted product data compatible with useProduct hook
|
|
46
|
+
*/
|
|
47
|
+
export function formatProductData(product) {
|
|
48
|
+
if (!product)
|
|
49
|
+
return null;
|
|
50
|
+
// Map Options
|
|
51
|
+
const options = product.options?.map(opt => ({
|
|
52
|
+
name: opt.title,
|
|
53
|
+
values: opt.values?.map(v => v.value) || []
|
|
54
|
+
})) || [];
|
|
55
|
+
// Map Variants
|
|
56
|
+
const variants = product.variants?.map((variant) => {
|
|
57
|
+
// Build an option dictionary like { Size: 'M', Color: 'Red' }
|
|
58
|
+
const variantOptions = {};
|
|
59
|
+
variant.options?.forEach((vo) => {
|
|
60
|
+
const parentOption = product.options?.find(o => o.id === vo.option_id);
|
|
61
|
+
if (parentOption && parentOption.title) {
|
|
62
|
+
variantOptions[parentOption.title] = vo.value;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// Price Calculation (Take the first calculated price for simplicity, assuming region is already applied)
|
|
66
|
+
const calculatedPriceInfo = variant.calculated_price || variant.prices?.[0] || {};
|
|
67
|
+
const price = calculatedPriceInfo.calculated_amount || calculatedPriceInfo.amount || 0;
|
|
68
|
+
const originalPrice = calculatedPriceInfo.original_amount || price;
|
|
69
|
+
return {
|
|
70
|
+
id: variant.id,
|
|
71
|
+
title: variant.title,
|
|
72
|
+
options: variantOptions,
|
|
73
|
+
price: price,
|
|
74
|
+
originalPrice: originalPrice,
|
|
75
|
+
inventoryQuantity: variant.inventory_quantity || 0,
|
|
76
|
+
allowBackorder: variant.allow_backorder || false,
|
|
77
|
+
image: variant.thumbnail || null
|
|
78
|
+
};
|
|
79
|
+
}) || [];
|
|
80
|
+
return {
|
|
81
|
+
id: product.id,
|
|
82
|
+
title: product.title,
|
|
83
|
+
handle: product.handle || undefined,
|
|
84
|
+
description: product.description || '',
|
|
85
|
+
collectionId: product.collection_id || undefined,
|
|
86
|
+
brand: product.collection?.title || undefined,
|
|
87
|
+
tags: product.tags?.map(t => t.value) || [],
|
|
88
|
+
tagIds: product.tags?.map(t => t.id).filter(Boolean) || [],
|
|
89
|
+
categories: product.categories?.map(c => c.name) || [],
|
|
90
|
+
options,
|
|
91
|
+
variants,
|
|
92
|
+
mediaUrls: product.images?.map(img => img.url) || (product.thumbnail ? [product.thumbnail] : [])
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { HttpTypes } from "@medusajs/types";
|
|
2
|
+
export type SortOptions = "price_asc" | "price_desc" | "created_at" | "created_at_desc" | "created_at_asc" | "bestsellers";
|
|
3
|
+
/**
|
|
4
|
+
* Client-side product sort helper (used when backend does not sort natively).
|
|
5
|
+
*/
|
|
6
|
+
export declare function sortProducts(products: HttpTypes.StoreProduct[], sortBy: SortOptions): HttpTypes.StoreProduct[];
|
|
7
|
+
/**
|
|
8
|
+
* Search products by query
|
|
9
|
+
*/
|
|
10
|
+
export declare const searchProducts: ({ sdk, query, region, page, limit, headers, next }: {
|
|
11
|
+
sdk: any;
|
|
12
|
+
query: string;
|
|
13
|
+
region: HttpTypes.StoreRegion;
|
|
14
|
+
page?: number;
|
|
15
|
+
limit?: number;
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
next?: any;
|
|
18
|
+
}) => Promise<{
|
|
19
|
+
response: {
|
|
20
|
+
products: HttpTypes.StoreProduct[];
|
|
21
|
+
count: number;
|
|
22
|
+
};
|
|
23
|
+
nextPage: number | null;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* List products with pagination and filters
|
|
27
|
+
*/
|
|
28
|
+
export declare const listProducts: ({ sdk, region, pageParam, queryParams, headers, next }: {
|
|
29
|
+
sdk: any;
|
|
30
|
+
region: HttpTypes.StoreRegion;
|
|
31
|
+
pageParam?: number;
|
|
32
|
+
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams;
|
|
33
|
+
headers?: Record<string, string>;
|
|
34
|
+
next?: any;
|
|
35
|
+
}) => Promise<{
|
|
36
|
+
response: {
|
|
37
|
+
products: HttpTypes.StoreProduct[];
|
|
38
|
+
count: number;
|
|
39
|
+
};
|
|
40
|
+
nextPage: number | null;
|
|
41
|
+
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* List products with sorting applied on the client-side (up to 100 products)
|
|
45
|
+
*/
|
|
46
|
+
export declare const listProductsWithSort: ({ sdk, region, page, limit, queryParams, sortBy, headers, next }: {
|
|
47
|
+
sdk: any;
|
|
48
|
+
region: HttpTypes.StoreRegion;
|
|
49
|
+
page?: number;
|
|
50
|
+
limit?: number;
|
|
51
|
+
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams;
|
|
52
|
+
sortBy?: SortOptions;
|
|
53
|
+
headers?: Record<string, string>;
|
|
54
|
+
next?: any;
|
|
55
|
+
}) => Promise<{
|
|
56
|
+
response: {
|
|
57
|
+
products: HttpTypes.StoreProduct[];
|
|
58
|
+
count: number;
|
|
59
|
+
};
|
|
60
|
+
nextPage: number | null;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Fetch the total order count for a product
|
|
64
|
+
*/
|
|
65
|
+
export declare const getProductOrderCount: ({ sdk, productId, headers, next }: {
|
|
66
|
+
sdk: any;
|
|
67
|
+
productId: string;
|
|
68
|
+
headers?: Record<string, string>;
|
|
69
|
+
next?: any;
|
|
70
|
+
}) => Promise<number>;
|
|
71
|
+
/**
|
|
72
|
+
* Fetch product with updated inventory/stock data
|
|
73
|
+
*/
|
|
74
|
+
export declare const getProductWithInventory: ({ sdk, productId, region, headers, next }: {
|
|
75
|
+
sdk: any;
|
|
76
|
+
productId: string;
|
|
77
|
+
region: HttpTypes.StoreRegion;
|
|
78
|
+
headers?: Record<string, string>;
|
|
79
|
+
next?: any;
|
|
80
|
+
}) => Promise<HttpTypes.StoreProduct | null>;
|
|
81
|
+
//# sourceMappingURL=product-listing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-listing.d.ts","sourceRoot":"","sources":["../product-listing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side product sort helper (used when backend does not sort natively).
|
|
3
|
+
*/
|
|
4
|
+
export function sortProducts(products, sortBy) {
|
|
5
|
+
const sortedProducts = [...products];
|
|
6
|
+
if (["price_asc", "price_desc"].includes(sortBy)) {
|
|
7
|
+
sortedProducts.forEach((product) => {
|
|
8
|
+
if (product.variants && product.variants.length > 0) {
|
|
9
|
+
product._minPrice = Math.min(...product.variants.map((variant) => variant?.calculated_price?.calculated_amount || 0));
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
product._minPrice = Infinity;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
sortedProducts.sort((a, b) => {
|
|
16
|
+
const diff = a._minPrice - b._minPrice;
|
|
17
|
+
return sortBy === "price_asc" ? diff : -diff;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (sortBy === "created_at" || sortBy === "created_at_desc") {
|
|
21
|
+
sortedProducts.sort((a, b) => {
|
|
22
|
+
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (sortBy === "created_at_asc") {
|
|
26
|
+
sortedProducts.sort((a, b) => {
|
|
27
|
+
return new Date(a.created_at).getTime() - new Date(b.created_at).getTime();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return sortedProducts;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Search products by query
|
|
34
|
+
*/
|
|
35
|
+
export const searchProducts = async ({ sdk, query, region, page = 1, limit = 12, headers = {}, next = {} }) => {
|
|
36
|
+
const offset = (page - 1) * limit;
|
|
37
|
+
const response = await sdk.client.fetch(`/store/products`, {
|
|
38
|
+
method: "GET",
|
|
39
|
+
query: {
|
|
40
|
+
q: query,
|
|
41
|
+
limit,
|
|
42
|
+
offset,
|
|
43
|
+
region_id: region.id,
|
|
44
|
+
fields: "*variants.calculated_price,*variants.prices,+variants.inventory_quantity,*variants.images,*images,*categories,*categories.parent_category,+metadata,+tags,*thumbnail,"
|
|
45
|
+
},
|
|
46
|
+
headers,
|
|
47
|
+
next,
|
|
48
|
+
cache: "no-store",
|
|
49
|
+
});
|
|
50
|
+
const totalPages = Math.ceil(response.count / limit);
|
|
51
|
+
const nextPage = page < totalPages ? page + 1 : null;
|
|
52
|
+
return {
|
|
53
|
+
response: {
|
|
54
|
+
products: response.products,
|
|
55
|
+
count: response.count,
|
|
56
|
+
},
|
|
57
|
+
nextPage,
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* List products with pagination and filters
|
|
62
|
+
*/
|
|
63
|
+
export const listProducts = async ({ sdk, region, pageParam = 1, queryParams, headers = {}, next = {} }) => {
|
|
64
|
+
const limit = queryParams?.limit || 12;
|
|
65
|
+
const _pageParam = Math.max(pageParam, 1);
|
|
66
|
+
const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit;
|
|
67
|
+
return sdk.client
|
|
68
|
+
.fetch(`/store/products`, {
|
|
69
|
+
method: "GET",
|
|
70
|
+
query: {
|
|
71
|
+
limit,
|
|
72
|
+
offset,
|
|
73
|
+
region_id: region.id,
|
|
74
|
+
fields: "*variants.calculated_price,*variants.prices,+variants.inventory_quantity,*variants.images,*images,*categories,*categories.parent_category,+metadata,+tags,*thumbnail,",
|
|
75
|
+
...queryParams,
|
|
76
|
+
},
|
|
77
|
+
headers,
|
|
78
|
+
next,
|
|
79
|
+
cache: "force-cache",
|
|
80
|
+
})
|
|
81
|
+
.then(({ products, count }) => {
|
|
82
|
+
const nextPage = count > offset + limit ? pageParam + 1 : null;
|
|
83
|
+
return {
|
|
84
|
+
response: {
|
|
85
|
+
products,
|
|
86
|
+
count,
|
|
87
|
+
},
|
|
88
|
+
nextPage: nextPage,
|
|
89
|
+
queryParams,
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* List products with sorting applied on the client-side (up to 100 products)
|
|
95
|
+
*/
|
|
96
|
+
export const listProductsWithSort = async ({ sdk, region, page = 1, limit = 12, queryParams, sortBy = "created_at", headers = {}, next = {} }) => {
|
|
97
|
+
const BATCH_SIZE = 100;
|
|
98
|
+
let allProducts = [];
|
|
99
|
+
let offset = 0;
|
|
100
|
+
let totalCount = 0;
|
|
101
|
+
// Fetch all products in batches
|
|
102
|
+
do {
|
|
103
|
+
const { products, count } = await sdk.client.fetch(`/store/products`, {
|
|
104
|
+
method: "GET",
|
|
105
|
+
query: {
|
|
106
|
+
limit: BATCH_SIZE,
|
|
107
|
+
offset,
|
|
108
|
+
region_id: region.id,
|
|
109
|
+
fields: "*variants.calculated_price,*variants.prices,+variants.inventory_quantity,*variants.images,*images,*categories,*categories.parent_category,+metadata,+tags,*thumbnail,",
|
|
110
|
+
...queryParams,
|
|
111
|
+
},
|
|
112
|
+
headers,
|
|
113
|
+
next,
|
|
114
|
+
cache: "force-cache",
|
|
115
|
+
});
|
|
116
|
+
allProducts = [...allProducts, ...products];
|
|
117
|
+
totalCount = count;
|
|
118
|
+
offset += BATCH_SIZE;
|
|
119
|
+
// Safety check to avoid infinite loops if totalCount is somehow inconsistent
|
|
120
|
+
if (products.length === 0)
|
|
121
|
+
break;
|
|
122
|
+
} while (allProducts.length < totalCount);
|
|
123
|
+
const sortedProducts = sortProducts(allProducts, sortBy);
|
|
124
|
+
const paginatedProducts = sortedProducts.slice((page - 1) * limit, page * limit);
|
|
125
|
+
const nextPage = sortedProducts.length > page * limit ? page + 1 : null;
|
|
126
|
+
return {
|
|
127
|
+
response: {
|
|
128
|
+
products: paginatedProducts,
|
|
129
|
+
count: sortedProducts.length,
|
|
130
|
+
},
|
|
131
|
+
nextPage,
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Fetch the total order count for a product
|
|
136
|
+
*/
|
|
137
|
+
export const getProductOrderCount = async ({ sdk, productId, headers = {}, next = {} }) => {
|
|
138
|
+
try {
|
|
139
|
+
const response = await sdk.client.fetch(`/store/orders`, {
|
|
140
|
+
method: "GET",
|
|
141
|
+
query: {
|
|
142
|
+
limit: 1000,
|
|
143
|
+
fields: "*items,*items.variant,*items.product",
|
|
144
|
+
},
|
|
145
|
+
headers,
|
|
146
|
+
next,
|
|
147
|
+
cache: "force-cache",
|
|
148
|
+
});
|
|
149
|
+
if (!response.orders) {
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
let orderCount = 0;
|
|
153
|
+
for (const order of response.orders) {
|
|
154
|
+
if (order.items?.some((item) => item.product?.id === productId || item.variant?.product_id === productId)) {
|
|
155
|
+
orderCount++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return orderCount;
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
console.error("Failed to fetch product order count:", error);
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Fetch product with updated inventory/stock data
|
|
167
|
+
*/
|
|
168
|
+
export const getProductWithInventory = async ({ sdk, productId, region, headers = {}, next = {} }) => {
|
|
169
|
+
try {
|
|
170
|
+
const response = await sdk.client.fetch(`/store/products/${productId}`, {
|
|
171
|
+
method: "GET",
|
|
172
|
+
query: {
|
|
173
|
+
region_id: region.id,
|
|
174
|
+
fields: "*variants.calculated_price,*variants.prices,+variants.inventory_quantity,*variants.manage_inventory,*variants.allow_backorder,*variants.images,*images,*categories,*categories.parent_category,+metadata,+tags,*thumbnail,",
|
|
175
|
+
},
|
|
176
|
+
headers,
|
|
177
|
+
next,
|
|
178
|
+
cache: "no-store",
|
|
179
|
+
});
|
|
180
|
+
if (!response || !response.product) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return response.product;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error("❌ Error fetching product inventory:", error);
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type MedusaStoreClientOptions } from "./store-api";
|
|
2
|
+
export interface StoreProduct {
|
|
3
|
+
id: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
handle?: string;
|
|
6
|
+
created_at?: string;
|
|
7
|
+
variants?: Array<Record<string, unknown>>;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface StoreProductListResponse {
|
|
11
|
+
products: StoreProduct[];
|
|
12
|
+
count: number;
|
|
13
|
+
}
|
|
14
|
+
export declare const MEDUSA_PRODUCT_LIST_FIELDS = "*variants.calculated_price,+variants.inventory_quantity,*variants.images,+variants.metadata,+variants.options,+metadata,+tags,+average_rating,+total_rating_count,+total_rating_sum,";
|
|
15
|
+
export declare const MEDUSA_PRODUCT_HANDLE_FIELDS = "*variants.calculated_price,+variants.inventory_quantity,+variants.manage_inventory,+variants.allow_backorder,*variants.options,*options,*options.values,*images,*thumbnail,+metadata";
|
|
16
|
+
export interface MedusaProductListParams {
|
|
17
|
+
pageParam?: number;
|
|
18
|
+
limit?: number;
|
|
19
|
+
regionId?: string;
|
|
20
|
+
queryParams?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* GET /store/products or /store/product-helper/products
|
|
24
|
+
*/
|
|
25
|
+
export declare function medusaProductList(options: MedusaStoreClientOptions, params: MedusaProductListParams): Promise<{
|
|
26
|
+
products: StoreProduct[];
|
|
27
|
+
count: number;
|
|
28
|
+
nextPage: number | null;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* GET /store/products?handle=
|
|
32
|
+
*/
|
|
33
|
+
export declare function medusaProductByHandle(handle: string, options: MedusaStoreClientOptions, query?: {
|
|
34
|
+
fields?: string;
|
|
35
|
+
region_id?: string;
|
|
36
|
+
}): Promise<StoreProduct | null>;
|
|
37
|
+
/**
|
|
38
|
+
* GET /store/product-helper/filters
|
|
39
|
+
*/
|
|
40
|
+
export declare function medusaProductHelperFilters(options: MedusaStoreClientOptions): Promise<Record<string, unknown>>;
|
|
41
|
+
//# sourceMappingURL=products.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../products.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAExF,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACrC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,0BAA0B,yLACmJ,CAAC;AAE3L,eAAO,MAAM,4BAA4B,yLACiJ,CAAC;AA0G3L,MAAM,WAAW,uBAAuB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACnC,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,uBAAuB,GAChC,OAAO,CAAC;IAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAiC/E;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,EACjC,KAAK,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC5C,OAAO,EAAE,wBAAwB,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAGlC"}
|
package/dist/products.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { parseStoreJson, storeFetch } from "./store-api";
|
|
2
|
+
export const MEDUSA_PRODUCT_LIST_FIELDS = "*variants.calculated_price,+variants.inventory_quantity,*variants.images,+variants.metadata,+variants.options,+metadata,+tags,+average_rating,+total_rating_count,+total_rating_sum,";
|
|
3
|
+
export const MEDUSA_PRODUCT_HANDLE_FIELDS = "*variants.calculated_price,+variants.inventory_quantity,+variants.manage_inventory,+variants.allow_backorder,*variants.options,*options,*options.values,*images,*thumbnail,+metadata";
|
|
4
|
+
const ADVANCED_FILTER_KEYS = [
|
|
5
|
+
"metadata",
|
|
6
|
+
"min_price",
|
|
7
|
+
"max_price",
|
|
8
|
+
"q",
|
|
9
|
+
"collection_id",
|
|
10
|
+
"category_id",
|
|
11
|
+
"tags",
|
|
12
|
+
"option_value",
|
|
13
|
+
"gender",
|
|
14
|
+
"color",
|
|
15
|
+
"material",
|
|
16
|
+
"style",
|
|
17
|
+
"brand",
|
|
18
|
+
"type",
|
|
19
|
+
"product_type",
|
|
20
|
+
"order",
|
|
21
|
+
];
|
|
22
|
+
function hasAdvancedFilters(queryParams) {
|
|
23
|
+
if (!queryParams)
|
|
24
|
+
return false;
|
|
25
|
+
return Object.keys(queryParams).some((key) => ADVANCED_FILTER_KEYS.includes(key) &&
|
|
26
|
+
queryParams[key] !== undefined &&
|
|
27
|
+
queryParams[key] !== null);
|
|
28
|
+
}
|
|
29
|
+
function buildHelperQueryParams(regionId, limit, offset, queryParams) {
|
|
30
|
+
const params = new URLSearchParams();
|
|
31
|
+
params.append("limit", limit.toString());
|
|
32
|
+
params.append("offset", offset.toString());
|
|
33
|
+
if (regionId)
|
|
34
|
+
params.append("region_id", regionId);
|
|
35
|
+
params.append("fields", "*");
|
|
36
|
+
for (const [key, value] of Object.entries(queryParams ?? {})) {
|
|
37
|
+
if (["metadata", "min_price", "max_price", "limit", "offset", "region_id", "fields"].includes(key)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const values = Array.isArray(value) ? value : [value];
|
|
41
|
+
const lowerKey = key.toLowerCase();
|
|
42
|
+
if (lowerKey === "color") {
|
|
43
|
+
values.forEach((v) => params.append("option_value[]", String(v)));
|
|
44
|
+
}
|
|
45
|
+
else if (["material", "gender", "product_type", "type", "style", "brand"].includes(lowerKey)) {
|
|
46
|
+
const metaKey = lowerKey === "type" ? "product_type" : lowerKey;
|
|
47
|
+
values.forEach((v) => params.append(`metadata[${metaKey}]`, String(v)));
|
|
48
|
+
}
|
|
49
|
+
else if (Array.isArray(value)) {
|
|
50
|
+
value.forEach((v) => params.append(`${key}[]`, String(v)));
|
|
51
|
+
}
|
|
52
|
+
else if (value !== undefined && value !== null) {
|
|
53
|
+
params.append(key, String(value));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (queryParams?.min_price)
|
|
57
|
+
params.append("price_min", String(queryParams.min_price));
|
|
58
|
+
if (queryParams?.max_price)
|
|
59
|
+
params.append("price_max", String(queryParams.max_price));
|
|
60
|
+
if (queryParams?.metadata && typeof queryParams.metadata === "object") {
|
|
61
|
+
for (const [key, value] of Object.entries(queryParams.metadata)) {
|
|
62
|
+
const values = Array.isArray(value) ? value : [value];
|
|
63
|
+
values.forEach((v) => {
|
|
64
|
+
if (key.toLowerCase() === "color") {
|
|
65
|
+
params.append("option_value[]", String(v));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
params.append(`metadata[${key}]`, String(v));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return params;
|
|
74
|
+
}
|
|
75
|
+
function buildStandardQuery(regionId, limit, offset, queryParams) {
|
|
76
|
+
const finalQuery = {
|
|
77
|
+
limit,
|
|
78
|
+
offset,
|
|
79
|
+
fields: MEDUSA_PRODUCT_LIST_FIELDS,
|
|
80
|
+
};
|
|
81
|
+
if (regionId)
|
|
82
|
+
finalQuery.region_id = regionId;
|
|
83
|
+
const safeKeys = ["order", "id", "handle", "status", "created_at", "updated_at", "type_id"];
|
|
84
|
+
for (const key of safeKeys) {
|
|
85
|
+
if (queryParams?.[key] !== undefined && queryParams[key] !== null) {
|
|
86
|
+
finalQuery[key] = queryParams[key];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return finalQuery;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* GET /store/products or /store/product-helper/products
|
|
93
|
+
*/
|
|
94
|
+
export async function medusaProductList(options, params) {
|
|
95
|
+
const limit = params.limit ?? params.queryParams?.limit ?? 12;
|
|
96
|
+
const pageParam = Math.max(params.pageParam ?? 1, 1);
|
|
97
|
+
const offset = pageParam === 1 ? 0 : (pageParam - 1) * limit;
|
|
98
|
+
const useHelper = hasAdvancedFilters(params.queryParams);
|
|
99
|
+
let response;
|
|
100
|
+
if (useHelper) {
|
|
101
|
+
const query = buildHelperQueryParams(params.regionId, limit, offset, params.queryParams);
|
|
102
|
+
response = await storeFetch(`/product-helper/products?${query.toString()}`, options, {
|
|
103
|
+
method: "GET",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
const query = buildStandardQuery(params.regionId, limit, offset, params.queryParams);
|
|
108
|
+
const search = new URLSearchParams();
|
|
109
|
+
for (const [key, value] of Object.entries(query)) {
|
|
110
|
+
search.set(key, String(value));
|
|
111
|
+
}
|
|
112
|
+
response = await storeFetch(`/products?${search.toString()}`, options, { method: "GET" });
|
|
113
|
+
}
|
|
114
|
+
const { products, count } = await parseStoreJson(response, "Product list request");
|
|
115
|
+
const nextPage = count > offset + limit ? pageParam + 1 : null;
|
|
116
|
+
return {
|
|
117
|
+
products: products ?? [],
|
|
118
|
+
count: count ?? 0,
|
|
119
|
+
nextPage,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* GET /store/products?handle=
|
|
124
|
+
*/
|
|
125
|
+
export async function medusaProductByHandle(handle, options, query) {
|
|
126
|
+
const params = new URLSearchParams();
|
|
127
|
+
params.set("handle", handle);
|
|
128
|
+
params.set("fields", query?.fields ?? MEDUSA_PRODUCT_HANDLE_FIELDS);
|
|
129
|
+
if (query?.region_id)
|
|
130
|
+
params.set("region_id", query.region_id);
|
|
131
|
+
const response = await storeFetch(`/products?${params.toString()}`, options, { method: "GET" });
|
|
132
|
+
const data = await parseStoreJson(response, "Product by handle request");
|
|
133
|
+
return data.products?.[0] ?? null;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* GET /store/product-helper/filters
|
|
137
|
+
*/
|
|
138
|
+
export async function medusaProductHelperFilters(options) {
|
|
139
|
+
const response = await storeFetch("/product-helper/filters", options, { method: "GET" });
|
|
140
|
+
return parseStoreJson(response, "Product filters request");
|
|
141
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RecentlyViewedServiceOptions {
|
|
2
|
+
storageKey?: string;
|
|
3
|
+
maxItems?: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Local-first recently viewed service.
|
|
7
|
+
* Later, swap internals with API calls without changing callers.
|
|
8
|
+
*/
|
|
9
|
+
export declare const recentlyViewedService: {
|
|
10
|
+
getAll(options?: RecentlyViewedServiceOptions): string[];
|
|
11
|
+
track(productId: string, options?: RecentlyViewedServiceOptions): string[];
|
|
12
|
+
clear(options?: RecentlyViewedServiceOptions): void;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=recently-viewed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recently-viewed.d.ts","sourceRoot":"","sources":["../recently-viewed.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AA8CD;;;GAGG;AACH,eAAO,MAAM,qBAAqB;qBACb,4BAA4B,GAAG,MAAM,EAAE;qBAIvC,MAAM,YAAY,4BAA4B,GAAG,MAAM,EAAE;oBAO1D,4BAA4B,GAAG,IAAI;CAGtD,CAAC"}
|