@thorprovider/adapters 5.0.8 → 5.0.9
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 +41 -2
- package/dist/index.d.ts +41 -2
- package/dist/index.js +152 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -33
- package/dist/index.mjs.map +1 -1
- package/docs/multi-tenant-channel-scoping.md +42 -4
- package/package.json +2 -2
- package/src/providers/medusa/index.test.ts +40 -0
- package/src/providers/medusa/index.ts +173 -36
- package/src/providers/medusa/transforms.ts +21 -13
package/dist/index.d.mts
CHANGED
|
@@ -1501,6 +1501,7 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1501
1501
|
private retryConfig;
|
|
1502
1502
|
private baseUrl;
|
|
1503
1503
|
private publishableKey;
|
|
1504
|
+
private regionId?;
|
|
1504
1505
|
/** Secret API key for admin operations (if configured). */
|
|
1505
1506
|
private adminApiKey?;
|
|
1506
1507
|
/**
|
|
@@ -1599,6 +1600,28 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1599
1600
|
private mapAttributeTypeToFilterType;
|
|
1600
1601
|
getCollection(handle: string): Promise<Collection | undefined>;
|
|
1601
1602
|
getCollections(options?: GetCollectionsOptions): Promise<Collection[]>;
|
|
1603
|
+
/**
|
|
1604
|
+
* Returns the set of product-collection IDs that have at least one product
|
|
1605
|
+
* available in the given sales channel (legacy fallback).
|
|
1606
|
+
*
|
|
1607
|
+
* @deprecated Use `_getChannelCollections()` instead (backed by Thor Commerce plugin).
|
|
1608
|
+
*/
|
|
1609
|
+
private _getActiveCollectionIds;
|
|
1610
|
+
/**
|
|
1611
|
+
* Fetch channel-scoped collections from Thor Commerce plugin.
|
|
1612
|
+
* Uses `GET /store/thor/collections` — the endpoint resolves the sales
|
|
1613
|
+
* channel from the publishable key header itself.
|
|
1614
|
+
*
|
|
1615
|
+
* Falls back to `_getActiveCollectionIds()` (legacy N+1) when the plugin is
|
|
1616
|
+
* not available; the legacy fallback needs an explicit `salesChannelId`.
|
|
1617
|
+
* Returns `null` when no scoping could be performed.
|
|
1618
|
+
*/
|
|
1619
|
+
private _getChannelCollections;
|
|
1620
|
+
/**
|
|
1621
|
+
* Legacy fallback for `_getChannelCollections()` when the Thor plugin is not
|
|
1622
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
1623
|
+
*/
|
|
1624
|
+
private _legacyChannelCollections;
|
|
1602
1625
|
getCollectionProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]>;
|
|
1603
1626
|
getCategory(idOrHandle: string): Promise<ProductCategory | undefined>;
|
|
1604
1627
|
/**
|
|
@@ -1617,14 +1640,30 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1617
1640
|
private _getActiveCategoryIds;
|
|
1618
1641
|
/**
|
|
1619
1642
|
* Fetch channel-scoped categories from Thor Commerce plugin.
|
|
1620
|
-
* Uses `GET /store/thor/categories` — a single indexed query.
|
|
1621
|
-
*
|
|
1643
|
+
* Uses `GET /store/thor/categories` — a single indexed query. The endpoint
|
|
1644
|
+
* resolves the sales channel from the publishable key header itself, so no
|
|
1645
|
+
* explicit channel id is required when the plugin is installed.
|
|
1646
|
+
*
|
|
1647
|
+
* Falls back to `_getActiveCategoryIds()` (legacy N+1) when the plugin is
|
|
1648
|
+
* not available. The legacy fallback needs an explicit `salesChannelId`;
|
|
1649
|
+
* when none is provided and the plugin is unavailable, returns `null` to
|
|
1650
|
+
* signal that scoping is not possible and the caller should skip filtering.
|
|
1651
|
+
*
|
|
1652
|
+
* @param salesChannelId - Only used by the legacy fallback (plugin absent).
|
|
1653
|
+
* @returns Set of category IDs active in the channel, or `null` when no
|
|
1654
|
+
* scoping could be performed.
|
|
1622
1655
|
*/
|
|
1623
1656
|
private _getChannelCategories;
|
|
1657
|
+
/**
|
|
1658
|
+
* Legacy fallback for `_getChannelCategories()` when the Thor plugin is not
|
|
1659
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
1660
|
+
*/
|
|
1661
|
+
private _legacyChannelCategories;
|
|
1624
1662
|
getCategories(options?: GetCategoriesOptions): Promise<ProductCategory[]>;
|
|
1625
1663
|
getCategoryProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]>;
|
|
1626
1664
|
createCart(options?: {
|
|
1627
1665
|
regionId?: string;
|
|
1666
|
+
salesChannelId?: string;
|
|
1628
1667
|
}): Promise<Cart>;
|
|
1629
1668
|
getCart(cartId: string): Promise<Cart | undefined>;
|
|
1630
1669
|
addToCart(cartId: string, lines: CartLineInput[]): Promise<Cart>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1501,6 +1501,7 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1501
1501
|
private retryConfig;
|
|
1502
1502
|
private baseUrl;
|
|
1503
1503
|
private publishableKey;
|
|
1504
|
+
private regionId?;
|
|
1504
1505
|
/** Secret API key for admin operations (if configured). */
|
|
1505
1506
|
private adminApiKey?;
|
|
1506
1507
|
/**
|
|
@@ -1599,6 +1600,28 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1599
1600
|
private mapAttributeTypeToFilterType;
|
|
1600
1601
|
getCollection(handle: string): Promise<Collection | undefined>;
|
|
1601
1602
|
getCollections(options?: GetCollectionsOptions): Promise<Collection[]>;
|
|
1603
|
+
/**
|
|
1604
|
+
* Returns the set of product-collection IDs that have at least one product
|
|
1605
|
+
* available in the given sales channel (legacy fallback).
|
|
1606
|
+
*
|
|
1607
|
+
* @deprecated Use `_getChannelCollections()` instead (backed by Thor Commerce plugin).
|
|
1608
|
+
*/
|
|
1609
|
+
private _getActiveCollectionIds;
|
|
1610
|
+
/**
|
|
1611
|
+
* Fetch channel-scoped collections from Thor Commerce plugin.
|
|
1612
|
+
* Uses `GET /store/thor/collections` — the endpoint resolves the sales
|
|
1613
|
+
* channel from the publishable key header itself.
|
|
1614
|
+
*
|
|
1615
|
+
* Falls back to `_getActiveCollectionIds()` (legacy N+1) when the plugin is
|
|
1616
|
+
* not available; the legacy fallback needs an explicit `salesChannelId`.
|
|
1617
|
+
* Returns `null` when no scoping could be performed.
|
|
1618
|
+
*/
|
|
1619
|
+
private _getChannelCollections;
|
|
1620
|
+
/**
|
|
1621
|
+
* Legacy fallback for `_getChannelCollections()` when the Thor plugin is not
|
|
1622
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
1623
|
+
*/
|
|
1624
|
+
private _legacyChannelCollections;
|
|
1602
1625
|
getCollectionProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]>;
|
|
1603
1626
|
getCategory(idOrHandle: string): Promise<ProductCategory | undefined>;
|
|
1604
1627
|
/**
|
|
@@ -1617,14 +1640,30 @@ declare class MedusaProvider implements CommerceProvider {
|
|
|
1617
1640
|
private _getActiveCategoryIds;
|
|
1618
1641
|
/**
|
|
1619
1642
|
* Fetch channel-scoped categories from Thor Commerce plugin.
|
|
1620
|
-
* Uses `GET /store/thor/categories` — a single indexed query.
|
|
1621
|
-
*
|
|
1643
|
+
* Uses `GET /store/thor/categories` — a single indexed query. The endpoint
|
|
1644
|
+
* resolves the sales channel from the publishable key header itself, so no
|
|
1645
|
+
* explicit channel id is required when the plugin is installed.
|
|
1646
|
+
*
|
|
1647
|
+
* Falls back to `_getActiveCategoryIds()` (legacy N+1) when the plugin is
|
|
1648
|
+
* not available. The legacy fallback needs an explicit `salesChannelId`;
|
|
1649
|
+
* when none is provided and the plugin is unavailable, returns `null` to
|
|
1650
|
+
* signal that scoping is not possible and the caller should skip filtering.
|
|
1651
|
+
*
|
|
1652
|
+
* @param salesChannelId - Only used by the legacy fallback (plugin absent).
|
|
1653
|
+
* @returns Set of category IDs active in the channel, or `null` when no
|
|
1654
|
+
* scoping could be performed.
|
|
1622
1655
|
*/
|
|
1623
1656
|
private _getChannelCategories;
|
|
1657
|
+
/**
|
|
1658
|
+
* Legacy fallback for `_getChannelCategories()` when the Thor plugin is not
|
|
1659
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
1660
|
+
*/
|
|
1661
|
+
private _legacyChannelCategories;
|
|
1624
1662
|
getCategories(options?: GetCategoriesOptions): Promise<ProductCategory[]>;
|
|
1625
1663
|
getCategoryProducts(handle: string, options?: CollectionProductsOptions): Promise<Product[]>;
|
|
1626
1664
|
createCart(options?: {
|
|
1627
1665
|
regionId?: string;
|
|
1666
|
+
salesChannelId?: string;
|
|
1628
1667
|
}): Promise<Cart>;
|
|
1629
1668
|
getCart(cartId: string): Promise<Cart | undefined>;
|
|
1630
1669
|
addToCart(cartId: string, lines: CartLineInput[]): Promise<Cart>;
|
package/dist/index.js
CHANGED
|
@@ -1154,6 +1154,12 @@ function transformCartItem(item, cartCurrencyCode) {
|
|
|
1154
1154
|
const product = variant?.product;
|
|
1155
1155
|
const currencyCode = resolveMedusaCartItemCurrencyCode(item, cartCurrencyCode);
|
|
1156
1156
|
const totalCents = resolveMedusaCartItemTotal(item);
|
|
1157
|
+
const merchandiseId = variant?.id ?? item.variant_id ?? "";
|
|
1158
|
+
const merchandiseTitle = variant?.title ?? item.variant_title ?? "";
|
|
1159
|
+
const productId = product?.id ?? item.product_id ?? "";
|
|
1160
|
+
const productHandle = product?.handle ?? item.product_handle ?? "";
|
|
1161
|
+
const productTitle = product?.title ?? item.product_title ?? "";
|
|
1162
|
+
const thumbnail = product?.thumbnail ?? item.thumbnail ?? "";
|
|
1157
1163
|
return {
|
|
1158
1164
|
id: item.id,
|
|
1159
1165
|
quantity: item.quantity ?? 1,
|
|
@@ -1161,17 +1167,17 @@ function transformCartItem(item, cartCurrencyCode) {
|
|
|
1161
1167
|
totalAmount: transformMoney(totalCents, currencyCode)
|
|
1162
1168
|
},
|
|
1163
1169
|
merchandise: {
|
|
1164
|
-
id:
|
|
1165
|
-
title:
|
|
1170
|
+
id: merchandiseId,
|
|
1171
|
+
title: merchandiseTitle,
|
|
1166
1172
|
selectedOptions: variant?.options?.map((opt) => ({
|
|
1167
1173
|
name: opt.option?.title ?? "",
|
|
1168
1174
|
value: opt.value ?? ""
|
|
1169
1175
|
})) ?? [],
|
|
1170
1176
|
product: {
|
|
1171
|
-
id:
|
|
1172
|
-
handle:
|
|
1173
|
-
title:
|
|
1174
|
-
featuredImage:
|
|
1177
|
+
id: productId,
|
|
1178
|
+
handle: productHandle,
|
|
1179
|
+
title: productTitle,
|
|
1180
|
+
featuredImage: thumbnail ? transformImage(thumbnail, productTitle) : transformImage("", "")
|
|
1175
1181
|
}
|
|
1176
1182
|
}
|
|
1177
1183
|
};
|
|
@@ -2308,6 +2314,7 @@ var MedusaProvider = class {
|
|
|
2308
2314
|
retryConfig;
|
|
2309
2315
|
baseUrl;
|
|
2310
2316
|
publishableKey;
|
|
2317
|
+
regionId;
|
|
2311
2318
|
/** Secret API key for admin operations (if configured). */
|
|
2312
2319
|
adminApiKey;
|
|
2313
2320
|
/**
|
|
@@ -2351,6 +2358,7 @@ var MedusaProvider = class {
|
|
|
2351
2358
|
this.currencyCode = config.currencyCode ?? "USD";
|
|
2352
2359
|
this.baseUrl = config.baseUrl;
|
|
2353
2360
|
this.publishableKey = config.publishableKey;
|
|
2361
|
+
this.regionId = config.regionId;
|
|
2354
2362
|
this.retryConfig = {
|
|
2355
2363
|
maxRetries: config.retry?.maxRetries ?? 3,
|
|
2356
2364
|
timeoutMs: config.retry?.timeoutMs ?? 1e4,
|
|
@@ -2485,16 +2493,17 @@ var MedusaProvider = class {
|
|
|
2485
2493
|
try {
|
|
2486
2494
|
return await this.withRetry(
|
|
2487
2495
|
async () => {
|
|
2496
|
+
const regionId = options?.regionId ?? this.regionId;
|
|
2488
2497
|
const baseFields = "+variants,+variants.inventory_quantity,+options,+images,+tags";
|
|
2489
2498
|
const pricingFields = ",+variants.calculated_price,+variants.prices";
|
|
2490
|
-
const fields =
|
|
2499
|
+
const fields = regionId ? baseFields + pricingFields : baseFields;
|
|
2491
2500
|
const queryParams = {
|
|
2492
2501
|
handle,
|
|
2493
2502
|
limit: 1,
|
|
2494
2503
|
fields
|
|
2495
2504
|
};
|
|
2496
|
-
if (
|
|
2497
|
-
queryParams.region_id =
|
|
2505
|
+
if (regionId) {
|
|
2506
|
+
queryParams.region_id = regionId;
|
|
2498
2507
|
}
|
|
2499
2508
|
const salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
|
|
2500
2509
|
if (salesChannelId) {
|
|
@@ -2524,9 +2533,10 @@ var MedusaProvider = class {
|
|
|
2524
2533
|
try {
|
|
2525
2534
|
return await this.withRetry(
|
|
2526
2535
|
async () => {
|
|
2536
|
+
const regionId = options.regionId ?? this.regionId;
|
|
2527
2537
|
const baseFields = "+variants,+variants.inventory_quantity,+options,+images,+tags";
|
|
2528
2538
|
const pricingFields = ",+variants.calculated_price,+variants.prices";
|
|
2529
|
-
const fields =
|
|
2539
|
+
const fields = regionId ? baseFields + pricingFields : baseFields;
|
|
2530
2540
|
const SORT_KEY_MAP = {
|
|
2531
2541
|
featured: null,
|
|
2532
2542
|
// server default order
|
|
@@ -2553,8 +2563,8 @@ var MedusaProvider = class {
|
|
|
2553
2563
|
queryParams.order = mappedOrder;
|
|
2554
2564
|
}
|
|
2555
2565
|
}
|
|
2556
|
-
if (
|
|
2557
|
-
queryParams.region_id =
|
|
2566
|
+
if (regionId) {
|
|
2567
|
+
queryParams.region_id = regionId;
|
|
2558
2568
|
}
|
|
2559
2569
|
if (options.categoryIds && options.categoryIds.length > 0) {
|
|
2560
2570
|
queryParams.category_id = options.categoryIds;
|
|
@@ -2947,6 +2957,11 @@ var MedusaProvider = class {
|
|
|
2947
2957
|
limit
|
|
2948
2958
|
});
|
|
2949
2959
|
let result = collections.map(transformCollection);
|
|
2960
|
+
const salesChannelId = options?.salesChannelId ?? process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
|
|
2961
|
+
const activeCollectionIds = await this._getChannelCollections(salesChannelId);
|
|
2962
|
+
if (activeCollectionIds) {
|
|
2963
|
+
result = result.filter((c) => activeCollectionIds.has(c.id));
|
|
2964
|
+
}
|
|
2950
2965
|
if (options?.query) {
|
|
2951
2966
|
const q = options.query.toLowerCase();
|
|
2952
2967
|
result = result.filter(
|
|
@@ -2963,6 +2978,89 @@ var MedusaProvider = class {
|
|
|
2963
2978
|
);
|
|
2964
2979
|
}
|
|
2965
2980
|
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Returns the set of product-collection IDs that have at least one product
|
|
2983
|
+
* available in the given sales channel (legacy fallback).
|
|
2984
|
+
*
|
|
2985
|
+
* @deprecated Use `_getChannelCollections()` instead (backed by Thor Commerce plugin).
|
|
2986
|
+
*/
|
|
2987
|
+
async _getActiveCollectionIds(salesChannelId) {
|
|
2988
|
+
this.logger.debug("_getActiveCollectionIds", { salesChannelId });
|
|
2989
|
+
const collectionIds = /* @__PURE__ */ new Set();
|
|
2990
|
+
const limit = 500;
|
|
2991
|
+
let offset = 0;
|
|
2992
|
+
while (true) {
|
|
2993
|
+
const { products } = await this.sdk.store.product.list({
|
|
2994
|
+
sales_channel_id: [salesChannelId],
|
|
2995
|
+
fields: "+collections.id",
|
|
2996
|
+
limit,
|
|
2997
|
+
offset
|
|
2998
|
+
});
|
|
2999
|
+
for (const product of products ?? []) {
|
|
3000
|
+
for (const col of product.collections ?? []) {
|
|
3001
|
+
if (col?.id) collectionIds.add(col.id);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
if (!products || products.length < limit) break;
|
|
3005
|
+
offset += limit;
|
|
3006
|
+
}
|
|
3007
|
+
this.logger.debug("_getActiveCollectionIds result", { count: collectionIds.size });
|
|
3008
|
+
return collectionIds;
|
|
3009
|
+
}
|
|
3010
|
+
/**
|
|
3011
|
+
* Fetch channel-scoped collections from Thor Commerce plugin.
|
|
3012
|
+
* Uses `GET /store/thor/collections` — the endpoint resolves the sales
|
|
3013
|
+
* channel from the publishable key header itself.
|
|
3014
|
+
*
|
|
3015
|
+
* Falls back to `_getActiveCollectionIds()` (legacy N+1) when the plugin is
|
|
3016
|
+
* not available; the legacy fallback needs an explicit `salesChannelId`.
|
|
3017
|
+
* Returns `null` when no scoping could be performed.
|
|
3018
|
+
*/
|
|
3019
|
+
async _getChannelCollections(salesChannelId) {
|
|
3020
|
+
try {
|
|
3021
|
+
const url = `${this.baseUrl}/store/thor/collections`;
|
|
3022
|
+
const response = await fetchWithRetry(
|
|
3023
|
+
url,
|
|
3024
|
+
{
|
|
3025
|
+
method: "GET",
|
|
3026
|
+
headers: {
|
|
3027
|
+
"x-publishable-api-key": this.publishableKey,
|
|
3028
|
+
"Content-Type": "application/json"
|
|
3029
|
+
}
|
|
3030
|
+
},
|
|
3031
|
+
this.retryConfig
|
|
3032
|
+
);
|
|
3033
|
+
if (response.status === 404 || !response.ok) {
|
|
3034
|
+
this.logger.debug("Thor plugin collections endpoint unavailable, falling back to legacy method");
|
|
3035
|
+
return this._legacyChannelCollections(salesChannelId);
|
|
3036
|
+
}
|
|
3037
|
+
const data = await response.json();
|
|
3038
|
+
const collectionIds = /* @__PURE__ */ new Set();
|
|
3039
|
+
for (const col of data.collections ?? []) {
|
|
3040
|
+
if (col?.id) collectionIds.add(col.id);
|
|
3041
|
+
}
|
|
3042
|
+
this.logger.debug("_getChannelCollections result (Thor plugin)", { count: collectionIds.size });
|
|
3043
|
+
return collectionIds;
|
|
3044
|
+
} catch (error) {
|
|
3045
|
+
this.logger.warn("Failed to fetch channel collections from Thor plugin, falling back to legacy method", {
|
|
3046
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3047
|
+
});
|
|
3048
|
+
return this._legacyChannelCollections(salesChannelId);
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
/**
|
|
3052
|
+
* Legacy fallback for `_getChannelCollections()` when the Thor plugin is not
|
|
3053
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
3054
|
+
*/
|
|
3055
|
+
async _legacyChannelCollections(salesChannelId) {
|
|
3056
|
+
if (!salesChannelId) {
|
|
3057
|
+
this.logger.warn(
|
|
3058
|
+
"Cannot scope collections: Thor plugin unavailable and no sales channel id provided; returning unscoped collections"
|
|
3059
|
+
);
|
|
3060
|
+
return null;
|
|
3061
|
+
}
|
|
3062
|
+
return this._getActiveCollectionIds(salesChannelId);
|
|
3063
|
+
}
|
|
2966
3064
|
async getCollectionProducts(handle, options = {}) {
|
|
2967
3065
|
this.logger.debug("getCollectionProducts", { handle, options });
|
|
2968
3066
|
try {
|
|
@@ -3057,8 +3155,18 @@ var MedusaProvider = class {
|
|
|
3057
3155
|
}
|
|
3058
3156
|
/**
|
|
3059
3157
|
* Fetch channel-scoped categories from Thor Commerce plugin.
|
|
3060
|
-
* Uses `GET /store/thor/categories` — a single indexed query.
|
|
3061
|
-
*
|
|
3158
|
+
* Uses `GET /store/thor/categories` — a single indexed query. The endpoint
|
|
3159
|
+
* resolves the sales channel from the publishable key header itself, so no
|
|
3160
|
+
* explicit channel id is required when the plugin is installed.
|
|
3161
|
+
*
|
|
3162
|
+
* Falls back to `_getActiveCategoryIds()` (legacy N+1) when the plugin is
|
|
3163
|
+
* not available. The legacy fallback needs an explicit `salesChannelId`;
|
|
3164
|
+
* when none is provided and the plugin is unavailable, returns `null` to
|
|
3165
|
+
* signal that scoping is not possible and the caller should skip filtering.
|
|
3166
|
+
*
|
|
3167
|
+
* @param salesChannelId - Only used by the legacy fallback (plugin absent).
|
|
3168
|
+
* @returns Set of category IDs active in the channel, or `null` when no
|
|
3169
|
+
* scoping could be performed.
|
|
3062
3170
|
*/
|
|
3063
3171
|
async _getChannelCategories(salesChannelId) {
|
|
3064
3172
|
try {
|
|
@@ -3074,15 +3182,9 @@ var MedusaProvider = class {
|
|
|
3074
3182
|
},
|
|
3075
3183
|
this.retryConfig
|
|
3076
3184
|
);
|
|
3077
|
-
if (response.status === 404) {
|
|
3078
|
-
this.logger.debug("Thor plugin categories endpoint
|
|
3079
|
-
return this.
|
|
3080
|
-
}
|
|
3081
|
-
if (!response.ok) {
|
|
3082
|
-
this.logger.warn("Thor plugin categories endpoint returned non-OK status", {
|
|
3083
|
-
status: response.status
|
|
3084
|
-
});
|
|
3085
|
-
return this._getActiveCategoryIds(salesChannelId);
|
|
3185
|
+
if (response.status === 404 || !response.ok) {
|
|
3186
|
+
this.logger.debug("Thor plugin categories endpoint unavailable, falling back to legacy method");
|
|
3187
|
+
return this._legacyChannelCategories(salesChannelId);
|
|
3086
3188
|
}
|
|
3087
3189
|
const data = await response.json();
|
|
3088
3190
|
const categoryIds = /* @__PURE__ */ new Set();
|
|
@@ -3095,8 +3197,21 @@ var MedusaProvider = class {
|
|
|
3095
3197
|
this.logger.warn("Failed to fetch channel categories from Thor plugin, falling back to legacy method", {
|
|
3096
3198
|
error: error instanceof Error ? error.message : String(error)
|
|
3097
3199
|
});
|
|
3098
|
-
return this.
|
|
3200
|
+
return this._legacyChannelCategories(salesChannelId);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
/**
|
|
3204
|
+
* Legacy fallback for `_getChannelCategories()` when the Thor plugin is not
|
|
3205
|
+
* installed. Requires an explicit `salesChannelId`; returns `null` otherwise.
|
|
3206
|
+
*/
|
|
3207
|
+
async _legacyChannelCategories(salesChannelId) {
|
|
3208
|
+
if (!salesChannelId) {
|
|
3209
|
+
this.logger.warn(
|
|
3210
|
+
"Cannot scope categories: Thor plugin unavailable and no sales channel id provided; returning unscoped categories"
|
|
3211
|
+
);
|
|
3212
|
+
return null;
|
|
3099
3213
|
}
|
|
3214
|
+
return this._getActiveCategoryIds(salesChannelId);
|
|
3100
3215
|
}
|
|
3101
3216
|
async getCategories(options = {}) {
|
|
3102
3217
|
this.logger.debug("getCategories", { options });
|
|
@@ -3117,8 +3232,8 @@ var MedusaProvider = class {
|
|
|
3117
3232
|
const { product_categories } = await this.sdk.store.category.list(queryParams);
|
|
3118
3233
|
let result = product_categories.map(transformCategory);
|
|
3119
3234
|
const salesChannelId = options.salesChannelId ?? process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
|
|
3120
|
-
|
|
3121
|
-
|
|
3235
|
+
const activeCategoryIds = await this._getChannelCategories(salesChannelId);
|
|
3236
|
+
if (activeCategoryIds) {
|
|
3122
3237
|
result = result.filter((c) => activeCategoryIds.has(c.id));
|
|
3123
3238
|
}
|
|
3124
3239
|
if (options.query) {
|
|
@@ -3151,6 +3266,9 @@ var MedusaProvider = class {
|
|
|
3151
3266
|
offset: options.after ? parseInt(options.after, 10) : void 0,
|
|
3152
3267
|
fields: "+variants,+variants.prices,+variants.calculated_prices,+variants.inventory_quantity,+options,+images,+tags"
|
|
3153
3268
|
};
|
|
3269
|
+
if (this.regionId) {
|
|
3270
|
+
categoryQueryParams.region_id = this.regionId;
|
|
3271
|
+
}
|
|
3154
3272
|
const salesChannelId = process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
|
|
3155
3273
|
if (salesChannelId) {
|
|
3156
3274
|
categoryQueryParams.sales_channel_id = [salesChannelId];
|
|
@@ -3171,7 +3289,10 @@ var MedusaProvider = class {
|
|
|
3171
3289
|
// Cart Operations
|
|
3172
3290
|
// ============================================
|
|
3173
3291
|
async createCart(options) {
|
|
3174
|
-
this.logger.debug("createCart", {
|
|
3292
|
+
this.logger.debug("createCart", {
|
|
3293
|
+
regionId: options?.regionId,
|
|
3294
|
+
salesChannelId: options?.salesChannelId
|
|
3295
|
+
});
|
|
3175
3296
|
try {
|
|
3176
3297
|
const createPayload = {};
|
|
3177
3298
|
if (options?.regionId) {
|
|
@@ -3179,6 +3300,10 @@ var MedusaProvider = class {
|
|
|
3179
3300
|
} else {
|
|
3180
3301
|
createPayload.currency_code = this.currencyCode.toLowerCase();
|
|
3181
3302
|
}
|
|
3303
|
+
const salesChannelId = options?.salesChannelId ?? process.env.NEXT_PUBLIC_SALES_CHANNEL_ID;
|
|
3304
|
+
if (salesChannelId) {
|
|
3305
|
+
createPayload.sales_channel_id = salesChannelId;
|
|
3306
|
+
}
|
|
3182
3307
|
const { cart } = await this.sdk.store.cart.create(createPayload);
|
|
3183
3308
|
return transformCart(cart);
|
|
3184
3309
|
} catch (error) {
|
|
@@ -3220,13 +3345,11 @@ var MedusaProvider = class {
|
|
|
3220
3345
|
"retrieveCartBeforeAdd",
|
|
3221
3346
|
retrieveCtx
|
|
3222
3347
|
);
|
|
3223
|
-
console.log("retrieveResult =", JSON.stringify(retrieveResult, null, 2));
|
|
3224
3348
|
const backendCart = retrieveResult?.cart;
|
|
3225
3349
|
if (!backendCart) {
|
|
3226
3350
|
this.logger.warn("Cart not found before addToCart", { cartId });
|
|
3227
3351
|
throw new ProviderAPIError("Cart not found. Please refresh and try again.", "medusa", 404);
|
|
3228
3352
|
}
|
|
3229
|
-
console.log("backendCart =", JSON.stringify(backendCart, null, 2));
|
|
3230
3353
|
if (!backendCart.region_id) {
|
|
3231
3354
|
this.logger.warn("Attempted to add item to cart with no region_id", { cartId });
|
|
3232
3355
|
throw new ProviderAPIError(
|
|
@@ -3275,15 +3398,11 @@ var MedusaProvider = class {
|
|
|
3275
3398
|
404
|
|
3276
3399
|
);
|
|
3277
3400
|
}
|
|
3278
|
-
console.log("Found Variant:", JSON.stringify(foundVariant, null, 2));
|
|
3279
3401
|
const variant = foundVariant;
|
|
3280
3402
|
let hasPriceForRegion = false;
|
|
3281
3403
|
if (variant?.calculated_price && (variant.calculated_price.calculated_amount ?? null) !== null) {
|
|
3282
3404
|
const calcCurrency = (variant.calculated_price.currency_code || "").toLowerCase();
|
|
3283
3405
|
const cartCurrency = (backendCart.currency_code || this.currencyCode || "").toLowerCase();
|
|
3284
|
-
console.log("calcCurrency =", calcCurrency);
|
|
3285
|
-
console.log("cartCurrency =", cartCurrency);
|
|
3286
|
-
console.log("this.currencyCode =", this.currencyCode);
|
|
3287
3406
|
if (!cartCurrency || calcCurrency === cartCurrency || calcCurrency === this.currencyCode.toLowerCase()) {
|
|
3288
3407
|
hasPriceForRegion = true;
|
|
3289
3408
|
}
|