@thorprovider/adapters 5.0.11 → 5.0.12
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/index.d.mts +29 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +294 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +294 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/providers/medusa/auth.test.ts +148 -25
- package/src/providers/medusa/auth.ts +129 -16
- package/src/providers/medusa/customer-orders.test.ts +142 -0
- package/src/providers/medusa/index.ts +108 -26
- package/src/providers/medusa/transforms.test.ts +45 -0
- package/src/providers/medusa/transforms.ts +7 -0
- package/src/providers/mock/catalog-query.test.ts +153 -17
- package/src/providers/mock/index.test.ts +19 -0
- package/src/providers/mock/mock.ts +189 -1
- package/.turbo/turbo-build.log +0 -18
- package/.turbo/turbo-test.log +0 -897
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/.tsbuildinfo +0 -1
- package/publish.log +0 -93
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _thorprovider_types from '@thorprovider/types';
|
|
2
|
-
import { Order, Cart, BackendCapabilities, Money, PaymentMethod, FulfillmentOption, CartItem, StockLocation, InventoryLevel, StorefrontConfig, DashboardMetrics, ProviderTypeString, CommerceProvider, AuthProvider, ProviderConfig, AuthConfig, Product, GetProductsOptions, CatalogQuery, CatalogQueryOutcome, FacetSupport, AdvancedSearchProductsOptions, SearchResultMeta, FilterConfig, Collection, GetCollectionsOptions, CollectionProductsOptions, ProductCategory, GetCategoriesOptions, CartLineInput, CartLineUpdate, GetOrdersOptions, GetCustomersOptions, Customer, Address, Region, AdminProduct, PaymentMethodsOptions, StockValidation, StorefrontContext, DesignerConfig, DesignerHistoryEntry, ShippingMethod, Country } from '@thorprovider/types';
|
|
2
|
+
import { Order, Cart, BackendCapabilities, Money, PaymentMethod, FulfillmentOption, CartItem, StockLocation, InventoryLevel, StorefrontConfig, DashboardMetrics, ProviderTypeString, CommerceProvider, AuthProvider, ProviderConfig, AuthConfig, Product, GetProductsOptions, CatalogQuery, CatalogQueryOutcome, FacetSupport, AdvancedSearchProductsOptions, SearchResultMeta, FilterConfig, Collection, GetCollectionsOptions, CollectionProductsOptions, ProductCategory, GetCategoriesOptions, CartLineInput, CartLineUpdate, GetOrdersOptions, GetCustomerOrdersPageOptions, CustomerOrdersPage, GetCustomersOptions, Customer, Address, Region, AdminProduct, PaymentMethodsOptions, StockValidation, StorefrontContext, DesignerConfig, DesignerHistoryEntry, ShippingMethod, Country } from '@thorprovider/types';
|
|
3
3
|
export * from '@thorprovider/types';
|
|
4
4
|
export { BackendCapabilities, CommerceProvider, DesignerConfig, DesignerHistoryEntry, DesignerNavItem, DesignerThemeConfig, DesignerThemePreset, ProviderConfig, StorefrontConfig, StorefrontContext, StorefrontPlatformType, StorefrontSeoDefaults } from '@thorprovider/types';
|
|
5
5
|
import Medusa from '@medusajs/js-sdk';
|
|
@@ -1905,13 +1905,17 @@ declare class MedusaProvider implements CommerceProvider, CartCompletionCapable
|
|
|
1905
1905
|
}>;
|
|
1906
1906
|
}>>;
|
|
1907
1907
|
/**
|
|
1908
|
-
* Get all orders for a customer (storefront).
|
|
1908
|
+
* Get all orders for a customer (storefront) as an array (legacy surface).
|
|
1909
1909
|
*
|
|
1910
|
-
*
|
|
1911
|
-
*
|
|
1910
|
+
* Delegates to the channel-scoped paginated contract
|
|
1911
|
+
* ({@link customerOrdersPage}) and returns that window's orders. The backend
|
|
1912
|
+
* (`GET /store/thor/orders`) scopes by BOTH the authenticated customer and
|
|
1913
|
+
* the sales channel resolved from the publishable key, so cross-channel
|
|
1914
|
+
* orders are excluded by the backend before pagination and **no client-side
|
|
1915
|
+
* channel filter runs**.
|
|
1912
1916
|
*
|
|
1913
|
-
* @param options - Order query options (supports
|
|
1914
|
-
* @returns Array of orders for the authenticated customer
|
|
1917
|
+
* @param options - Order query options (supports a custom fetcher)
|
|
1918
|
+
* @returns Array of orders for the authenticated customer on the store channel
|
|
1915
1919
|
*
|
|
1916
1920
|
* @example
|
|
1917
1921
|
* ```typescript
|
|
@@ -1920,6 +1924,25 @@ declare class MedusaProvider implements CommerceProvider, CartCompletionCapable
|
|
|
1920
1924
|
* ```
|
|
1921
1925
|
*/
|
|
1922
1926
|
getOrders(options?: GetOrdersOptions): Promise<Order[]>;
|
|
1927
|
+
/**
|
|
1928
|
+
* Channel-scoped, paginated order history for the authenticated customer.
|
|
1929
|
+
*
|
|
1930
|
+
* Calls the backend route `GET /store/thor/orders`, which requires the
|
|
1931
|
+
* customer session and scopes `order` by `customer_id` **and** the
|
|
1932
|
+
* `sales_channel_id` resolved from the publishable key, returning
|
|
1933
|
+
* `{ orders, count, limit, offset }` with the backend's real total computed
|
|
1934
|
+
* before pagination.
|
|
1935
|
+
*
|
|
1936
|
+
* The `salesChannelId` option is the store's explicitly configured channel.
|
|
1937
|
+
* When supplied, every returned order is asserted to belong to it; a
|
|
1938
|
+
* foreign-channel order (for example from a multi-channel publishable key that
|
|
1939
|
+
* silently resolved an arbitrary first id) fails closed with a typed error
|
|
1940
|
+
* rather than being presented as the customer's history.
|
|
1941
|
+
*
|
|
1942
|
+
* @param options - Bounded pagination window and the store's sales channel
|
|
1943
|
+
* @returns The backend's `{ orders, count, limit, offset }`
|
|
1944
|
+
*/
|
|
1945
|
+
customerOrdersPage(options?: GetCustomerOrdersPageOptions): Promise<CustomerOrdersPage>;
|
|
1923
1946
|
/**
|
|
1924
1947
|
* Get a single order by ID
|
|
1925
1948
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _thorprovider_types from '@thorprovider/types';
|
|
2
|
-
import { Order, Cart, BackendCapabilities, Money, PaymentMethod, FulfillmentOption, CartItem, StockLocation, InventoryLevel, StorefrontConfig, DashboardMetrics, ProviderTypeString, CommerceProvider, AuthProvider, ProviderConfig, AuthConfig, Product, GetProductsOptions, CatalogQuery, CatalogQueryOutcome, FacetSupport, AdvancedSearchProductsOptions, SearchResultMeta, FilterConfig, Collection, GetCollectionsOptions, CollectionProductsOptions, ProductCategory, GetCategoriesOptions, CartLineInput, CartLineUpdate, GetOrdersOptions, GetCustomersOptions, Customer, Address, Region, AdminProduct, PaymentMethodsOptions, StockValidation, StorefrontContext, DesignerConfig, DesignerHistoryEntry, ShippingMethod, Country } from '@thorprovider/types';
|
|
2
|
+
import { Order, Cart, BackendCapabilities, Money, PaymentMethod, FulfillmentOption, CartItem, StockLocation, InventoryLevel, StorefrontConfig, DashboardMetrics, ProviderTypeString, CommerceProvider, AuthProvider, ProviderConfig, AuthConfig, Product, GetProductsOptions, CatalogQuery, CatalogQueryOutcome, FacetSupport, AdvancedSearchProductsOptions, SearchResultMeta, FilterConfig, Collection, GetCollectionsOptions, CollectionProductsOptions, ProductCategory, GetCategoriesOptions, CartLineInput, CartLineUpdate, GetOrdersOptions, GetCustomerOrdersPageOptions, CustomerOrdersPage, GetCustomersOptions, Customer, Address, Region, AdminProduct, PaymentMethodsOptions, StockValidation, StorefrontContext, DesignerConfig, DesignerHistoryEntry, ShippingMethod, Country } from '@thorprovider/types';
|
|
3
3
|
export * from '@thorprovider/types';
|
|
4
4
|
export { BackendCapabilities, CommerceProvider, DesignerConfig, DesignerHistoryEntry, DesignerNavItem, DesignerThemeConfig, DesignerThemePreset, ProviderConfig, StorefrontConfig, StorefrontContext, StorefrontPlatformType, StorefrontSeoDefaults } from '@thorprovider/types';
|
|
5
5
|
import Medusa from '@medusajs/js-sdk';
|
|
@@ -1905,13 +1905,17 @@ declare class MedusaProvider implements CommerceProvider, CartCompletionCapable
|
|
|
1905
1905
|
}>;
|
|
1906
1906
|
}>>;
|
|
1907
1907
|
/**
|
|
1908
|
-
* Get all orders for a customer (storefront).
|
|
1908
|
+
* Get all orders for a customer (storefront) as an array (legacy surface).
|
|
1909
1909
|
*
|
|
1910
|
-
*
|
|
1911
|
-
*
|
|
1910
|
+
* Delegates to the channel-scoped paginated contract
|
|
1911
|
+
* ({@link customerOrdersPage}) and returns that window's orders. The backend
|
|
1912
|
+
* (`GET /store/thor/orders`) scopes by BOTH the authenticated customer and
|
|
1913
|
+
* the sales channel resolved from the publishable key, so cross-channel
|
|
1914
|
+
* orders are excluded by the backend before pagination and **no client-side
|
|
1915
|
+
* channel filter runs**.
|
|
1912
1916
|
*
|
|
1913
|
-
* @param options - Order query options (supports
|
|
1914
|
-
* @returns Array of orders for the authenticated customer
|
|
1917
|
+
* @param options - Order query options (supports a custom fetcher)
|
|
1918
|
+
* @returns Array of orders for the authenticated customer on the store channel
|
|
1915
1919
|
*
|
|
1916
1920
|
* @example
|
|
1917
1921
|
* ```typescript
|
|
@@ -1920,6 +1924,25 @@ declare class MedusaProvider implements CommerceProvider, CartCompletionCapable
|
|
|
1920
1924
|
* ```
|
|
1921
1925
|
*/
|
|
1922
1926
|
getOrders(options?: GetOrdersOptions): Promise<Order[]>;
|
|
1927
|
+
/**
|
|
1928
|
+
* Channel-scoped, paginated order history for the authenticated customer.
|
|
1929
|
+
*
|
|
1930
|
+
* Calls the backend route `GET /store/thor/orders`, which requires the
|
|
1931
|
+
* customer session and scopes `order` by `customer_id` **and** the
|
|
1932
|
+
* `sales_channel_id` resolved from the publishable key, returning
|
|
1933
|
+
* `{ orders, count, limit, offset }` with the backend's real total computed
|
|
1934
|
+
* before pagination.
|
|
1935
|
+
*
|
|
1936
|
+
* The `salesChannelId` option is the store's explicitly configured channel.
|
|
1937
|
+
* When supplied, every returned order is asserted to belong to it; a
|
|
1938
|
+
* foreign-channel order (for example from a multi-channel publishable key that
|
|
1939
|
+
* silently resolved an arbitrary first id) fails closed with a typed error
|
|
1940
|
+
* rather than being presented as the customer's history.
|
|
1941
|
+
*
|
|
1942
|
+
* @param options - Bounded pagination window and the store's sales channel
|
|
1943
|
+
* @returns The backend's `{ orders, count, limit, offset }`
|
|
1944
|
+
*/
|
|
1945
|
+
customerOrdersPage(options?: GetCustomerOrdersPageOptions): Promise<CustomerOrdersPage>;
|
|
1923
1946
|
/**
|
|
1924
1947
|
* Get a single order by ID
|
|
1925
1948
|
*
|
package/dist/index.js
CHANGED
|
@@ -1139,6 +1139,12 @@ function transformProduct(product, currencyCode) {
|
|
|
1139
1139
|
title: product.collection.title ?? "",
|
|
1140
1140
|
handle: product.collection.handle ?? ""
|
|
1141
1141
|
}] : void 0,
|
|
1142
|
+
categories: product.categories?.map((category) => ({
|
|
1143
|
+
id: category.id,
|
|
1144
|
+
name: category.name ?? "",
|
|
1145
|
+
handle: category.handle ?? "",
|
|
1146
|
+
parentCategoryId: category.parent_category_id ?? void 0
|
|
1147
|
+
})),
|
|
1142
1148
|
productType: product.type?.value ?? void 0,
|
|
1143
1149
|
vendor: void 0,
|
|
1144
1150
|
// Medusa doesn't have vendor field
|
|
@@ -1911,6 +1917,7 @@ var MedusaAuthProvider = class {
|
|
|
1911
1917
|
if (this.authConfig.method === "jwt") {
|
|
1912
1918
|
await this.storageManager.setToken(token);
|
|
1913
1919
|
}
|
|
1920
|
+
await this.linkCustomerChannel();
|
|
1914
1921
|
const customer = await this.getCurrentCustomer();
|
|
1915
1922
|
this.logger.info("Login successful", { customerId: customer?.id });
|
|
1916
1923
|
return {
|
|
@@ -1918,6 +1925,7 @@ var MedusaAuthProvider = class {
|
|
|
1918
1925
|
customer: customer ?? void 0
|
|
1919
1926
|
};
|
|
1920
1927
|
} catch (error) {
|
|
1928
|
+
if (error instanceof ProviderAPIError) throw error;
|
|
1921
1929
|
this.logger.error("Login failed", error);
|
|
1922
1930
|
throw new ProviderAPIError(
|
|
1923
1931
|
`Authentication failed: ${error.message}`,
|
|
@@ -1929,16 +1937,14 @@ var MedusaAuthProvider = class {
|
|
|
1929
1937
|
async register(data) {
|
|
1930
1938
|
this.logger.debug("register", { email: data.email });
|
|
1931
1939
|
try {
|
|
1932
|
-
await this.sdk.auth.register("customer", "emailpass", {
|
|
1940
|
+
const registrationToken = await this.sdk.auth.register("customer", "emailpass", {
|
|
1933
1941
|
email: data.email,
|
|
1934
1942
|
password: data.password
|
|
1935
1943
|
});
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
phone: data.phone
|
|
1941
|
-
});
|
|
1944
|
+
if (this.authConfig.method === "jwt" && typeof registrationToken === "string") {
|
|
1945
|
+
await this.storageManager.setToken(registrationToken);
|
|
1946
|
+
}
|
|
1947
|
+
const linked = await this.createChannelLinkedCustomer(data);
|
|
1942
1948
|
const loginResult = await this.sdk.auth.login("customer", "emailpass", {
|
|
1943
1949
|
email: data.email,
|
|
1944
1950
|
password: data.password
|
|
@@ -1964,12 +1970,20 @@ var MedusaAuthProvider = class {
|
|
|
1964
1970
|
if (this.authConfig.method === "jwt") {
|
|
1965
1971
|
await this.storageManager.setToken(token);
|
|
1966
1972
|
}
|
|
1973
|
+
const customer = await this.getCurrentCustomer();
|
|
1974
|
+
if (!customer || customer.id !== linked.id) {
|
|
1975
|
+
throw new ProviderAPIError(
|
|
1976
|
+
"Registration created an auth identity without a linked customer.",
|
|
1977
|
+
"CUSTOMER_LINK_INCOMPLETE"
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1967
1980
|
this.logger.info("Registration successful", { customerId: customer.id });
|
|
1968
1981
|
return {
|
|
1969
1982
|
token: this.authConfig.method === "jwt" ? token : void 0,
|
|
1970
|
-
customer
|
|
1983
|
+
customer
|
|
1971
1984
|
};
|
|
1972
1985
|
} catch (error) {
|
|
1986
|
+
if (error instanceof ProviderAPIError) throw error;
|
|
1973
1987
|
this.logger.error("Registration failed", error);
|
|
1974
1988
|
throw new ProviderAPIError(
|
|
1975
1989
|
`Registration failed: ${error.message}`,
|
|
@@ -1978,6 +1992,79 @@ var MedusaAuthProvider = class {
|
|
|
1978
1992
|
);
|
|
1979
1993
|
}
|
|
1980
1994
|
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Create and channel-link a customer through `POST /store/thor/customers`.
|
|
1997
|
+
*
|
|
1998
|
+
* The request carries the registration token (read by the SDK from the
|
|
1999
|
+
* request-scoped custom storage) and the publishable key; the backend links
|
|
2000
|
+
* the customer to the publishable-key sales channel. A route that is
|
|
2001
|
+
* unavailable fails closed with a typed error — there is no silent native
|
|
2002
|
+
* fallback that would leave the customer unlinked.
|
|
2003
|
+
*/
|
|
2004
|
+
async createChannelLinkedCustomer(data) {
|
|
2005
|
+
const response = await this.fetchChannelAccountRoute(
|
|
2006
|
+
"/store/thor/customers",
|
|
2007
|
+
{
|
|
2008
|
+
method: "POST",
|
|
2009
|
+
body: {
|
|
2010
|
+
email: data.email,
|
|
2011
|
+
first_name: data.first_name,
|
|
2012
|
+
last_name: data.last_name,
|
|
2013
|
+
phone: data.phone
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
);
|
|
2017
|
+
const id = response?.customer?.id;
|
|
2018
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
2019
|
+
throw new ProviderAPIError(
|
|
2020
|
+
"Channel-linked customer creation returned no customer id.",
|
|
2021
|
+
"CUSTOMER_LINK_INCOMPLETE"
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
return { id };
|
|
2025
|
+
}
|
|
2026
|
+
/**
|
|
2027
|
+
* Link the authenticated customer to the publishable-key sales channel
|
|
2028
|
+
* through `POST /store/thor/customers/me/channels` (idempotent). Called after
|
|
2029
|
+
* login so history is channel-scoped for the current storefront.
|
|
2030
|
+
*/
|
|
2031
|
+
async linkCustomerChannel() {
|
|
2032
|
+
const response = await this.fetchChannelAccountRoute("/store/thor/customers/me/channels", { method: "POST" });
|
|
2033
|
+
if (response?.linked === false && response?.reason !== "already_linked") {
|
|
2034
|
+
throw new ProviderAPIError(
|
|
2035
|
+
"Customer channel link did not complete.",
|
|
2036
|
+
"CUSTOMER_LINK_INCOMPLETE"
|
|
2037
|
+
);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* Call a Thor channel account route through the SDK client, which attaches
|
|
2042
|
+
* the request-scoped customer/registration token and the publishable key. A
|
|
2043
|
+
* missing client or an unavailable route (404/405/501) fails closed with a
|
|
2044
|
+
* typed `CUSTOMER_LINK_UNAVAILABLE` error.
|
|
2045
|
+
*/
|
|
2046
|
+
async fetchChannelAccountRoute(path, init) {
|
|
2047
|
+
const client = this.sdk.client;
|
|
2048
|
+
if (!client || typeof client.fetch !== "function") {
|
|
2049
|
+
throw new ProviderAPIError(
|
|
2050
|
+
`The channel account route ${path} is unavailable in this SDK.`,
|
|
2051
|
+
"CUSTOMER_LINK_UNAVAILABLE"
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
try {
|
|
2055
|
+
return await client.fetch(path, init);
|
|
2056
|
+
} catch (error) {
|
|
2057
|
+
const status = error?.status || error?.statusCode;
|
|
2058
|
+
if (status === 404 || status === 405 || status === 501) {
|
|
2059
|
+
throw new ProviderAPIError(
|
|
2060
|
+
`The channel account route ${path} is unavailable (status ${status}).`,
|
|
2061
|
+
"CUSTOMER_LINK_UNAVAILABLE",
|
|
2062
|
+
status
|
|
2063
|
+
);
|
|
2064
|
+
}
|
|
2065
|
+
throw error;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
1981
2068
|
async logout() {
|
|
1982
2069
|
this.logger.debug("logout");
|
|
1983
2070
|
try {
|
|
@@ -2324,6 +2411,14 @@ async function getPaymentMethods(sdk, options) {
|
|
|
2324
2411
|
|
|
2325
2412
|
// src/providers/medusa/index.ts
|
|
2326
2413
|
var MEDUSA_CART_RETRIEVE_FIELDS = "+items,+items.variant,+items.variant.product,+items.variant.product.thumbnail,+items.variant.options,+items.variant.options.option,+items.total,+items.unit_price,+items.item_subtotal,+items.item_total,+shipping_methods,+shipping_methods.id,+shipping_methods.shipping_option_id";
|
|
2414
|
+
var CUSTOMER_ORDERS_DEFAULT_PAGE_SIZE = 10;
|
|
2415
|
+
var CUSTOMER_ORDERS_MAX_PAGE_SIZE = 100;
|
|
2416
|
+
function normalizeCustomerOrdersPage(options) {
|
|
2417
|
+
const page = Number.isInteger(options.page) && options.page > 0 ? options.page : 1;
|
|
2418
|
+
const requested = Number.isInteger(options.pageSize) && options.pageSize > 0 ? options.pageSize : CUSTOMER_ORDERS_DEFAULT_PAGE_SIZE;
|
|
2419
|
+
const pageSize = Math.min(requested, CUSTOMER_ORDERS_MAX_PAGE_SIZE);
|
|
2420
|
+
return { page, pageSize, limit: pageSize, offset: (page - 1) * pageSize };
|
|
2421
|
+
}
|
|
2327
2422
|
var MEDUSA_ORDER_COMPLETION_FIELDS = "*items";
|
|
2328
2423
|
var DEFAULT_CATALOG_PAGE_SIZE = 50;
|
|
2329
2424
|
function resolveCatalogPageSize(configured) {
|
|
@@ -2687,7 +2782,7 @@ var MedusaProvider = class {
|
|
|
2687
2782
|
}
|
|
2688
2783
|
/** Fields needed to price a product variant for the current region. */
|
|
2689
2784
|
buildProductFields(regionId) {
|
|
2690
|
-
const baseFields = "+variants,+variants.inventory_quantity,+options,+images,+tags";
|
|
2785
|
+
const baseFields = "+variants,+variants.inventory_quantity,+options,+images,+tags,+categories.*";
|
|
2691
2786
|
const pricingFields = ",+variants.calculated_price,+variants.prices";
|
|
2692
2787
|
return regionId ? baseFields + pricingFields : baseFields;
|
|
2693
2788
|
}
|
|
@@ -4245,13 +4340,17 @@ var MedusaProvider = class {
|
|
|
4245
4340
|
// Order Operations
|
|
4246
4341
|
// ============================================
|
|
4247
4342
|
/**
|
|
4248
|
-
* Get all orders for a customer (storefront).
|
|
4343
|
+
* Get all orders for a customer (storefront) as an array (legacy surface).
|
|
4249
4344
|
*
|
|
4250
|
-
*
|
|
4251
|
-
*
|
|
4345
|
+
* Delegates to the channel-scoped paginated contract
|
|
4346
|
+
* ({@link customerOrdersPage}) and returns that window's orders. The backend
|
|
4347
|
+
* (`GET /store/thor/orders`) scopes by BOTH the authenticated customer and
|
|
4348
|
+
* the sales channel resolved from the publishable key, so cross-channel
|
|
4349
|
+
* orders are excluded by the backend before pagination and **no client-side
|
|
4350
|
+
* channel filter runs**.
|
|
4252
4351
|
*
|
|
4253
|
-
* @param options - Order query options (supports
|
|
4254
|
-
* @returns Array of orders for the authenticated customer
|
|
4352
|
+
* @param options - Order query options (supports a custom fetcher)
|
|
4353
|
+
* @returns Array of orders for the authenticated customer on the store channel
|
|
4255
4354
|
*
|
|
4256
4355
|
* @example
|
|
4257
4356
|
* ```typescript
|
|
@@ -4265,32 +4364,68 @@ var MedusaProvider = class {
|
|
|
4265
4364
|
this.logger.debug("Using custom fetcher for orders");
|
|
4266
4365
|
return customFetcher(options);
|
|
4267
4366
|
}
|
|
4268
|
-
|
|
4367
|
+
const page = await this.customerOrdersPage({
|
|
4368
|
+
page: 1,
|
|
4369
|
+
pageSize: options.limit ?? CUSTOMER_ORDERS_MAX_PAGE_SIZE,
|
|
4370
|
+
salesChannelId
|
|
4371
|
+
});
|
|
4372
|
+
return page.orders;
|
|
4373
|
+
}
|
|
4374
|
+
/**
|
|
4375
|
+
* Channel-scoped, paginated order history for the authenticated customer.
|
|
4376
|
+
*
|
|
4377
|
+
* Calls the backend route `GET /store/thor/orders`, which requires the
|
|
4378
|
+
* customer session and scopes `order` by `customer_id` **and** the
|
|
4379
|
+
* `sales_channel_id` resolved from the publishable key, returning
|
|
4380
|
+
* `{ orders, count, limit, offset }` with the backend's real total computed
|
|
4381
|
+
* before pagination.
|
|
4382
|
+
*
|
|
4383
|
+
* The `salesChannelId` option is the store's explicitly configured channel.
|
|
4384
|
+
* When supplied, every returned order is asserted to belong to it; a
|
|
4385
|
+
* foreign-channel order (for example from a multi-channel publishable key that
|
|
4386
|
+
* silently resolved an arbitrary first id) fails closed with a typed error
|
|
4387
|
+
* rather than being presented as the customer's history.
|
|
4388
|
+
*
|
|
4389
|
+
* @param options - Bounded pagination window and the store's sales channel
|
|
4390
|
+
* @returns The backend's `{ orders, count, limit, offset }`
|
|
4391
|
+
*/
|
|
4392
|
+
async customerOrdersPage(options = {}) {
|
|
4393
|
+
const { page, pageSize, limit, offset } = normalizeCustomerOrdersPage(options);
|
|
4394
|
+
const { salesChannelId } = options;
|
|
4395
|
+
this.logger.info("Getting channel-scoped customer orders", { page, pageSize });
|
|
4269
4396
|
try {
|
|
4270
|
-
const
|
|
4271
|
-
async () => this.sdk.
|
|
4272
|
-
|
|
4273
|
-
|
|
4397
|
+
const response = await this.withRetry(
|
|
4398
|
+
async () => this.sdk.client.fetch("/store/thor/orders", {
|
|
4399
|
+
method: "GET",
|
|
4400
|
+
query: { limit, offset }
|
|
4274
4401
|
}),
|
|
4275
|
-
"
|
|
4402
|
+
"customerOrdersPage",
|
|
4276
4403
|
{}
|
|
4277
4404
|
);
|
|
4278
|
-
const
|
|
4279
|
-
this.logger.debug(`Found ${
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
const scoped = filterByChannel(transformed, channelId);
|
|
4284
|
-
this.logger.debug(
|
|
4285
|
-
`Channel scoping: ${scoped.length}/${transformed.length} orders match channel ${channelId}`
|
|
4405
|
+
const rawOrders = response.orders ?? [];
|
|
4406
|
+
this.logger.debug(`Found ${rawOrders.length} channel-scoped orders for customer`);
|
|
4407
|
+
if (salesChannelId) {
|
|
4408
|
+
const foreign = rawOrders.find(
|
|
4409
|
+
(order) => typeof order?.sales_channel_id === "string" && order.sales_channel_id !== salesChannelId
|
|
4286
4410
|
);
|
|
4287
|
-
|
|
4411
|
+
if (foreign) {
|
|
4412
|
+
throw new ProviderAPIError(
|
|
4413
|
+
`Channel-scoped order history returned an order outside the store's sales channel (${salesChannelId}).`,
|
|
4414
|
+
"medusa"
|
|
4415
|
+
);
|
|
4416
|
+
}
|
|
4288
4417
|
}
|
|
4289
|
-
return
|
|
4418
|
+
return {
|
|
4419
|
+
orders: rawOrders.map((order) => transformOrder(order)),
|
|
4420
|
+
count: typeof response.count === "number" ? response.count : rawOrders.length,
|
|
4421
|
+
limit: typeof response.limit === "number" ? response.limit : limit,
|
|
4422
|
+
offset: typeof response.offset === "number" ? response.offset : offset
|
|
4423
|
+
};
|
|
4290
4424
|
} catch (error) {
|
|
4425
|
+
if (error instanceof ProviderAPIError) throw error;
|
|
4291
4426
|
const status = error?.status || error?.statusCode;
|
|
4292
4427
|
const errorMessage = extractErrorMessage(error);
|
|
4293
|
-
this.logger.error("Error getting orders", { error: errorMessage });
|
|
4428
|
+
this.logger.error("Error getting channel-scoped orders", { error: errorMessage });
|
|
4294
4429
|
throw new ProviderAPIError(
|
|
4295
4430
|
`Failed to fetch orders: ${errorMessage}`,
|
|
4296
4431
|
"medusa",
|
|
@@ -9937,7 +10072,7 @@ var categoryFixtures = [
|
|
|
9937
10072
|
description: "Complementary products for cart and bundle flows."
|
|
9938
10073
|
}
|
|
9939
10074
|
];
|
|
9940
|
-
var
|
|
10075
|
+
var heroProductFixtures = [
|
|
9941
10076
|
{
|
|
9942
10077
|
id: "mock-product-aurora-jacket",
|
|
9943
10078
|
handle: "aurora-jacket",
|
|
@@ -10069,6 +10204,119 @@ var productFixtures = [
|
|
|
10069
10204
|
]
|
|
10070
10205
|
}
|
|
10071
10206
|
];
|
|
10207
|
+
var generatedBlueprints = [
|
|
10208
|
+
{
|
|
10209
|
+
categoryHandle: "jackets",
|
|
10210
|
+
noun: "Jacket",
|
|
10211
|
+
productType: "outerwear",
|
|
10212
|
+
vendor: "Thor Atelier",
|
|
10213
|
+
tags: ["outerwear", "layer"],
|
|
10214
|
+
variantName: "Size",
|
|
10215
|
+
variantValues: ["S", "M"],
|
|
10216
|
+
names: ["Alpine", "Boreal", "Cinder", "Drift", "Ember", "Fjord", "Harbor", "Meridian", "Nomad", "Tundra", "Vantage"],
|
|
10217
|
+
description: "A considered layering piece in a brushed weave.",
|
|
10218
|
+
basePrice: 118,
|
|
10219
|
+
baseHue: 210
|
|
10220
|
+
},
|
|
10221
|
+
{
|
|
10222
|
+
categoryHandle: "dresses",
|
|
10223
|
+
noun: "Dress",
|
|
10224
|
+
productType: "dress",
|
|
10225
|
+
vendor: "Thor Atelier",
|
|
10226
|
+
tags: ["dress", "editorial"],
|
|
10227
|
+
variantName: "Size",
|
|
10228
|
+
variantValues: ["S", "M"],
|
|
10229
|
+
names: ["Amber", "Camille", "Dahlia", "Elara", "Iris", "Lumen", "Nova", "Rosalind", "Vera"],
|
|
10230
|
+
description: "Cut from a fluid cloth for editorial styling.",
|
|
10231
|
+
basePrice: 142,
|
|
10232
|
+
baseHue: 330
|
|
10233
|
+
},
|
|
10234
|
+
{
|
|
10235
|
+
categoryHandle: "home",
|
|
10236
|
+
noun: "Lamp",
|
|
10237
|
+
productType: "decor",
|
|
10238
|
+
vendor: "Thor Home",
|
|
10239
|
+
tags: ["home", "decor", "interior"],
|
|
10240
|
+
variantName: "Finish",
|
|
10241
|
+
variantValues: ["Brass"],
|
|
10242
|
+
names: ["Atlas", "Copper", "Dune", "Onyx", "Quill", "Slate", "Terra", "Verdant"],
|
|
10243
|
+
description: "A calm sculptural accent for modern interiors.",
|
|
10244
|
+
basePrice: 74,
|
|
10245
|
+
baseHue: 40
|
|
10246
|
+
},
|
|
10247
|
+
{
|
|
10248
|
+
categoryHandle: "accessories",
|
|
10249
|
+
noun: "Bag",
|
|
10250
|
+
productType: "bag",
|
|
10251
|
+
vendor: "Thor Atelier",
|
|
10252
|
+
tags: ["accessory", "everyday"],
|
|
10253
|
+
variantName: "Color",
|
|
10254
|
+
variantValues: ["Juniper"],
|
|
10255
|
+
names: ["Cove", "Fable", "Juniper", "Kestrel", "Marlowe", "Piper", "Rune"],
|
|
10256
|
+
description: "An everyday carry with a textured finish.",
|
|
10257
|
+
basePrice: 68,
|
|
10258
|
+
baseHue: 280
|
|
10259
|
+
}
|
|
10260
|
+
];
|
|
10261
|
+
var GENERATED_CREATED_AT_BASE = Date.parse("2025-12-30T00:00:00.000Z");
|
|
10262
|
+
var GENERATED_COLLECTION_POOL = ["new-arrivals", "best-sellers", "studio-essentials"];
|
|
10263
|
+
function buildGeneratedProductFixtures() {
|
|
10264
|
+
const fixtures = [];
|
|
10265
|
+
let globalIndex = 0;
|
|
10266
|
+
for (const blueprint of generatedBlueprints) {
|
|
10267
|
+
const noun = blueprint.noun.toLowerCase();
|
|
10268
|
+
blueprint.names.forEach((name, localIndex) => {
|
|
10269
|
+
const handle = `${name.toLowerCase()}-${noun}`;
|
|
10270
|
+
const title = `${name} ${blueprint.noun}`;
|
|
10271
|
+
const price = blueprint.basePrice + localIndex * 7 + localIndex % 3 * 0.5;
|
|
10272
|
+
const quantityAvailable = globalIndex * 5 % 17;
|
|
10273
|
+
const primaryCollection = GENERATED_COLLECTION_POOL[globalIndex % GENERATED_COLLECTION_POOL.length];
|
|
10274
|
+
const collectionHandles = [primaryCollection];
|
|
10275
|
+
if (globalIndex % 5 === 0) {
|
|
10276
|
+
const secondary = GENERATED_COLLECTION_POOL[(globalIndex + 1) % GENERATED_COLLECTION_POOL.length];
|
|
10277
|
+
if (secondary !== primaryCollection) {
|
|
10278
|
+
collectionHandles.push(secondary);
|
|
10279
|
+
}
|
|
10280
|
+
}
|
|
10281
|
+
const createdAt = new Date(GENERATED_CREATED_AT_BASE - globalIndex * 864e5).toISOString();
|
|
10282
|
+
const variants = blueprint.variantValues.map((value, variantIndex) => ({
|
|
10283
|
+
id: `mock-variant-${handle}-${value.toLowerCase()}`,
|
|
10284
|
+
title: value,
|
|
10285
|
+
price,
|
|
10286
|
+
quantityAvailable: Math.max(0, quantityAvailable - variantIndex),
|
|
10287
|
+
selectedOptions: [{ name: blueprint.variantName, value }]
|
|
10288
|
+
}));
|
|
10289
|
+
fixtures.push({
|
|
10290
|
+
id: `mock-product-${handle}`,
|
|
10291
|
+
handle,
|
|
10292
|
+
title,
|
|
10293
|
+
description: `${title} - ${blueprint.description}`,
|
|
10294
|
+
imageLabel: title,
|
|
10295
|
+
imageHue: (blueprint.baseHue + localIndex * 13) % 360,
|
|
10296
|
+
collectionHandles,
|
|
10297
|
+
categoryHandle: blueprint.categoryHandle,
|
|
10298
|
+
productType: blueprint.productType,
|
|
10299
|
+
vendor: blueprint.vendor,
|
|
10300
|
+
tags: [...blueprint.tags],
|
|
10301
|
+
options: [
|
|
10302
|
+
{
|
|
10303
|
+
id: `${handle}-${blueprint.variantName.toLowerCase()}`,
|
|
10304
|
+
name: blueprint.variantName,
|
|
10305
|
+
values: [...blueprint.variantValues]
|
|
10306
|
+
}
|
|
10307
|
+
],
|
|
10308
|
+
variants,
|
|
10309
|
+
createdAt
|
|
10310
|
+
});
|
|
10311
|
+
globalIndex += 1;
|
|
10312
|
+
});
|
|
10313
|
+
}
|
|
10314
|
+
return fixtures;
|
|
10315
|
+
}
|
|
10316
|
+
var productFixtures = [
|
|
10317
|
+
...heroProductFixtures,
|
|
10318
|
+
...buildGeneratedProductFixtures()
|
|
10319
|
+
];
|
|
10072
10320
|
var stockLocationFixture = {
|
|
10073
10321
|
id: "mock-stock-primary",
|
|
10074
10322
|
name: "Mock Main Warehouse",
|
|
@@ -10185,6 +10433,20 @@ function buildProducts(currencyCode) {
|
|
|
10185
10433
|
title: collection.title,
|
|
10186
10434
|
handle: collection.handle
|
|
10187
10435
|
})),
|
|
10436
|
+
categories: (() => {
|
|
10437
|
+
const category = categoryFixtures.find(
|
|
10438
|
+
(item) => item.handle === product.categoryHandle
|
|
10439
|
+
);
|
|
10440
|
+
if (!category) return void 0;
|
|
10441
|
+
return [
|
|
10442
|
+
{
|
|
10443
|
+
id: category.id,
|
|
10444
|
+
name: category.name,
|
|
10445
|
+
handle: category.handle,
|
|
10446
|
+
parentCategoryId: category.parentCategoryId
|
|
10447
|
+
}
|
|
10448
|
+
];
|
|
10449
|
+
})(),
|
|
10188
10450
|
productType: product.productType,
|
|
10189
10451
|
vendor: product.vendor,
|
|
10190
10452
|
tags: product.tags,
|