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.
Files changed (89) hide show
  1. package/dist/auth.d.ts +29 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +80 -0
  4. package/dist/cart.d.ts +148 -0
  5. package/dist/cart.d.ts.map +1 -0
  6. package/dist/cart.js +156 -0
  7. package/dist/categories.d.ts +20 -0
  8. package/dist/categories.d.ts.map +1 -0
  9. package/dist/categories.js +36 -0
  10. package/dist/collections.d.ts +27 -0
  11. package/dist/collections.d.ts.map +1 -0
  12. package/dist/collections.js +36 -0
  13. package/dist/contact-action.d.ts +18 -0
  14. package/dist/contact-action.d.ts.map +1 -0
  15. package/dist/contact-action.js +42 -0
  16. package/dist/customer.d.ts +59 -0
  17. package/dist/customer.d.ts.map +1 -0
  18. package/dist/customer.js +68 -0
  19. package/dist/facebook-login.d.ts +37 -0
  20. package/dist/facebook-login.d.ts.map +1 -0
  21. package/dist/facebook-login.js +146 -0
  22. package/dist/fulfillment.d.ts +33 -0
  23. package/dist/fulfillment.d.ts.map +1 -0
  24. package/dist/fulfillment.js +43 -0
  25. package/dist/gift-wrap.d.ts +30 -0
  26. package/dist/gift-wrap.d.ts.map +1 -0
  27. package/dist/gift-wrap.js +29 -0
  28. package/dist/google-login.d.ts +37 -0
  29. package/dist/google-login.d.ts.map +1 -0
  30. package/dist/google-login.js +150 -0
  31. package/dist/guest.d.ts +46 -0
  32. package/dist/guest.d.ts.map +1 -0
  33. package/dist/guest.js +91 -0
  34. package/dist/index.d.ts +29 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +28 -0
  37. package/dist/locales.d.ts +13 -0
  38. package/dist/locales.d.ts.map +1 -0
  39. package/dist/locales.js +13 -0
  40. package/dist/medusa-auth.d.ts +17 -0
  41. package/dist/medusa-auth.d.ts.map +1 -0
  42. package/dist/medusa-auth.js +25 -0
  43. package/dist/middleware.d.ts +13 -0
  44. package/dist/middleware.d.ts.map +1 -0
  45. package/dist/middleware.js +36 -0
  46. package/dist/orders.d.ts +105 -0
  47. package/dist/orders.d.ts.map +1 -0
  48. package/dist/orders.js +139 -0
  49. package/dist/payment.d.ts +55 -0
  50. package/dist/payment.d.ts.map +1 -0
  51. package/dist/payment.js +68 -0
  52. package/dist/product-detail.d.ts +30 -0
  53. package/dist/product-detail.d.ts.map +1 -0
  54. package/dist/product-detail.js +94 -0
  55. package/dist/product-listing.d.ts +81 -0
  56. package/dist/product-listing.d.ts.map +1 -0
  57. package/dist/product-listing.js +189 -0
  58. package/dist/products.d.ts +41 -0
  59. package/dist/products.d.ts.map +1 -0
  60. package/dist/products.js +141 -0
  61. package/dist/recently-viewed.d.ts +14 -0
  62. package/dist/recently-viewed.d.ts.map +1 -0
  63. package/dist/recently-viewed.js +59 -0
  64. package/dist/regions.d.ts +37 -0
  65. package/dist/regions.d.ts.map +1 -0
  66. package/dist/regions.js +30 -0
  67. package/dist/related-products.d.ts +30 -0
  68. package/dist/related-products.d.ts.map +1 -0
  69. package/dist/related-products.js +99 -0
  70. package/dist/returns.d.ts +75 -0
  71. package/dist/returns.d.ts.map +1 -0
  72. package/dist/returns.js +105 -0
  73. package/dist/reviews.d.ts +135 -0
  74. package/dist/reviews.d.ts.map +1 -0
  75. package/dist/reviews.js +202 -0
  76. package/dist/store-api.d.ts +20 -0
  77. package/dist/store-api.d.ts.map +1 -0
  78. package/dist/store-api.js +55 -0
  79. package/dist/swaps.d.ts +33 -0
  80. package/dist/swaps.d.ts.map +1 -0
  81. package/dist/swaps.js +39 -0
  82. package/dist/variants.d.ts +17 -0
  83. package/dist/variants.d.ts.map +1 -0
  84. package/dist/variants.js +8 -0
  85. package/dist/wishlist.d.ts +65 -0
  86. package/dist/wishlist.d.ts.map +1 -0
  87. package/dist/wishlist.js +149 -0
  88. package/middleware.ts +54 -0
  89. package/package.json +174 -0
@@ -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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,MAAM,WAAW,GACjB,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,iBAAiB,GACjB,gBAAgB,GAChB,aAAa,CAAA;AAQnB;;GAEG;AACH,wBAAgB,YAAY,CACxB,QAAQ,EAAE,SAAS,CAAC,YAAY,EAAE,EAClC,MAAM,EAAE,WAAW,GACpB,SAAS,CAAC,YAAY,EAAE,CAmC1B;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,oDAQlC;IACC,GAAG,EAAE,GAAG,CAAA;IACR,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAC,WAAW,CAAA;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb;;;;;;EA+BA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GAAU,wDAOhC;IACC,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,SAAS,CAAC,WAAW,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,sBAAsB,CAAA;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb,KAAG,OAAO,CAAC;IACR,QAAQ,EAAE;QAAE,QAAQ,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,sBAAsB,CAAA;CACxE,CAmCA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAU,kEASxC;IACC,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,SAAS,CAAC,WAAW,CAAA;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,sBAAsB,CAAA;IACrE,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb,KAAG,OAAO,CAAC;IACR,QAAQ,EAAE;QAAE,QAAQ,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B,CAkDA,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAU,mCAKxC;IACC,GAAG,EAAE,GAAG,CAAA;IACR,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb,KAAG,OAAO,CAAC,MAAM,CAoCjB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAU,2CAM3C;IACC,GAAG,EAAE,GAAG,CAAA;IACR,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,SAAS,CAAC,WAAW,CAAA;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,GAAG,CAAA;CACb,KAAG,OAAO,CAAC,SAAS,CAAC,YAAY,GAAG,IAAI,CAyBxC,CAAA"}
@@ -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"}
@@ -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"}