@thorprovider/medusa-extended 1.2.1 → 1.2.2

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/README.md CHANGED
@@ -85,6 +85,8 @@ POST /auth/user/emailpass
85
85
  | `getProducts(options?)` | `GET /admin/thor/dropshipper/products` |
86
86
  | `updatePrices(body)` | `PUT /admin/thor/dropshipper/prices` |
87
87
 
88
+ Business rule note: product visibility is not global in multitenant dropshipping. A product can appear in multiple dropshipper channels, and visibility must be scoped per channel/tenant. Do not use a product-wide status change to hide a product for all dropshippers unless the implementation explicitly intends global catalog behavior.
89
+
88
90
  #### Orders (Y + X for set-payment-collector)
89
91
 
90
92
  | Method | Endpoint |
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetChannelCustomersOptions, GetChannelCustomersResponse, GetChannelApiKeysResponse, GetChannelCategoriesOptions, GetChannelCategoriesResponse, GetCategorySalesChannelsResponse, AssignCategoriesToChannelsBody, AssignCategoriesToChannelsResponse, UnassignCategoriesFromChannelsBody, UnassignCategoriesFromChannelsResponse, GetCollectionSalesChannelsResponse, AssignCollectionsToChannelsBody, AssignCollectionsToChannelsResponse, UnassignCollectionsFromChannelsBody, UnassignCollectionsFromChannelsResponse, GetAdminStorefrontConfigResponse, UpdateStorefrontConfigBody, UpdateStorefrontConfigResponse, GetAdminSiteConfigResponse, UpdateSiteConfigBody, UpdateSiteConfigResponse, GetAdminSiteConfigHistoryOptions, GetAdminSiteConfigHistoryResponse, RestoreSiteConfigResponse, OnboardDropshipperBody, OnboardDropshipperResponse, GetVariantCostsOptions, GetVariantCostsResponse, CreateVariantCostBody, CreateVariantCostResponse, BatchVariantCostsBody, BatchVariantCostsResponse, DeleteVariantCostResponse, GetDropshipperProductsOptions, GetDropshipperProductsResponse, UpdateDropshipperPricesBody, UpdateDropshipperPricesResponse, GetDropshipperOrdersOptions, GetDropshipperOrdersResponse, GetDropshipperOrderDetailResponse, GetDropshipperShippingOptionsParams, GetDropshipperShippingOptionsResponse, ExtendedCreateDropshipperOrderBody, ExtendedCreateDropshipperOrderResponse, SetPaymentCollectorBody, SetPaymentCollectorResponse, CancelDropshipperOrderResponse, CreateOrderEditBody, CreateOrderEditResponse, AddOrderEditItemBody, AddOrderEditItemResponse, ConfirmOrderEditResponse, GetOrderNotesResponse, CreateOrderNoteBody, OrderNote, DeleteOrderNoteResponse, GetProviderCategoriesResponse, GetDropshipperCategoriesOptions, GetDropshipperCategoriesResponse, CreateDropshipperCategoryBody, DropshipperCategory, UpdateDropshipperCategoryBody, DeleteDropshipperCategoryResponse, GetCategoryMappingsOptions, GetCategoryMappingsResponse, CreateCategoryMappingBody, CreateCategoryMappingResponse, DeleteCategoryMappingResponse, GetDropshipperCustomersOptions, GetDropshipperCustomersResponse, GetDropshipperCustomerDetailResponse, CreateDropshipperCustomerBody, CreateDropshipperCustomerResponse, GetDropshipperAddressesResponse, DropshipperAddressBody, DropshipperAddressResponse, GetDropshipperAccountResponse, GetDropshipperPayableResponse, GetDropshipperReceivableResponse, GetSettlementsOptions, GetSettlementsResponse, GetSettlementDetailResponse, CreateSettlementBody, CreateSettlementResponse, ConfirmSettlementBody, UpdateSettlementStatusResponse, CancelSettlementBody, GetAdminDropshipperAccountsResponse, GetAdminAccountBalanceResponse, GetAdminPriceListsResponse, GetUserChannelResponse, GetDropshipperPromotionsOptions, GetDropshipperPromotionsResponse, CreateDropshipperPromotionBody, DropshipperPromotion, UpdateDropshipperPromotionBody, DeleteDropshipperPromotionResponse, GetDashboardStatsOptions, GetDashboardStatsResponse, GetStorefrontDropshipperCategoriesResponse } from '@thorprovider/types';
1
+ import { GetChannelCustomersOptions, GetChannelCustomersResponse, GetChannelApiKeysResponse, GetChannelCategoriesOptions, GetChannelCategoriesResponse, GetCategorySalesChannelsResponse, AssignCategoriesToChannelsBody, AssignCategoriesToChannelsResponse, UnassignCategoriesFromChannelsBody, UnassignCategoriesFromChannelsResponse, GetCollectionSalesChannelsResponse, AssignCollectionsToChannelsBody, AssignCollectionsToChannelsResponse, UnassignCollectionsFromChannelsBody, UnassignCollectionsFromChannelsResponse, GetAdminStorefrontConfigResponse, UpdateStorefrontConfigBody, UpdateStorefrontConfigResponse, GetAdminSiteConfigResponse, UpdateSiteConfigBody, UpdateSiteConfigResponse, GetAdminSiteConfigHistoryOptions, GetAdminSiteConfigHistoryResponse, RestoreSiteConfigResponse, OnboardDropshipperBody, OnboardDropshipperResponse, GetVariantCostsOptions, GetVariantCostsResponse, CreateVariantCostBody, CreateVariantCostResponse, BatchVariantCostsBody, BatchVariantCostsResponse, DeleteVariantCostResponse, GetDropshipperProductsOptions, GetDropshipperProductsResponse, UpdateDropshipperProductStatusBody, UpdateDropshipperProductStatusResponse, UpdateDropshipperPricesBody, UpdateDropshipperPricesResponse, GetDropshipperOrdersOptions, GetDropshipperOrdersResponse, GetDropshipperOrderDetailResponse, GetDropshipperShippingOptionsParams, GetDropshipperShippingOptionsResponse, ExtendedCreateDropshipperOrderBody, ExtendedCreateDropshipperOrderResponse, SetPaymentCollectorBody, SetPaymentCollectorResponse, CancelDropshipperOrderResponse, CreateOrderEditBody, CreateOrderEditResponse, AddOrderEditItemBody, AddOrderEditItemResponse, ConfirmOrderEditResponse, GetOrderNotesResponse, CreateOrderNoteBody, OrderNote, DeleteOrderNoteResponse, GetProviderCategoriesResponse, GetDropshipperCategoriesOptions, GetDropshipperCategoriesResponse, CreateDropshipperCategoryBody, DropshipperCategory, UpdateDropshipperCategoryBody, DeleteDropshipperCategoryResponse, GetCategoryMappingsOptions, GetCategoryMappingsResponse, CreateCategoryMappingBody, CreateCategoryMappingResponse, DeleteCategoryMappingResponse, GetDropshipperCustomersOptions, GetDropshipperCustomersResponse, GetDropshipperCustomerDetailResponse, CreateDropshipperCustomerBody, CreateDropshipperCustomerResponse, GetDropshipperAddressesResponse, DropshipperAddressBody, DropshipperAddressResponse, GetDropshipperAccountResponse, GetDropshipperPayableResponse, GetDropshipperReceivableResponse, GetSettlementsOptions, GetSettlementsResponse, GetSettlementDetailResponse, CreateSettlementBody, CreateSettlementResponse, ConfirmSettlementBody, UpdateSettlementStatusResponse, CancelSettlementBody, GetAdminDropshipperAccountsResponse, GetAdminAccountBalanceResponse, GetAdminPriceListsResponse, GetUserChannelResponse, GetDropshipperPromotionsOptions, GetDropshipperPromotionsResponse, CreateDropshipperPromotionBody, DropshipperPromotion, UpdateDropshipperPromotionBody, DeleteDropshipperPromotionResponse, GetDashboardStatsOptions, GetDashboardStatsResponse, GetStorefrontDropshipperCategoriesResponse } from '@thorprovider/types';
2
2
 
3
3
  /**
4
4
  * @fileoverview Medusa Multi-Tenant Admin Client
@@ -239,7 +239,14 @@ declare class DropshipperClient {
239
239
  */
240
240
  getProducts(options?: GetDropshipperProductsOptions): Promise<GetDropshipperProductsResponse>;
241
241
  /**
242
- * Bulk-update sale prices on Y's channel price list.
242
+ * Toggle whether a product is visible in the public store for the current sales channel.
243
+ * This does not mutate the shared global Medusa product status.
244
+ *
245
+ * `POST /admin/thor/dropshipper/products/:id/status`
246
+ */
247
+ updateProductStatus(productId: string, body: UpdateDropshipperProductStatusBody): Promise<UpdateDropshipperProductStatusResponse>;
248
+ /**
249
+ * Bulk-update product and variant margins on Y's channel price list.
243
250
  *
244
251
  * `PUT /admin/thor/dropshipper/prices`
245
252
  */
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetChannelCustomersOptions, GetChannelCustomersResponse, GetChannelApiKeysResponse, GetChannelCategoriesOptions, GetChannelCategoriesResponse, GetCategorySalesChannelsResponse, AssignCategoriesToChannelsBody, AssignCategoriesToChannelsResponse, UnassignCategoriesFromChannelsBody, UnassignCategoriesFromChannelsResponse, GetCollectionSalesChannelsResponse, AssignCollectionsToChannelsBody, AssignCollectionsToChannelsResponse, UnassignCollectionsFromChannelsBody, UnassignCollectionsFromChannelsResponse, GetAdminStorefrontConfigResponse, UpdateStorefrontConfigBody, UpdateStorefrontConfigResponse, GetAdminSiteConfigResponse, UpdateSiteConfigBody, UpdateSiteConfigResponse, GetAdminSiteConfigHistoryOptions, GetAdminSiteConfigHistoryResponse, RestoreSiteConfigResponse, OnboardDropshipperBody, OnboardDropshipperResponse, GetVariantCostsOptions, GetVariantCostsResponse, CreateVariantCostBody, CreateVariantCostResponse, BatchVariantCostsBody, BatchVariantCostsResponse, DeleteVariantCostResponse, GetDropshipperProductsOptions, GetDropshipperProductsResponse, UpdateDropshipperPricesBody, UpdateDropshipperPricesResponse, GetDropshipperOrdersOptions, GetDropshipperOrdersResponse, GetDropshipperOrderDetailResponse, GetDropshipperShippingOptionsParams, GetDropshipperShippingOptionsResponse, ExtendedCreateDropshipperOrderBody, ExtendedCreateDropshipperOrderResponse, SetPaymentCollectorBody, SetPaymentCollectorResponse, CancelDropshipperOrderResponse, CreateOrderEditBody, CreateOrderEditResponse, AddOrderEditItemBody, AddOrderEditItemResponse, ConfirmOrderEditResponse, GetOrderNotesResponse, CreateOrderNoteBody, OrderNote, DeleteOrderNoteResponse, GetProviderCategoriesResponse, GetDropshipperCategoriesOptions, GetDropshipperCategoriesResponse, CreateDropshipperCategoryBody, DropshipperCategory, UpdateDropshipperCategoryBody, DeleteDropshipperCategoryResponse, GetCategoryMappingsOptions, GetCategoryMappingsResponse, CreateCategoryMappingBody, CreateCategoryMappingResponse, DeleteCategoryMappingResponse, GetDropshipperCustomersOptions, GetDropshipperCustomersResponse, GetDropshipperCustomerDetailResponse, CreateDropshipperCustomerBody, CreateDropshipperCustomerResponse, GetDropshipperAddressesResponse, DropshipperAddressBody, DropshipperAddressResponse, GetDropshipperAccountResponse, GetDropshipperPayableResponse, GetDropshipperReceivableResponse, GetSettlementsOptions, GetSettlementsResponse, GetSettlementDetailResponse, CreateSettlementBody, CreateSettlementResponse, ConfirmSettlementBody, UpdateSettlementStatusResponse, CancelSettlementBody, GetAdminDropshipperAccountsResponse, GetAdminAccountBalanceResponse, GetAdminPriceListsResponse, GetUserChannelResponse, GetDropshipperPromotionsOptions, GetDropshipperPromotionsResponse, CreateDropshipperPromotionBody, DropshipperPromotion, UpdateDropshipperPromotionBody, DeleteDropshipperPromotionResponse, GetDashboardStatsOptions, GetDashboardStatsResponse, GetStorefrontDropshipperCategoriesResponse } from '@thorprovider/types';
1
+ import { GetChannelCustomersOptions, GetChannelCustomersResponse, GetChannelApiKeysResponse, GetChannelCategoriesOptions, GetChannelCategoriesResponse, GetCategorySalesChannelsResponse, AssignCategoriesToChannelsBody, AssignCategoriesToChannelsResponse, UnassignCategoriesFromChannelsBody, UnassignCategoriesFromChannelsResponse, GetCollectionSalesChannelsResponse, AssignCollectionsToChannelsBody, AssignCollectionsToChannelsResponse, UnassignCollectionsFromChannelsBody, UnassignCollectionsFromChannelsResponse, GetAdminStorefrontConfigResponse, UpdateStorefrontConfigBody, UpdateStorefrontConfigResponse, GetAdminSiteConfigResponse, UpdateSiteConfigBody, UpdateSiteConfigResponse, GetAdminSiteConfigHistoryOptions, GetAdminSiteConfigHistoryResponse, RestoreSiteConfigResponse, OnboardDropshipperBody, OnboardDropshipperResponse, GetVariantCostsOptions, GetVariantCostsResponse, CreateVariantCostBody, CreateVariantCostResponse, BatchVariantCostsBody, BatchVariantCostsResponse, DeleteVariantCostResponse, GetDropshipperProductsOptions, GetDropshipperProductsResponse, UpdateDropshipperProductStatusBody, UpdateDropshipperProductStatusResponse, UpdateDropshipperPricesBody, UpdateDropshipperPricesResponse, GetDropshipperOrdersOptions, GetDropshipperOrdersResponse, GetDropshipperOrderDetailResponse, GetDropshipperShippingOptionsParams, GetDropshipperShippingOptionsResponse, ExtendedCreateDropshipperOrderBody, ExtendedCreateDropshipperOrderResponse, SetPaymentCollectorBody, SetPaymentCollectorResponse, CancelDropshipperOrderResponse, CreateOrderEditBody, CreateOrderEditResponse, AddOrderEditItemBody, AddOrderEditItemResponse, ConfirmOrderEditResponse, GetOrderNotesResponse, CreateOrderNoteBody, OrderNote, DeleteOrderNoteResponse, GetProviderCategoriesResponse, GetDropshipperCategoriesOptions, GetDropshipperCategoriesResponse, CreateDropshipperCategoryBody, DropshipperCategory, UpdateDropshipperCategoryBody, DeleteDropshipperCategoryResponse, GetCategoryMappingsOptions, GetCategoryMappingsResponse, CreateCategoryMappingBody, CreateCategoryMappingResponse, DeleteCategoryMappingResponse, GetDropshipperCustomersOptions, GetDropshipperCustomersResponse, GetDropshipperCustomerDetailResponse, CreateDropshipperCustomerBody, CreateDropshipperCustomerResponse, GetDropshipperAddressesResponse, DropshipperAddressBody, DropshipperAddressResponse, GetDropshipperAccountResponse, GetDropshipperPayableResponse, GetDropshipperReceivableResponse, GetSettlementsOptions, GetSettlementsResponse, GetSettlementDetailResponse, CreateSettlementBody, CreateSettlementResponse, ConfirmSettlementBody, UpdateSettlementStatusResponse, CancelSettlementBody, GetAdminDropshipperAccountsResponse, GetAdminAccountBalanceResponse, GetAdminPriceListsResponse, GetUserChannelResponse, GetDropshipperPromotionsOptions, GetDropshipperPromotionsResponse, CreateDropshipperPromotionBody, DropshipperPromotion, UpdateDropshipperPromotionBody, DeleteDropshipperPromotionResponse, GetDashboardStatsOptions, GetDashboardStatsResponse, GetStorefrontDropshipperCategoriesResponse } from '@thorprovider/types';
2
2
 
3
3
  /**
4
4
  * @fileoverview Medusa Multi-Tenant Admin Client
@@ -239,7 +239,14 @@ declare class DropshipperClient {
239
239
  */
240
240
  getProducts(options?: GetDropshipperProductsOptions): Promise<GetDropshipperProductsResponse>;
241
241
  /**
242
- * Bulk-update sale prices on Y's channel price list.
242
+ * Toggle whether a product is visible in the public store for the current sales channel.
243
+ * This does not mutate the shared global Medusa product status.
244
+ *
245
+ * `POST /admin/thor/dropshipper/products/:id/status`
246
+ */
247
+ updateProductStatus(productId: string, body: UpdateDropshipperProductStatusBody): Promise<UpdateDropshipperProductStatusResponse>;
248
+ /**
249
+ * Bulk-update product and variant margins on Y's channel price list.
243
250
  *
244
251
  * `PUT /admin/thor/dropshipper/prices`
245
252
  */
package/dist/index.js CHANGED
@@ -518,11 +518,24 @@ var DropshipperClient = class {
518
518
  `/admin/thor/dropshipper/products?${qs}`
519
519
  );
520
520
  }
521
+ /**
522
+ * Toggle whether a product is visible in the public store for the current sales channel.
523
+ * This does not mutate the shared global Medusa product status.
524
+ *
525
+ * `POST /admin/thor/dropshipper/products/:id/status`
526
+ */
527
+ async updateProductStatus(productId, body) {
528
+ return this.request(
529
+ "POST",
530
+ `/admin/thor/dropshipper/products/${productId}/status`,
531
+ body
532
+ );
533
+ }
521
534
  // -------------------------------------------------------------------------
522
535
  // Prices (Solo Y)
523
536
  // -------------------------------------------------------------------------
524
537
  /**
525
- * Bulk-update sale prices on Y's channel price list.
538
+ * Bulk-update product and variant margins on Y's channel price list.
526
539
  *
527
540
  * `PUT /admin/thor/dropshipper/prices`
528
541
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/admin.ts","../src/request-resilience.ts","../src/dropshipper.ts"],"sourcesContent":["/**\n * @thorprovider/medusa-extended\n * Thor Commerce multi-tenant admin extensions for Medusa\n */\n\nexport { MedusaAdminClient } from './admin';\nexport type { MedusaAdminClientConfig } from './admin';\n\nexport { DropshipperClient } from './dropshipper';\nexport type { DropshipperClientConfig } from './dropshipper';\n\n","/**\n * @fileoverview Medusa Multi-Tenant Admin Client\n * @module @thorprovider/adapters/providers/medusa/admin\n *\n * Wrapper methods for all `/admin/thor/` endpoints defined in the Thor Commerce\n * multi-tenant API contract. Requires an admin API key (`adminConfig.apiKey`)\n * to be provided when creating the Medusa provider.\n *\n * Every method performs a raw `fetch` against the Medusa backend using the\n * admin API key (`x-medusa-access-token`) — the Medusa JS-SDK's admin client\n * does not expose these custom Thor plugin routes, so we use direct HTTP calls.\n *\n * Endpoint reference: `multitenant-api-contract.md`\n */\n\nimport type {\n GetChannelCustomersOptions,\n GetChannelCustomersResponse,\n GetChannelApiKeysResponse,\n GetChannelCategoriesOptions,\n GetChannelCategoriesResponse,\n GetCategorySalesChannelsResponse,\n AssignCategoriesToChannelsBody,\n AssignCategoriesToChannelsResponse,\n UnassignCategoriesFromChannelsBody,\n UnassignCategoriesFromChannelsResponse,\n GetCollectionSalesChannelsResponse,\n AssignCollectionsToChannelsBody,\n AssignCollectionsToChannelsResponse,\n UnassignCollectionsFromChannelsBody,\n UnassignCollectionsFromChannelsResponse,\n GetAdminStorefrontConfigResponse,\n UpdateStorefrontConfigBody,\n UpdateStorefrontConfigResponse,\n GetAdminSiteConfigResponse,\n UpdateSiteConfigBody,\n UpdateSiteConfigResponse,\n GetAdminSiteConfigHistoryOptions,\n GetAdminSiteConfigHistoryResponse,\n RestoreSiteConfigResponse,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the admin client.\n */\nexport interface MedusaAdminClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /** Secret admin API key (x-medusa-access-token) */\n apiKey: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// MedusaAdminClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce multi-tenant admin endpoints (`/admin/thor/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const admin = new MedusaAdminClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * apiKey: process.env.MEDUSA_ADMIN_API_KEY!,\n * });\n *\n * const { customers } = await admin.getChannelCustomers('sc_01JXXXXX');\n * ```\n */\nexport class MedusaAdminClient {\n private baseUrl: string;\n private apiKey: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: MedusaAdminClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.logger = createLogger('MedusaAdminClient', config.debug);\n }\n\n // -----------------------------------------------------------------------\n // Private — HTTP helper\n // -----------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[admin] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n 'x-medusa-access-token': this.apiKey,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[admin] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[admin] ${method} ${path} failed: ${message}`,\n `ADMIN_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -----------------------------------------------------------------------\n // 3.1 — Sales Channel: Customers\n // -----------------------------------------------------------------------\n\n /**\n * Paginated list of customers linked to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/customers`\n */\n async getChannelCustomers(\n salesChannelId: string,\n options: GetChannelCustomersOptions = {},\n ): Promise<GetChannelCustomersResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetChannelCustomersResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.2 — Sales Channel: API Keys\n // -----------------------------------------------------------------------\n\n /**\n * Publishable API keys associated with a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/api-keys`\n */\n async getChannelApiKeys(salesChannelId: string): Promise<GetChannelApiKeysResponse> {\n return this.request<GetChannelApiKeysResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/api-keys`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.3 — Sales Channel: Categories\n // -----------------------------------------------------------------------\n\n /**\n * Product categories assigned to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/categories`\n */\n async getChannelCategories(\n salesChannelId: string,\n options: GetChannelCategoriesOptions = {},\n ): Promise<GetChannelCategoriesResponse> {\n const { limit = 20, offset = 0, include_descendants = false } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n include_descendants: String(include_descendants),\n });\n return this.request<GetChannelCategoriesResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.4 — Category: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a category is assigned.\n *\n * `GET /admin/thor/categories/:id/sales-channels`\n */\n async getCategorySalesChannels(\n categoryId: string,\n ): Promise<GetCategorySalesChannelsResponse> {\n return this.request<GetCategorySalesChannelsResponse>(\n 'GET',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.5 — Category: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a category to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/categories/:id/sales-channels`\n */\n async assignCategoryToChannels(\n categoryId: string,\n body: AssignCategoriesToChannelsBody,\n ): Promise<AssignCategoriesToChannelsResponse> {\n return this.request<AssignCategoriesToChannelsResponse>(\n 'POST',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.6 — Category: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove category assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/categories/:id/sales-channels`\n */\n async unassignCategoryFromChannels(\n categoryId: string,\n body: UnassignCategoriesFromChannelsBody,\n ): Promise<UnassignCategoriesFromChannelsResponse> {\n return this.request<UnassignCategoriesFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.7 — Collection: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a collection is assigned.\n *\n * `GET /admin/thor/collections/:id/sales-channels`\n */\n async getCollectionSalesChannels(\n collectionId: string,\n ): Promise<GetCollectionSalesChannelsResponse> {\n return this.request<GetCollectionSalesChannelsResponse>(\n 'GET',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.8 — Collection: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a collection to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/collections/:id/sales-channels`\n */\n async assignCollectionToChannels(\n collectionId: string,\n body: AssignCollectionsToChannelsBody,\n ): Promise<AssignCollectionsToChannelsResponse> {\n return this.request<AssignCollectionsToChannelsResponse>(\n 'POST',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.9 — Collection: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove collection assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/collections/:id/sales-channels`\n */\n async unassignCollectionFromChannels(\n collectionId: string,\n body: UnassignCollectionsFromChannelsBody,\n ): Promise<UnassignCollectionsFromChannelsResponse> {\n return this.request<UnassignCollectionsFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.10 — Storefront Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the visual storefront configuration for a channel.\n * `:id` is the `sales_channel_id`.\n *\n * `GET /admin/thor/storefront-config/:id`\n */\n async getStorefrontConfig(\n salesChannelId: string,\n ): Promise<GetAdminStorefrontConfigResponse> {\n return this.request<GetAdminStorefrontConfigResponse>(\n 'GET',\n `/admin/thor/storefront-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.11 — Storefront Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the visual storefront configuration for a channel.\n * Triggers the `storefront_config.updated` event → ISR webhook.\n *\n * `PUT /admin/thor/storefront-config/:id`\n */\n async updateStorefrontConfig(\n salesChannelId: string,\n body: UpdateStorefrontConfigBody,\n ): Promise<UpdateStorefrontConfigResponse> {\n return this.request<UpdateStorefrontConfigResponse>(\n 'PUT',\n `/admin/thor/storefront-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.12 — Site Designer Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the active Site Designer configuration for a channel, including the\n * last 10 history entries.\n *\n * `GET /admin/thor/site-config/:sales_channel_id`\n */\n async getSiteConfig(salesChannelId: string): Promise<GetAdminSiteConfigResponse> {\n return this.request<GetAdminSiteConfigResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.13 — Site Designer Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the Site Designer configuration for a channel.\n * Creates a new history entry on every PUT.\n *\n * `PUT /admin/thor/site-config/:sales_channel_id`\n */\n async updateSiteConfig(\n salesChannelId: string,\n body: UpdateSiteConfigBody,\n ): Promise<UpdateSiteConfigResponse> {\n return this.request<UpdateSiteConfigResponse>(\n 'PUT',\n `/admin/thor/site-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.14 — Site Designer Config: History\n // -----------------------------------------------------------------------\n\n /**\n * Full paginated history of Site Designer versions for a channel.\n * Entries are immutable — they are never deleted.\n *\n * `GET /admin/thor/site-config/:sales_channel_id/history`\n */\n async getSiteConfigHistory(\n salesChannelId: string,\n options: GetAdminSiteConfigHistoryOptions = {},\n ): Promise<GetAdminSiteConfigHistoryResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetAdminSiteConfigHistoryResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.15 — Site Designer Config: Restore\n // -----------------------------------------------------------------------\n\n /**\n * Restore a previous Site Designer version.\n * Internally runs the update workflow with the stored config of the target\n * version — this creates a **new** history entry and does NOT mutate past\n * entries.\n *\n * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`\n */\n async restoreSiteConfig(\n salesChannelId: string,\n version: string,\n ): Promise<RestoreSiteConfigResponse> {\n return this.request<RestoreSiteConfigResponse>(\n 'POST',\n `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`,\n );\n }\n}\n","import { ProviderAPIError, backendCircuitBreaker } from '@thorprovider/adapters'\n\ntype RetryConfig = {\n maxRetries?: number\n initialDelayMs?: number\n backoffMultiplier?: number\n maxDelayMs?: number\n timeoutMs?: number\n retryableStatusCodes?: number[]\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelayMs: 300,\n backoffMultiplier: 2,\n maxDelayMs: 5000,\n timeoutMs: 10000,\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction calculateDelay(attempt: number, config: Required<RetryConfig>): number {\n const delay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt)\n return Math.min(delay, config.maxDelayMs)\n}\n\nfunction isRetryableError(error: unknown, config: Required<RetryConfig>): boolean {\n const err = error as { name?: string; message?: string; status?: number }\n\n if (err.name === 'TypeError' || err.message?.includes('fetch failed')) return true\n if (err.name === 'AbortError' || err.message?.includes('timeout')) return true\n if (typeof err.status === 'number' && config.retryableStatusCodes.includes(err.status)) return true\n return false\n}\n\nasync function fetchWithRetry(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig }\n let lastError: unknown\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs)\n\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timeoutId)\n\n if (!response.ok && config.retryableStatusCodes.includes(response.status)) {\n const error = new Error(`HTTP ${response.status}: ${response.statusText}`) as Error & { status?: number }\n error.status = response.status\n throw error\n }\n\n return response\n } catch (error) {\n lastError = error\n const shouldRetry = attempt < config.maxRetries && isRetryableError(error, config)\n\n if (shouldRetry) {\n await sleep(calculateDelay(attempt, config))\n continue\n }\n\n break\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error('Backend request failed')\n}\n\nexport async function fetchBackendWithResilience(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n try {\n return await backendCircuitBreaker.execute(() => fetchWithRetry(url, init, retryConfig))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new ProviderAPIError(`Backend request failed: ${message}`, 'backend', 503)\n }\n}\n","/**\n * @fileoverview Dropshipper Client — Thor Commerce Extended\n * @module @thorprovider/medusa-extended/dropshipper\n *\n * HTTP client for all `/admin/thor/dropshipper/` endpoints.\n *\n * Used by both:\n * - X (ThorProvider admin) — authenticated via admin JWT, role \"Admin\"\n * - Y (Dropshipper panel) — authenticated via dropshipper JWT, role \"Dropshipper\"\n *\n * Access control is enforced server-side via `withDropshipperScope` middleware.\n * This client always sends `Authorization: Bearer <token>`.\n *\n * Endpoint reference: `dropshipping-api-contract.md`\n */\n\nimport type {\n // Onboarding\n OnboardDropshipperBody,\n OnboardDropshipperResponse,\n // Variant Costs\n GetVariantCostsOptions,\n GetVariantCostsResponse,\n CreateVariantCostBody,\n CreateVariantCostResponse,\n BatchVariantCostsBody,\n BatchVariantCostsResponse,\n DeleteVariantCostResponse,\n // Products & Prices\n GetDropshipperProductsOptions,\n GetDropshipperProductsResponse,\n UpdateDropshipperPricesBody,\n UpdateDropshipperPricesResponse,\n // Orders\n GetDropshipperOrdersOptions,\n GetDropshipperOrdersResponse,\n GetDropshipperShippingOptionsParams,\n GetDropshipperShippingOptionsResponse,\n GetDropshipperOrderDetailResponse,\n ExtendedCreateDropshipperOrderBody,\n ExtendedCreateDropshipperOrderResponse,\n SetPaymentCollectorBody,\n SetPaymentCollectorResponse,\n // Order Cancel & Edits\n CancelDropshipperOrderResponse,\n CreateOrderEditBody,\n CreateOrderEditResponse,\n AddOrderEditItemBody,\n AddOrderEditItemResponse,\n ConfirmOrderEditResponse,\n // Order Notes\n OrderNote,\n CreateOrderNoteBody,\n GetOrderNotesResponse,\n DeleteOrderNoteResponse,\n // Dropshipper Addresses\n DropshipperAddressBody,\n DropshipperAddressResponse,\n GetDropshipperAddressesResponse,\n // Categories\n GetDropshipperCategoriesOptions,\n GetDropshipperCategoriesResponse,\n CreateDropshipperCategoryBody,\n UpdateDropshipperCategoryBody,\n DeleteDropshipperCategoryResponse,\n GetProviderCategoriesResponse,\n GetCategoryMappingsOptions,\n GetCategoryMappingsResponse,\n CreateCategoryMappingBody,\n CreateCategoryMappingResponse,\n DeleteCategoryMappingResponse,\n // Customers\n GetDropshipperCustomersOptions,\n GetDropshipperCustomersResponse,\n GetDropshipperCustomerDetailResponse,\n CreateDropshipperCustomerBody,\n CreateDropshipperCustomerResponse,\n // Account & Settlements (Y)\n GetDropshipperAccountResponse,\n GetDropshipperPayableResponse,\n GetDropshipperReceivableResponse,\n GetSettlementsOptions,\n GetSettlementsResponse,\n GetSettlementDetailResponse,\n // Admin Settlements (X)\n CreateSettlementBody,\n CreateSettlementResponse,\n ConfirmSettlementBody,\n CancelSettlementBody,\n UpdateSettlementStatusResponse,\n // Admin Account Management (X)\n GetAdminDropshipperAccountsResponse,\n GetAdminAccountBalanceResponse,\n GetAdminPriceListsResponse,\n GetUserChannelResponse,\n // Promotions\n GetDropshipperPromotionsOptions,\n GetDropshipperPromotionsResponse,\n CreateDropshipperPromotionBody,\n UpdateDropshipperPromotionBody,\n DeleteDropshipperPromotionResponse,\n // Dashboard\n GetDashboardStatsOptions,\n GetDashboardStatsResponse,\n // Storefront (V)\n GetStorefrontDropshipperCategoriesResponse,\n // Inline return types\n DropshipperCategory,\n DropshipperPromotion,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the dropshipper client.\n */\nexport interface DropshipperClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /**\n * JWT token obtained from `POST /auth/user/emailpass`.\n * Used as `Authorization: Bearer <token>`.\n */\n token: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// DropshipperClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce dropshipping endpoints (`/admin/thor/dropshipper/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const client = new DropshipperClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * token: jwtFromLogin,\n * });\n *\n * // Y: list own products\n * const { products } = await client.getProducts();\n *\n * // X: onboard a new dropshipper\n * const { dropshipper } = await client.onboardDropshipper({ ... });\n * ```\n */\nexport class DropshipperClient {\n private baseUrl: string;\n private token: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: DropshipperClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.token = config.token;\n this.logger = createLogger('DropshipperClient', config.debug);\n }\n\n // -------------------------------------------------------------------------\n // Private — HTTP helper\n // -------------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[dropshipper] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[dropshipper] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[dropshipper] ${method} ${path} failed: ${message}`,\n `DROPSHIPPER_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -------------------------------------------------------------------------\n // Onboarding (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a new dropshipper account (sales channel + user + price list).\n *\n * `POST /admin/thor/dropshipper/onboard`\n */\n async onboardDropshipper(\n body: OnboardDropshipperBody,\n ): Promise<OnboardDropshipperResponse> {\n return this.request<OnboardDropshipperResponse>(\n 'POST',\n '/admin/thor/dropshipper/onboard',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Variant Costs (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List variant cost records, optionally filtered by account/variant/currency.\n *\n * `GET /admin/thor/dropshipper/variant-costs`\n */\n async getVariantCosts(\n options: GetVariantCostsOptions = {},\n ): Promise<GetVariantCostsResponse> {\n const { account_id, variant_id, currency_code, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(account_id ? { account_id } : {}),\n ...(variant_id ? { variant_id } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n return this.request<GetVariantCostsResponse>(\n 'GET',\n `/admin/thor/dropshipper/variant-costs?${qs}`,\n );\n }\n\n /**\n * Upsert a single variant cost record.\n *\n * `POST /admin/thor/dropshipper/variant-costs`\n */\n async createVariantCost(\n body: CreateVariantCostBody,\n ): Promise<CreateVariantCostResponse> {\n return this.request<CreateVariantCostResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs',\n body,\n );\n }\n\n /**\n * Batch-upsert variant costs for a given account and currency.\n *\n * `POST /admin/thor/dropshipper/variant-costs/batch`\n */\n async batchVariantCosts(\n body: BatchVariantCostsBody,\n ): Promise<BatchVariantCostsResponse> {\n return this.request<BatchVariantCostsResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs/batch',\n body,\n );\n }\n\n /**\n * Delete a variant cost record by ID.\n *\n * `DELETE /admin/thor/dropshipper/variant-costs/:id`\n */\n async deleteVariantCost(id: string): Promise<DeleteVariantCostResponse> {\n return this.request<DeleteVariantCostResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/variant-costs/${id}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Products (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List products available in Y's channel with cost/margin data.\n *\n * `GET /admin/thor/dropshipper/products`\n */\n async getProducts(\n options: GetDropshipperProductsOptions = {},\n ): Promise<GetDropshipperProductsResponse> {\n const { q, category_id, status, in_stock, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(category_id ? { category_id } : {}),\n ...(status ? { status } : {}),\n ...(in_stock !== undefined ? { in_stock: String(in_stock) } : {}),\n });\n return this.request<GetDropshipperProductsResponse>(\n 'GET',\n `/admin/thor/dropshipper/products?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Prices (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Bulk-update sale prices on Y's channel price list.\n *\n * `PUT /admin/thor/dropshipper/prices`\n */\n async updatePrices(\n body: UpdateDropshipperPricesBody,\n ): Promise<UpdateDropshipperPricesResponse> {\n return this.request<UpdateDropshipperPricesResponse>(\n 'PUT',\n '/admin/thor/dropshipper/prices',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Orders (Y + X for set-payment-collector)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of orders in Y's channel.\n *\n * `GET /admin/thor/dropshipper/orders`\n */\n async getOrders(\n options: GetDropshipperOrdersOptions = {},\n ): Promise<GetDropshipperOrdersResponse> {\n const { status, payment_collector, settlement_status, from, to, q, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(payment_collector ? { payment_collector } : {}),\n ...(settlement_status ? { settlement_status } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(q ? { q } : {}),\n });\n return this.request<GetDropshipperOrdersResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders?${qs}`,\n );\n }\n\n /**\n * Full detail for a single order with profit breakdown.\n *\n * `GET /admin/thor/dropshipper/orders/:id`\n */\n async getOrder(orderId: string): Promise<GetDropshipperOrderDetailResponse> {\n return this.request<GetDropshipperOrderDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}`,\n );\n }\n\n /**\n * List shipping options for a manual dropshipper order.\n *\n * `GET /admin/thor/dropshipper/orders/shipping-options`\n */\n async getOrderShippingOptions(\n params: GetDropshipperShippingOptionsParams,\n ): Promise<GetDropshipperShippingOptionsResponse> {\n const qs = new URLSearchParams({\n currency_code: params.currency_code.toLowerCase(),\n ...(params.country_code ? { country_code: params.country_code.toLowerCase() } : {}),\n });\n\n return this.request<GetDropshipperShippingOptionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/shipping-options?${qs}`,\n );\n }\n\n /**\n * Manually create an order on behalf of a customer.\n *\n * `POST /admin/thor/dropshipper/orders`\n */\n async createOrder(\n body: ExtendedCreateDropshipperOrderBody,\n ): Promise<ExtendedCreateDropshipperOrderResponse> {\n return this.request<ExtendedCreateDropshipperOrderResponse>(\n 'POST',\n '/admin/thor/dropshipper/orders',\n body,\n );\n }\n\n /**\n * Set who collects payment for an order (Solo X).\n *\n * `POST /admin/thor/dropshipper/orders/:id/set-payment-collector`\n */\n async setPaymentCollector(\n orderId: string,\n body: SetPaymentCollectorBody,\n ): Promise<SetPaymentCollectorResponse> {\n return this.request<SetPaymentCollectorResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/set-payment-collector`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Order Cancel & Edits (Solo Y) — B-04\n // -------------------------------------------------------------------------\n\n /**\n * Cancel a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/cancel`\n */\n async cancelOrder(orderId: string): Promise<CancelDropshipperOrderResponse> {\n return this.request<CancelDropshipperOrderResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/cancel`,\n );\n }\n\n /**\n * Create an order edit for a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit`\n */\n async createOrderEdit(\n orderId: string,\n body: CreateOrderEditBody = {},\n ): Promise<CreateOrderEditResponse> {\n return this.request<CreateOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit`,\n body,\n );\n }\n\n /**\n * Add an item to the active order edit.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/items`\n */\n async addOrderEditItem(\n orderId: string,\n body: AddOrderEditItemBody,\n ): Promise<AddOrderEditItemResponse> {\n return this.request<AddOrderEditItemResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/items`,\n body,\n );\n }\n\n /**\n * Confirm the active order edit, applying changes to the order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/confirm`\n */\n async confirmOrderEdit(\n orderId: string,\n ): Promise<ConfirmOrderEditResponse> {\n return this.request<ConfirmOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/confirm`,\n );\n }\n\n /**\n * Get all notes for an order.\n *\n * `GET /admin/thor/dropshipper/orders/:id/notes`\n */\n async getOrderNotes(orderId: string): Promise<GetOrderNotesResponse> {\n return this.request<GetOrderNotesResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n );\n }\n\n /**\n * Create a new note for an order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/notes`\n */\n async createOrderNote(\n orderId: string,\n body: CreateOrderNoteBody,\n ): Promise<OrderNote> {\n return this.request<OrderNote>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n body,\n );\n }\n\n /**\n * Delete a note from an order.\n *\n * `DELETE /admin/thor/dropshipper/orders/:id/notes/:noteId`\n */\n async deleteOrderNote(\n orderId: string,\n noteId: string,\n ): Promise<DeleteOrderNoteResponse> {\n return this.request<DeleteOrderNoteResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/orders/${orderId}/notes/${noteId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Custom Categories (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Medusa provider categories linked to Y's channel (read-only).\n *\n * `GET /admin/thor/dropshipper/categories/provider`\n */\n async getProviderCategories(): Promise<GetProviderCategoriesResponse> {\n return this.request<GetProviderCategoriesResponse>(\n 'GET',\n '/admin/thor/dropshipper/categories/provider',\n );\n }\n\n /**\n * List Y's custom product categories.\n *\n * `GET /admin/thor/dropshipper/categories`\n */\n async getCategories(\n options: GetDropshipperCategoriesOptions = {},\n ): Promise<GetDropshipperCategoriesResponse> {\n const { parent_id, include_children } = options;\n const qs = new URLSearchParams({\n ...(parent_id ? { parent_id } : {}),\n ...(include_children !== undefined ? { include_children: String(include_children) } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDropshipperCategoriesResponse>(\n 'GET',\n `/admin/thor/dropshipper/categories${query}`,\n );\n }\n\n /**\n * Create a custom category in Y's channel.\n *\n * `POST /admin/thor/dropshipper/categories`\n */\n async createCategory(\n body: CreateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'POST',\n '/admin/thor/dropshipper/categories',\n body,\n );\n }\n\n /**\n * Update a custom category.\n *\n * `PUT /admin/thor/dropshipper/categories/:id`\n */\n async updateCategory(\n categoryId: string,\n body: UpdateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'PUT',\n `/admin/thor/dropshipper/categories/${categoryId}`,\n body,\n );\n }\n\n /**\n * Delete a custom category.\n *\n * Pass `{ force: true }` to cascade-delete child categories.\n *\n * `DELETE /admin/thor/dropshipper/categories/:id`\n */\n async deleteCategory(\n categoryId: string,\n options: { force?: boolean } = {},\n ): Promise<DeleteDropshipperCategoryResponse> {\n const qs = options.force ? '?force=true' : '';\n return this.request<DeleteDropshipperCategoryResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/categories/${categoryId}${qs}`,\n );\n }\n\n /**\n * List product-to-category mappings, optionally filtered by product.\n *\n * `GET /admin/thor/dropshipper/category-mappings`\n */\n async getCategoryMappings(\n options: GetCategoryMappingsOptions = {},\n ): Promise<GetCategoryMappingsResponse> {\n const qs = options.product_id ? `?product_id=${options.product_id}` : '';\n return this.request<GetCategoryMappingsResponse>(\n 'GET',\n `/admin/thor/dropshipper/category-mappings${qs}`,\n );\n }\n\n /**\n * Map a product to a custom category.\n *\n * `POST /admin/thor/dropshipper/category-mappings`\n */\n async createCategoryMapping(\n body: CreateCategoryMappingBody,\n ): Promise<CreateCategoryMappingResponse> {\n return this.request<CreateCategoryMappingResponse>(\n 'POST',\n '/admin/thor/dropshipper/category-mappings',\n body,\n );\n }\n\n /**\n * Remove a product-to-category mapping.\n *\n * `DELETE /admin/thor/dropshipper/category-mappings/:id`\n */\n async deleteCategoryMapping(\n mappingId: string,\n ): Promise<DeleteCategoryMappingResponse> {\n return this.request<DeleteCategoryMappingResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/category-mappings/${mappingId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customers (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of customers in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers`\n */\n async getCustomers(\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n const { q, has_orders, from, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(has_orders !== undefined ? { has_orders: String(has_orders) } : {}),\n ...(from ? { from } : {}),\n });\n return this.request<GetDropshipperCustomersResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers?${qs}`,\n );\n }\n\n /**\n * Backwards-compatible alias used by the dashboard checkout flow.\n */\n async getChannelCustomers(\n _channelId: string,\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n return this.getCustomers(options);\n }\n\n /**\n * Full detail for a single customer.\n *\n * `GET /admin/thor/dropshipper/customers/:id`\n */\n async getCustomer(\n customerId: string,\n ): Promise<GetDropshipperCustomerDetailResponse> {\n return this.request<GetDropshipperCustomerDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}`,\n );\n }\n\n /**\n * Create a customer scoped to Y's channel.\n *\n * `POST /admin/thor/dropshipper/customers`\n */\n async createCustomer(\n body: CreateDropshipperCustomerBody,\n ): Promise<CreateDropshipperCustomerResponse> {\n return this.request<CreateDropshipperCustomerResponse>(\n 'POST',\n '/admin/thor/dropshipper/customers',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customer Addresses (Solo Y) — B-06\n // -------------------------------------------------------------------------\n\n /**\n * List addresses for a customer in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers/:id/addresses`\n */\n async getCustomerAddresses(\n customerId: string,\n ): Promise<GetDropshipperAddressesResponse> {\n return this.request<GetDropshipperAddressesResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n );\n }\n\n /**\n * Create a new address for a customer.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses`\n */\n async createCustomerAddress(\n customerId: string,\n body: DropshipperAddressBody,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n body,\n );\n }\n\n /**\n * Update an existing customer address.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async updateCustomerAddress(\n customerId: string,\n addressId: string,\n body: Partial<DropshipperAddressBody>,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n body,\n );\n }\n\n /**\n * Delete a customer address.\n *\n * `DELETE /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async deleteCustomerAddress(\n customerId: string,\n addressId: string,\n ): Promise<{ deleted: true; id: string }> {\n return this.request<{ deleted: true; id: string }>(\n 'DELETE',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Account & Settlements (Y read-only)\n // -------------------------------------------------------------------------\n\n /**\n * Y's account info with current balance.\n *\n * `GET /admin/thor/dropshipper/account`\n */\n async getAccount(): Promise<GetDropshipperAccountResponse> {\n return this.request<GetDropshipperAccountResponse>(\n 'GET',\n '/admin/thor/dropshipper/account',\n );\n }\n\n /**\n * Orders where Y owes money to X (Y collected payment, needs to pay costs).\n *\n * `GET /admin/thor/dropshipper/account/payable`\n */\n async getPayable(): Promise<GetDropshipperPayableResponse> {\n return this.request<GetDropshipperPayableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/payable',\n );\n }\n\n /**\n * Orders where X owes money to Y (X collected COD, needs to transfer profit).\n *\n * `GET /admin/thor/dropshipper/account/receivable`\n */\n async getReceivable(): Promise<GetDropshipperReceivableResponse> {\n return this.request<GetDropshipperReceivableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/receivable',\n );\n }\n\n /**\n * List settlements (Y sees own; X can filter by account_id).\n *\n * `GET /admin/thor/dropshipper/settlements`\n */\n async getSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements?${qs}`,\n );\n }\n\n /**\n * Full detail for a single settlement record.\n *\n * `GET /admin/thor/dropshipper/settlements/:id`\n */\n async getSettlement(\n settlementId: string,\n ): Promise<GetSettlementDetailResponse> {\n return this.request<GetSettlementDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements/${settlementId}`,\n\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a settlement record for a dropshipper account.\n *\n * `POST /admin/thor/dropshipper/admin/settlements`\n */\n async createSettlement(\n body: CreateSettlementBody,\n ): Promise<CreateSettlementResponse> {\n return this.request<CreateSettlementResponse>(\n 'POST',\n '/admin/thor/dropshipper/admin/settlements',\n body,\n );\n }\n\n /**\n * Confirm a pending settlement (marks it as paid/received).\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/confirm`\n */\n async confirmSettlement(\n settlementId: string,\n body: ConfirmSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/confirm`,\n body,\n );\n }\n\n /**\n * Cancel a pending settlement.\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/cancel`\n */\n async cancelSettlement(\n settlementId: string,\n body: CancelSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/cancel`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements — list (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * X views all settlement records across all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/settlements`\n */\n async getAdminSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/settlements?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Account Management (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/accounts`\n */\n async getAdminAccounts(): Promise<GetAdminDropshipperAccountsResponse> {\n return this.request<GetAdminDropshipperAccountsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/accounts',\n );\n }\n\n /**\n * Full balance detail for a specific dropshipper account.\n *\n * `GET /admin/thor/dropshipper/admin/accounts/:id/balance`\n */\n async getAdminAccountBalance(\n accountId: string,\n ): Promise<GetAdminAccountBalanceResponse> {\n return this.request<GetAdminAccountBalanceResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/accounts/${accountId}/balance`,\n );\n }\n\n /**\n * List all dropshipper price lists.\n *\n * `GET /admin/thor/dropshipper/admin/price-lists`\n */\n async getAdminPriceLists(): Promise<GetAdminPriceListsResponse> {\n return this.request<GetAdminPriceListsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/price-lists',\n );\n }\n\n /**\n * Utility: look up which sales channel a user belongs to.\n *\n * `GET /admin/thor/dropshipper/admin/user-channel`\n */\n async getUserChannel(): Promise<GetUserChannelResponse> {\n return this.request<GetUserChannelResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/user-channel',\n );\n }\n\n // -------------------------------------------------------------------------\n // Promotions (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Y's promotions (discount codes).\n *\n * `GET /admin/thor/dropshipper/promotions`\n */\n async getPromotions(\n options: GetDropshipperPromotionsOptions = {},\n ): Promise<GetDropshipperPromotionsResponse> {\n const { type, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(type ? { type } : {}),\n });\n return this.request<GetDropshipperPromotionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/promotions?${qs}`,\n );\n }\n\n /**\n * Create a promotion for Y's channel.\n *\n * `POST /admin/thor/dropshipper/promotions`\n */\n async createPromotion(\n body: CreateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'POST',\n '/admin/thor/dropshipper/promotions',\n body,\n );\n }\n\n /**\n * Get a single promotion by ID.\n *\n * `GET /admin/thor/dropshipper/promotions/:id`\n */\n async getPromotion(promotionId: string): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'GET',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n /**\n * Update an existing promotion.\n *\n * `PUT /admin/thor/dropshipper/promotions/:id`\n */\n async updatePromotion(\n promotionId: string,\n body: UpdateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'PUT',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n body,\n );\n }\n\n /**\n * Delete a promotion.\n *\n * `DELETE /admin/thor/dropshipper/promotions/:id`\n */\n async deletePromotion(\n promotionId: string,\n ): Promise<DeleteDropshipperPromotionResponse> {\n return this.request<DeleteDropshipperPromotionResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Dashboard (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Aggregate stats for Y's dashboard (revenue, profit, top products).\n *\n * `GET /admin/thor/dropshipper/dashboard/stats`\n */\n async getDashboardStats(\n options: GetDashboardStatsOptions = {},\n ): Promise<GetDashboardStatsResponse> {\n const { period, from, to, currency_code } = options;\n const qs = new URLSearchParams({\n ...(period ? { period } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDashboardStatsResponse>(\n 'GET',\n `/admin/thor/dropshipper/dashboard/stats${query}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Storefront (V — end customer, uses publishable API key)\n // -------------------------------------------------------------------------\n\n /**\n * Public endpoint: dropshipper-scoped categories for the storefront.\n * Typically called with a publishable API key rather than a JWT.\n *\n * `GET /store/thor/dropshipper-categories`\n */\n async getStorefrontCategories(): Promise<GetStorefrontDropshipperCategoriesResponse> {\n return this.request<GetStorefrontDropshipperCategoriesResponse>(\n 'GET',\n '/store/thor/dropshipper-categories',\n );\n }\n}\n\n// Re-export types used by callers so they don't need to import from @thorprovider/types directly.\nexport type { DropshipperCategory, DropshipperPromotion } from '@thorprovider/types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyCA,IAAAA,mBAA+C;;;ACzC/C,sBAAwD;AAWxD,IAAM,uBAA8C;AAAA,EAClD,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,sBAAsB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACrD;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAEA,SAAS,eAAe,SAAiB,QAAuC;AAC9E,QAAM,QAAQ,OAAO,iBAAiB,KAAK,IAAI,OAAO,mBAAmB,OAAO;AAChF,SAAO,KAAK,IAAI,OAAO,OAAO,UAAU;AAC1C;AAEA,SAAS,iBAAiB,OAAgB,QAAwC;AAChF,QAAM,MAAM;AAEZ,MAAI,IAAI,SAAS,eAAe,IAAI,SAAS,SAAS,cAAc,EAAG,QAAO;AAC9E,MAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AAC1E,MAAI,OAAO,IAAI,WAAW,YAAY,OAAO,qBAAqB,SAAS,IAAI,MAAM,EAAG,QAAO;AAC/F,SAAO;AACT;AAEA,eAAe,eAAe,KAAa,MAAmB,aAA8C;AAC1G,QAAM,SAAS,EAAE,GAAG,sBAAsB,GAAG,YAAY;AACzD,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,OAAO,YAAY,WAAW;AAC7D,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO,SAAS;AAEvE,YAAM,WAAW,MAAM,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,CAAC;AACxE,mBAAa,SAAS;AAEtB,UAAI,CAAC,SAAS,MAAM,OAAO,qBAAqB,SAAS,SAAS,MAAM,GAAG;AACzE,cAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AACzE,cAAM,SAAS,SAAS;AACxB,cAAM;AAAA,MACR;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,kBAAY;AACZ,YAAM,cAAc,UAAU,OAAO,cAAc,iBAAiB,OAAO,MAAM;AAEjF,UAAI,aAAa;AACf,cAAM,MAAM,eAAe,SAAS,MAAM,CAAC;AAC3C;AAAA,MACF;AAEA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,wBAAwB;AACnF;AAEA,eAAsB,2BAA2B,KAAa,MAAmB,aAA8C;AAC7H,MAAI;AACF,WAAO,MAAM,sCAAsB,QAAQ,MAAM,eAAe,KAAK,MAAM,WAAW,CAAC;AAAA,EACzF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,IAAI,iCAAiB,2BAA2B,OAAO,IAAI,WAAW,GAAG;AAAA,EACjF;AACF;;;ADCO,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAiC;AAC3C,SAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC/C,SAAK,SAAS,OAAO;AACrB,SAAK,aAAS,+BAAa,qBAAqB,OAAO,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,SAAK,OAAO,MAAM,WAAW,MAAM,IAAI,IAAI,EAAE;AAE7C,UAAM,UAAkC;AAAA,MACtC,yBAAyB,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAEA,UAAM,OAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC7D;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,2BAA2B,KAAK,IAAI;AAAA,IACvD,SAAS,cAAmB;AAC1B,YAAM,IAAI;AAAA,QACR,4BAA4B,MAAM,IAAI,IAAI,KAAK,aAAa,OAAO;AAAA,QACnE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,UAAU,QAAQ,SAAS,MAAM;AACrC,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,kBAAU,MAAM,WAAW;AAAA,MAC7B,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,WAAW,MAAM,IAAI,IAAI,YAAY,OAAO;AAAA,QAC5C,aAAa,SAAS,MAAM;AAAA,QAC5B,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,oBACJ,gBACA,UAAsC,CAAC,GACD;AACtC,UAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,IAAI;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc,oBAAoB,KAAK,WAAW,MAAM;AAAA,IACxF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,kBAAkB,gBAA4D;AAClF,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,qBACJ,gBACA,UAAuC,CAAC,GACD;AACvC,UAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,sBAAsB,MAAM,IAAI;AAChE,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,qBAAqB,OAAO,mBAAmB;AAAA,IACjD,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc,eAAe,EAAE;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,yBACJ,YAC2C;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,yBACJ,YACA,MAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,6BACJ,YACA,MACiD;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,2BACJ,cAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,2BACJ,cACA,MAC8C;AAC9C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,+BACJ,cACA,MACkD;AAClD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,oBACJ,gBAC2C;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iCAAiC,cAAc;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,uBACJ,gBACA,MACyC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iCAAiC,cAAc;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,cAAc,gBAA6D;AAC/E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,iBACJ,gBACA,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,qBACJ,gBACA,UAA4C,CAAC,GACD;AAC5C,UAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,IAAI;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc,kBAAkB,KAAK,WAAW,MAAM;AAAA,IACnF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,kBACJ,gBACA,SACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc,YAAY,mBAAmB,OAAO,CAAC;AAAA,IAClF;AAAA,EACF;AACF;;;AE3UA,IAAAC,mBAA+C;AA+CxC,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAiC;AAC3C,SAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC/C,SAAK,QAAQ,OAAO;AACpB,SAAK,aAAS,+BAAa,qBAAqB,OAAO,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,SAAK,OAAO,MAAM,iBAAiB,MAAM,IAAI,IAAI,EAAE;AAEnD,UAAM,UAAkC;AAAA,MACtC,eAAe,UAAU,KAAK,KAAK;AAAA,MACnC,gBAAgB;AAAA,IAClB;AAEA,UAAM,OAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC7D;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,2BAA2B,KAAK,IAAI;AAAA,IACvD,SAAS,cAAmB;AAC1B,YAAM,IAAI;AAAA,QACR,kCAAkC,MAAM,IAAI,IAAI,KAAK,aAAa,OAAO;AAAA,QACzE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,UAAU,QAAQ,SAAS,MAAM;AACrC,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,kBAAU,MAAM,WAAW;AAAA,MAC7B,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,iBAAiB,MAAM,IAAI,IAAI,YAAY,OAAO;AAAA,QAClD,mBAAmB,SAAS,MAAM;AAAA,QAClC,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,mBACJ,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,gBACJ,UAAkC,CAAC,GACD;AAClC,UAAM,EAAE,YAAY,YAAY,eAAe,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC1E,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,MACnC,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,MACnC,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,IAC3C,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,yCAAyC,EAAE;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,MACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,MACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAkB,IAAgD;AACtE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,yCAAyC,EAAE;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,YACJ,UAAyC,CAAC,GACD;AACzC,UAAM,EAAE,GAAG,aAAa,QAAQ,UAAU,QAAQ,IAAI,SAAS,EAAE,IAAI;AACrE,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,MACjB,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,MACrC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,aAAa,SAAY,EAAE,UAAU,OAAO,QAAQ,EAAE,IAAI,CAAC;AAAA,IACjE,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,oCAAoC,EAAE;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aACJ,MAC0C;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,UACJ,UAAuC,CAAC,GACD;AACvC,UAAM,EAAE,QAAQ,mBAAmB,mBAAmB,MAAM,IAAI,GAAG,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC9F,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,MACjD,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,MACjD,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MACnB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,IACnB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,EAAE;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,SAA6D;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,wBACJ,QACgD;AAChD,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,eAAe,OAAO,cAAc,YAAY;AAAA,MAChD,GAAI,OAAO,eAAe,EAAE,cAAc,OAAO,aAAa,YAAY,EAAE,IAAI,CAAC;AAAA,IACnF,CAAC;AAED,WAAO,KAAK;AAAA,MACV;AAAA,MACA,mDAAmD,EAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,MACiD;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOC,MAAM,oBACJ,SACA,MACsC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACH;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF,MAAM,YAAY,SAA0D;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,OAA4B,CAAC,GACK;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,SACA,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,SACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,SAAiD;AACnE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,MACoB;AACpB,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,QACkC;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO,UAAU,MAAM;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,wBAAgE;AACpE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACJ,UAA2C,CAAC,GACD;AAC3C,UAAM,EAAE,WAAW,iBAAiB,IAAI;AACxC,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,qBAAqB,SAAY,EAAE,kBAAkB,OAAO,gBAAgB,EAAE,IAAI,CAAC;AAAA,IACzF,CAAC;AACD,UAAM,QAAQ,GAAG,SAAS,IAAI,IAAI,EAAE,KAAK;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,KAAK;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,MAC8B;AAC9B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,YACA,MAC8B;AAC9B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,UAAU;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eACJ,YACA,UAA+B,CAAC,GACY;AAC5C,UAAM,KAAK,QAAQ,QAAQ,gBAAgB;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,UAAU,GAAG,EAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBACJ,UAAsC,CAAC,GACD;AACtC,UAAM,KAAK,QAAQ,aAAa,eAAe,QAAQ,UAAU,KAAK;AACtE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,4CAA4C,EAAE;AAAA,IAChD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,MACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,WACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,SAAS;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aACJ,UAA0C,CAAC,GACD;AAC1C,UAAM,EAAE,GAAG,YAAY,MAAM,QAAQ,IAAI,SAAS,EAAE,IAAI;AACxD,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,MACjB,GAAI,eAAe,SAAY,EAAE,YAAY,OAAO,UAAU,EAAE,IAAI,CAAC;AAAA,MACrE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACzB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,EAAE;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,YACA,UAA0C,CAAC,GACD;AAC1C,WAAO,KAAK,aAAa,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,YAC+C;AAC/C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,MAC4C;AAC5C,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF,MAAM,qBACJ,YAC0C;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,WACA,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU,cAAc,SAAS;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,WACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU,cAAc,SAAS;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWC,MAAM,aAAqD;AACzD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAqD;AACzD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAA2D;AAC/D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,UAAiC,CAAC,GACD;AACjC,UAAM,EAAE,QAAQ,MAAM,YAAY,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC7D,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACrC,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,uCAAuC,EAAE;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACJ,cACsC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,uCAAuC,YAAY;AAAA,IAEtD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,iBACJ,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,cACA,OAA8B,CAAC,GACU;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,YAAY;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,cACA,OAA6B,CAAC,GACW;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,YAAY;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,oBACJ,UAAiC,CAAC,GACD;AACjC,UAAM,EAAE,QAAQ,MAAM,YAAY,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC7D,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACrC,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,EAAE;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,mBAAiE;AACrE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,uBACJ,WACyC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0CAA0C,SAAS;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAA0D;AAC9D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAkD;AACtD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cACJ,UAA2C,CAAC,GACD;AAC3C,UAAM,EAAE,MAAM,QAAQ,IAAI,SAAS,EAAE,IAAI;AACzC,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACzB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,EAAE;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,MAC+B;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,aAAoD;AACrE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,aACA,MAC+B;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,aAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,kBACJ,UAAoC,CAAC,GACD;AACpC,UAAM,EAAE,QAAQ,MAAM,IAAI,cAAc,IAAI;AAC5C,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MACnB,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,IAC3C,CAAC;AACD,UAAM,QAAQ,GAAG,SAAS,IAAI,IAAI,EAAE,KAAK;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0CAA0C,KAAK;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,0BAA+E;AACnF,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":["import_adapters","import_adapters"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/admin.ts","../src/request-resilience.ts","../src/dropshipper.ts"],"sourcesContent":["/**\n * @thorprovider/medusa-extended\n * Thor Commerce multi-tenant admin extensions for Medusa\n */\n\nexport { MedusaAdminClient } from './admin';\nexport type { MedusaAdminClientConfig } from './admin';\n\nexport { DropshipperClient } from './dropshipper';\nexport type { DropshipperClientConfig } from './dropshipper';\n\n","/**\n * @fileoverview Medusa Multi-Tenant Admin Client\n * @module @thorprovider/adapters/providers/medusa/admin\n *\n * Wrapper methods for all `/admin/thor/` endpoints defined in the Thor Commerce\n * multi-tenant API contract. Requires an admin API key (`adminConfig.apiKey`)\n * to be provided when creating the Medusa provider.\n *\n * Every method performs a raw `fetch` against the Medusa backend using the\n * admin API key (`x-medusa-access-token`) — the Medusa JS-SDK's admin client\n * does not expose these custom Thor plugin routes, so we use direct HTTP calls.\n *\n * Endpoint reference: `multitenant-api-contract.md`\n */\n\nimport type {\n GetChannelCustomersOptions,\n GetChannelCustomersResponse,\n GetChannelApiKeysResponse,\n GetChannelCategoriesOptions,\n GetChannelCategoriesResponse,\n GetCategorySalesChannelsResponse,\n AssignCategoriesToChannelsBody,\n AssignCategoriesToChannelsResponse,\n UnassignCategoriesFromChannelsBody,\n UnassignCategoriesFromChannelsResponse,\n GetCollectionSalesChannelsResponse,\n AssignCollectionsToChannelsBody,\n AssignCollectionsToChannelsResponse,\n UnassignCollectionsFromChannelsBody,\n UnassignCollectionsFromChannelsResponse,\n GetAdminStorefrontConfigResponse,\n UpdateStorefrontConfigBody,\n UpdateStorefrontConfigResponse,\n GetAdminSiteConfigResponse,\n UpdateSiteConfigBody,\n UpdateSiteConfigResponse,\n GetAdminSiteConfigHistoryOptions,\n GetAdminSiteConfigHistoryResponse,\n RestoreSiteConfigResponse,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the admin client.\n */\nexport interface MedusaAdminClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /** Secret admin API key (x-medusa-access-token) */\n apiKey: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// MedusaAdminClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce multi-tenant admin endpoints (`/admin/thor/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const admin = new MedusaAdminClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * apiKey: process.env.MEDUSA_ADMIN_API_KEY!,\n * });\n *\n * const { customers } = await admin.getChannelCustomers('sc_01JXXXXX');\n * ```\n */\nexport class MedusaAdminClient {\n private baseUrl: string;\n private apiKey: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: MedusaAdminClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.logger = createLogger('MedusaAdminClient', config.debug);\n }\n\n // -----------------------------------------------------------------------\n // Private — HTTP helper\n // -----------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[admin] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n 'x-medusa-access-token': this.apiKey,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[admin] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[admin] ${method} ${path} failed: ${message}`,\n `ADMIN_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -----------------------------------------------------------------------\n // 3.1 — Sales Channel: Customers\n // -----------------------------------------------------------------------\n\n /**\n * Paginated list of customers linked to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/customers`\n */\n async getChannelCustomers(\n salesChannelId: string,\n options: GetChannelCustomersOptions = {},\n ): Promise<GetChannelCustomersResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetChannelCustomersResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.2 — Sales Channel: API Keys\n // -----------------------------------------------------------------------\n\n /**\n * Publishable API keys associated with a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/api-keys`\n */\n async getChannelApiKeys(salesChannelId: string): Promise<GetChannelApiKeysResponse> {\n return this.request<GetChannelApiKeysResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/api-keys`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.3 — Sales Channel: Categories\n // -----------------------------------------------------------------------\n\n /**\n * Product categories assigned to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/categories`\n */\n async getChannelCategories(\n salesChannelId: string,\n options: GetChannelCategoriesOptions = {},\n ): Promise<GetChannelCategoriesResponse> {\n const { limit = 20, offset = 0, include_descendants = false } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n include_descendants: String(include_descendants),\n });\n return this.request<GetChannelCategoriesResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.4 — Category: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a category is assigned.\n *\n * `GET /admin/thor/categories/:id/sales-channels`\n */\n async getCategorySalesChannels(\n categoryId: string,\n ): Promise<GetCategorySalesChannelsResponse> {\n return this.request<GetCategorySalesChannelsResponse>(\n 'GET',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.5 — Category: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a category to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/categories/:id/sales-channels`\n */\n async assignCategoryToChannels(\n categoryId: string,\n body: AssignCategoriesToChannelsBody,\n ): Promise<AssignCategoriesToChannelsResponse> {\n return this.request<AssignCategoriesToChannelsResponse>(\n 'POST',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.6 — Category: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove category assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/categories/:id/sales-channels`\n */\n async unassignCategoryFromChannels(\n categoryId: string,\n body: UnassignCategoriesFromChannelsBody,\n ): Promise<UnassignCategoriesFromChannelsResponse> {\n return this.request<UnassignCategoriesFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.7 — Collection: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a collection is assigned.\n *\n * `GET /admin/thor/collections/:id/sales-channels`\n */\n async getCollectionSalesChannels(\n collectionId: string,\n ): Promise<GetCollectionSalesChannelsResponse> {\n return this.request<GetCollectionSalesChannelsResponse>(\n 'GET',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.8 — Collection: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a collection to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/collections/:id/sales-channels`\n */\n async assignCollectionToChannels(\n collectionId: string,\n body: AssignCollectionsToChannelsBody,\n ): Promise<AssignCollectionsToChannelsResponse> {\n return this.request<AssignCollectionsToChannelsResponse>(\n 'POST',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.9 — Collection: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove collection assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/collections/:id/sales-channels`\n */\n async unassignCollectionFromChannels(\n collectionId: string,\n body: UnassignCollectionsFromChannelsBody,\n ): Promise<UnassignCollectionsFromChannelsResponse> {\n return this.request<UnassignCollectionsFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.10 — Storefront Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the visual storefront configuration for a channel.\n * `:id` is the `sales_channel_id`.\n *\n * `GET /admin/thor/storefront-config/:id`\n */\n async getStorefrontConfig(\n salesChannelId: string,\n ): Promise<GetAdminStorefrontConfigResponse> {\n return this.request<GetAdminStorefrontConfigResponse>(\n 'GET',\n `/admin/thor/storefront-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.11 — Storefront Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the visual storefront configuration for a channel.\n * Triggers the `storefront_config.updated` event → ISR webhook.\n *\n * `PUT /admin/thor/storefront-config/:id`\n */\n async updateStorefrontConfig(\n salesChannelId: string,\n body: UpdateStorefrontConfigBody,\n ): Promise<UpdateStorefrontConfigResponse> {\n return this.request<UpdateStorefrontConfigResponse>(\n 'PUT',\n `/admin/thor/storefront-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.12 — Site Designer Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the active Site Designer configuration for a channel, including the\n * last 10 history entries.\n *\n * `GET /admin/thor/site-config/:sales_channel_id`\n */\n async getSiteConfig(salesChannelId: string): Promise<GetAdminSiteConfigResponse> {\n return this.request<GetAdminSiteConfigResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.13 — Site Designer Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the Site Designer configuration for a channel.\n * Creates a new history entry on every PUT.\n *\n * `PUT /admin/thor/site-config/:sales_channel_id`\n */\n async updateSiteConfig(\n salesChannelId: string,\n body: UpdateSiteConfigBody,\n ): Promise<UpdateSiteConfigResponse> {\n return this.request<UpdateSiteConfigResponse>(\n 'PUT',\n `/admin/thor/site-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.14 — Site Designer Config: History\n // -----------------------------------------------------------------------\n\n /**\n * Full paginated history of Site Designer versions for a channel.\n * Entries are immutable — they are never deleted.\n *\n * `GET /admin/thor/site-config/:sales_channel_id/history`\n */\n async getSiteConfigHistory(\n salesChannelId: string,\n options: GetAdminSiteConfigHistoryOptions = {},\n ): Promise<GetAdminSiteConfigHistoryResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetAdminSiteConfigHistoryResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.15 — Site Designer Config: Restore\n // -----------------------------------------------------------------------\n\n /**\n * Restore a previous Site Designer version.\n * Internally runs the update workflow with the stored config of the target\n * version — this creates a **new** history entry and does NOT mutate past\n * entries.\n *\n * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`\n */\n async restoreSiteConfig(\n salesChannelId: string,\n version: string,\n ): Promise<RestoreSiteConfigResponse> {\n return this.request<RestoreSiteConfigResponse>(\n 'POST',\n `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`,\n );\n }\n}\n","import { ProviderAPIError, backendCircuitBreaker } from '@thorprovider/adapters'\n\ntype RetryConfig = {\n maxRetries?: number\n initialDelayMs?: number\n backoffMultiplier?: number\n maxDelayMs?: number\n timeoutMs?: number\n retryableStatusCodes?: number[]\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelayMs: 300,\n backoffMultiplier: 2,\n maxDelayMs: 5000,\n timeoutMs: 10000,\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction calculateDelay(attempt: number, config: Required<RetryConfig>): number {\n const delay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt)\n return Math.min(delay, config.maxDelayMs)\n}\n\nfunction isRetryableError(error: unknown, config: Required<RetryConfig>): boolean {\n const err = error as { name?: string; message?: string; status?: number }\n\n if (err.name === 'TypeError' || err.message?.includes('fetch failed')) return true\n if (err.name === 'AbortError' || err.message?.includes('timeout')) return true\n if (typeof err.status === 'number' && config.retryableStatusCodes.includes(err.status)) return true\n return false\n}\n\nasync function fetchWithRetry(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig }\n let lastError: unknown\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs)\n\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timeoutId)\n\n if (!response.ok && config.retryableStatusCodes.includes(response.status)) {\n const error = new Error(`HTTP ${response.status}: ${response.statusText}`) as Error & { status?: number }\n error.status = response.status\n throw error\n }\n\n return response\n } catch (error) {\n lastError = error\n const shouldRetry = attempt < config.maxRetries && isRetryableError(error, config)\n\n if (shouldRetry) {\n await sleep(calculateDelay(attempt, config))\n continue\n }\n\n break\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error('Backend request failed')\n}\n\nexport async function fetchBackendWithResilience(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n try {\n return await backendCircuitBreaker.execute(() => fetchWithRetry(url, init, retryConfig))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new ProviderAPIError(`Backend request failed: ${message}`, 'backend', 503)\n }\n}\n","/**\n * @fileoverview Dropshipper Client — Thor Commerce Extended\n * @module @thorprovider/medusa-extended/dropshipper\n *\n * HTTP client for all `/admin/thor/dropshipper/` endpoints.\n *\n * Used by both:\n * - X (ThorProvider admin) — authenticated via admin JWT, role \"Admin\"\n * - Y (Dropshipper panel) — authenticated via dropshipper JWT, role \"Dropshipper\"\n *\n * Access control is enforced server-side via `withDropshipperScope` middleware.\n * This client always sends `Authorization: Bearer <token>`.\n *\n * Endpoint reference: `dropshipping-api-contract.md`\n */\n\nimport type {\n // Onboarding\n OnboardDropshipperBody,\n OnboardDropshipperResponse,\n // Variant Costs\n GetVariantCostsOptions,\n GetVariantCostsResponse,\n CreateVariantCostBody,\n CreateVariantCostResponse,\n BatchVariantCostsBody,\n BatchVariantCostsResponse,\n DeleteVariantCostResponse,\n // Products & Prices\n GetDropshipperProductsOptions,\n GetDropshipperProductsResponse,\n UpdateDropshipperProductStatusBody,\n UpdateDropshipperProductStatusResponse,\n UpdateDropshipperPricesBody,\n UpdateDropshipperPricesResponse,\n // Orders\n GetDropshipperOrdersOptions,\n GetDropshipperOrdersResponse,\n GetDropshipperShippingOptionsParams,\n GetDropshipperShippingOptionsResponse,\n GetDropshipperOrderDetailResponse,\n ExtendedCreateDropshipperOrderBody,\n ExtendedCreateDropshipperOrderResponse,\n SetPaymentCollectorBody,\n SetPaymentCollectorResponse,\n // Order Cancel & Edits\n CancelDropshipperOrderResponse,\n CreateOrderEditBody,\n CreateOrderEditResponse,\n AddOrderEditItemBody,\n AddOrderEditItemResponse,\n ConfirmOrderEditResponse,\n // Order Notes\n OrderNote,\n CreateOrderNoteBody,\n GetOrderNotesResponse,\n DeleteOrderNoteResponse,\n // Dropshipper Addresses\n DropshipperAddressBody,\n DropshipperAddressResponse,\n GetDropshipperAddressesResponse,\n // Categories\n GetDropshipperCategoriesOptions,\n GetDropshipperCategoriesResponse,\n CreateDropshipperCategoryBody,\n UpdateDropshipperCategoryBody,\n DeleteDropshipperCategoryResponse,\n GetProviderCategoriesResponse,\n GetCategoryMappingsOptions,\n GetCategoryMappingsResponse,\n CreateCategoryMappingBody,\n CreateCategoryMappingResponse,\n DeleteCategoryMappingResponse,\n // Customers\n GetDropshipperCustomersOptions,\n GetDropshipperCustomersResponse,\n GetDropshipperCustomerDetailResponse,\n CreateDropshipperCustomerBody,\n CreateDropshipperCustomerResponse,\n // Account & Settlements (Y)\n GetDropshipperAccountResponse,\n GetDropshipperPayableResponse,\n GetDropshipperReceivableResponse,\n GetSettlementsOptions,\n GetSettlementsResponse,\n GetSettlementDetailResponse,\n // Admin Settlements (X)\n CreateSettlementBody,\n CreateSettlementResponse,\n ConfirmSettlementBody,\n CancelSettlementBody,\n UpdateSettlementStatusResponse,\n // Admin Account Management (X)\n GetAdminDropshipperAccountsResponse,\n GetAdminAccountBalanceResponse,\n GetAdminPriceListsResponse,\n GetUserChannelResponse,\n // Promotions\n GetDropshipperPromotionsOptions,\n GetDropshipperPromotionsResponse,\n CreateDropshipperPromotionBody,\n UpdateDropshipperPromotionBody,\n DeleteDropshipperPromotionResponse,\n // Dashboard\n GetDashboardStatsOptions,\n GetDashboardStatsResponse,\n // Storefront (V)\n GetStorefrontDropshipperCategoriesResponse,\n // Inline return types\n DropshipperCategory,\n DropshipperPromotion,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the dropshipper client.\n */\nexport interface DropshipperClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /**\n * JWT token obtained from `POST /auth/user/emailpass`.\n * Used as `Authorization: Bearer <token>`.\n */\n token: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// DropshipperClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce dropshipping endpoints (`/admin/thor/dropshipper/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const client = new DropshipperClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * token: jwtFromLogin,\n * });\n *\n * // Y: list own products\n * const { products } = await client.getProducts();\n *\n * // X: onboard a new dropshipper\n * const { dropshipper } = await client.onboardDropshipper({ ... });\n * ```\n */\nexport class DropshipperClient {\n private baseUrl: string;\n private token: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: DropshipperClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.token = config.token;\n this.logger = createLogger('DropshipperClient', config.debug);\n }\n\n // -------------------------------------------------------------------------\n // Private — HTTP helper\n // -------------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[dropshipper] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[dropshipper] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[dropshipper] ${method} ${path} failed: ${message}`,\n `DROPSHIPPER_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -------------------------------------------------------------------------\n // Onboarding (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a new dropshipper account (sales channel + user + price list).\n *\n * `POST /admin/thor/dropshipper/onboard`\n */\n async onboardDropshipper(\n body: OnboardDropshipperBody,\n ): Promise<OnboardDropshipperResponse> {\n return this.request<OnboardDropshipperResponse>(\n 'POST',\n '/admin/thor/dropshipper/onboard',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Variant Costs (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List variant cost records, optionally filtered by account/variant/currency.\n *\n * `GET /admin/thor/dropshipper/variant-costs`\n */\n async getVariantCosts(\n options: GetVariantCostsOptions = {},\n ): Promise<GetVariantCostsResponse> {\n const { account_id, variant_id, currency_code, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(account_id ? { account_id } : {}),\n ...(variant_id ? { variant_id } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n return this.request<GetVariantCostsResponse>(\n 'GET',\n `/admin/thor/dropshipper/variant-costs?${qs}`,\n );\n }\n\n /**\n * Upsert a single variant cost record.\n *\n * `POST /admin/thor/dropshipper/variant-costs`\n */\n async createVariantCost(\n body: CreateVariantCostBody,\n ): Promise<CreateVariantCostResponse> {\n return this.request<CreateVariantCostResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs',\n body,\n );\n }\n\n /**\n * Batch-upsert variant costs for a given account and currency.\n *\n * `POST /admin/thor/dropshipper/variant-costs/batch`\n */\n async batchVariantCosts(\n body: BatchVariantCostsBody,\n ): Promise<BatchVariantCostsResponse> {\n return this.request<BatchVariantCostsResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs/batch',\n body,\n );\n }\n\n /**\n * Delete a variant cost record by ID.\n *\n * `DELETE /admin/thor/dropshipper/variant-costs/:id`\n */\n async deleteVariantCost(id: string): Promise<DeleteVariantCostResponse> {\n return this.request<DeleteVariantCostResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/variant-costs/${id}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Products (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List products available in Y's channel with cost/margin data.\n *\n * `GET /admin/thor/dropshipper/products`\n */\n async getProducts(\n options: GetDropshipperProductsOptions = {},\n ): Promise<GetDropshipperProductsResponse> {\n const { q, category_id, status, in_stock, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(category_id ? { category_id } : {}),\n ...(status ? { status } : {}),\n ...(in_stock !== undefined ? { in_stock: String(in_stock) } : {}),\n });\n return this.request<GetDropshipperProductsResponse>(\n 'GET',\n `/admin/thor/dropshipper/products?${qs}`,\n );\n }\n\n /**\n * Toggle whether a product is visible in the public store for the current sales channel.\n * This does not mutate the shared global Medusa product status.\n *\n * `POST /admin/thor/dropshipper/products/:id/status`\n */\n async updateProductStatus(\n productId: string,\n body: UpdateDropshipperProductStatusBody,\n ): Promise<UpdateDropshipperProductStatusResponse> {\n return this.request<UpdateDropshipperProductStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/products/${productId}/status`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Prices (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Bulk-update product and variant margins on Y's channel price list.\n *\n * `PUT /admin/thor/dropshipper/prices`\n */\n async updatePrices(\n body: UpdateDropshipperPricesBody,\n ): Promise<UpdateDropshipperPricesResponse> {\n return this.request<UpdateDropshipperPricesResponse>(\n 'PUT',\n '/admin/thor/dropshipper/prices',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Orders (Y + X for set-payment-collector)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of orders in Y's channel.\n *\n * `GET /admin/thor/dropshipper/orders`\n */\n async getOrders(\n options: GetDropshipperOrdersOptions = {},\n ): Promise<GetDropshipperOrdersResponse> {\n const { status, payment_collector, settlement_status, from, to, q, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(payment_collector ? { payment_collector } : {}),\n ...(settlement_status ? { settlement_status } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(q ? { q } : {}),\n });\n return this.request<GetDropshipperOrdersResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders?${qs}`,\n );\n }\n\n /**\n * Full detail for a single order with profit breakdown.\n *\n * `GET /admin/thor/dropshipper/orders/:id`\n */\n async getOrder(orderId: string): Promise<GetDropshipperOrderDetailResponse> {\n return this.request<GetDropshipperOrderDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}`,\n );\n }\n\n /**\n * List shipping options for a manual dropshipper order.\n *\n * `GET /admin/thor/dropshipper/orders/shipping-options`\n */\n async getOrderShippingOptions(\n params: GetDropshipperShippingOptionsParams,\n ): Promise<GetDropshipperShippingOptionsResponse> {\n const qs = new URLSearchParams({\n currency_code: params.currency_code.toLowerCase(),\n ...(params.country_code ? { country_code: params.country_code.toLowerCase() } : {}),\n });\n\n return this.request<GetDropshipperShippingOptionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/shipping-options?${qs}`,\n );\n }\n\n /**\n * Manually create an order on behalf of a customer.\n *\n * `POST /admin/thor/dropshipper/orders`\n */\n async createOrder(\n body: ExtendedCreateDropshipperOrderBody,\n ): Promise<ExtendedCreateDropshipperOrderResponse> {\n return this.request<ExtendedCreateDropshipperOrderResponse>(\n 'POST',\n '/admin/thor/dropshipper/orders',\n body,\n );\n }\n\n /**\n * Set who collects payment for an order (Solo X).\n *\n * `POST /admin/thor/dropshipper/orders/:id/set-payment-collector`\n */\n async setPaymentCollector(\n orderId: string,\n body: SetPaymentCollectorBody,\n ): Promise<SetPaymentCollectorResponse> {\n return this.request<SetPaymentCollectorResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/set-payment-collector`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Order Cancel & Edits (Solo Y) — B-04\n // -------------------------------------------------------------------------\n\n /**\n * Cancel a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/cancel`\n */\n async cancelOrder(orderId: string): Promise<CancelDropshipperOrderResponse> {\n return this.request<CancelDropshipperOrderResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/cancel`,\n );\n }\n\n /**\n * Create an order edit for a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit`\n */\n async createOrderEdit(\n orderId: string,\n body: CreateOrderEditBody = {},\n ): Promise<CreateOrderEditResponse> {\n return this.request<CreateOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit`,\n body,\n );\n }\n\n /**\n * Add an item to the active order edit.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/items`\n */\n async addOrderEditItem(\n orderId: string,\n body: AddOrderEditItemBody,\n ): Promise<AddOrderEditItemResponse> {\n return this.request<AddOrderEditItemResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/items`,\n body,\n );\n }\n\n /**\n * Confirm the active order edit, applying changes to the order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/confirm`\n */\n async confirmOrderEdit(\n orderId: string,\n ): Promise<ConfirmOrderEditResponse> {\n return this.request<ConfirmOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/confirm`,\n );\n }\n\n /**\n * Get all notes for an order.\n *\n * `GET /admin/thor/dropshipper/orders/:id/notes`\n */\n async getOrderNotes(orderId: string): Promise<GetOrderNotesResponse> {\n return this.request<GetOrderNotesResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n );\n }\n\n /**\n * Create a new note for an order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/notes`\n */\n async createOrderNote(\n orderId: string,\n body: CreateOrderNoteBody,\n ): Promise<OrderNote> {\n return this.request<OrderNote>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n body,\n );\n }\n\n /**\n * Delete a note from an order.\n *\n * `DELETE /admin/thor/dropshipper/orders/:id/notes/:noteId`\n */\n async deleteOrderNote(\n orderId: string,\n noteId: string,\n ): Promise<DeleteOrderNoteResponse> {\n return this.request<DeleteOrderNoteResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/orders/${orderId}/notes/${noteId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Custom Categories (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Medusa provider categories linked to Y's channel (read-only).\n *\n * `GET /admin/thor/dropshipper/categories/provider`\n */\n async getProviderCategories(): Promise<GetProviderCategoriesResponse> {\n return this.request<GetProviderCategoriesResponse>(\n 'GET',\n '/admin/thor/dropshipper/categories/provider',\n );\n }\n\n /**\n * List Y's custom product categories.\n *\n * `GET /admin/thor/dropshipper/categories`\n */\n async getCategories(\n options: GetDropshipperCategoriesOptions = {},\n ): Promise<GetDropshipperCategoriesResponse> {\n const { parent_id, include_children } = options;\n const qs = new URLSearchParams({\n ...(parent_id ? { parent_id } : {}),\n ...(include_children !== undefined ? { include_children: String(include_children) } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDropshipperCategoriesResponse>(\n 'GET',\n `/admin/thor/dropshipper/categories${query}`,\n );\n }\n\n /**\n * Create a custom category in Y's channel.\n *\n * `POST /admin/thor/dropshipper/categories`\n */\n async createCategory(\n body: CreateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'POST',\n '/admin/thor/dropshipper/categories',\n body,\n );\n }\n\n /**\n * Update a custom category.\n *\n * `PUT /admin/thor/dropshipper/categories/:id`\n */\n async updateCategory(\n categoryId: string,\n body: UpdateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'PUT',\n `/admin/thor/dropshipper/categories/${categoryId}`,\n body,\n );\n }\n\n /**\n * Delete a custom category.\n *\n * Pass `{ force: true }` to cascade-delete child categories.\n *\n * `DELETE /admin/thor/dropshipper/categories/:id`\n */\n async deleteCategory(\n categoryId: string,\n options: { force?: boolean } = {},\n ): Promise<DeleteDropshipperCategoryResponse> {\n const qs = options.force ? '?force=true' : '';\n return this.request<DeleteDropshipperCategoryResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/categories/${categoryId}${qs}`,\n );\n }\n\n /**\n * List product-to-category mappings, optionally filtered by product.\n *\n * `GET /admin/thor/dropshipper/category-mappings`\n */\n async getCategoryMappings(\n options: GetCategoryMappingsOptions = {},\n ): Promise<GetCategoryMappingsResponse> {\n const qs = options.product_id ? `?product_id=${options.product_id}` : '';\n return this.request<GetCategoryMappingsResponse>(\n 'GET',\n `/admin/thor/dropshipper/category-mappings${qs}`,\n );\n }\n\n /**\n * Map a product to a custom category.\n *\n * `POST /admin/thor/dropshipper/category-mappings`\n */\n async createCategoryMapping(\n body: CreateCategoryMappingBody,\n ): Promise<CreateCategoryMappingResponse> {\n return this.request<CreateCategoryMappingResponse>(\n 'POST',\n '/admin/thor/dropshipper/category-mappings',\n body,\n );\n }\n\n /**\n * Remove a product-to-category mapping.\n *\n * `DELETE /admin/thor/dropshipper/category-mappings/:id`\n */\n async deleteCategoryMapping(\n mappingId: string,\n ): Promise<DeleteCategoryMappingResponse> {\n return this.request<DeleteCategoryMappingResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/category-mappings/${mappingId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customers (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of customers in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers`\n */\n async getCustomers(\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n const { q, has_orders, from, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(has_orders !== undefined ? { has_orders: String(has_orders) } : {}),\n ...(from ? { from } : {}),\n });\n return this.request<GetDropshipperCustomersResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers?${qs}`,\n );\n }\n\n /**\n * Backwards-compatible alias used by the dashboard checkout flow.\n */\n async getChannelCustomers(\n _channelId: string,\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n return this.getCustomers(options);\n }\n\n /**\n * Full detail for a single customer.\n *\n * `GET /admin/thor/dropshipper/customers/:id`\n */\n async getCustomer(\n customerId: string,\n ): Promise<GetDropshipperCustomerDetailResponse> {\n return this.request<GetDropshipperCustomerDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}`,\n );\n }\n\n /**\n * Create a customer scoped to Y's channel.\n *\n * `POST /admin/thor/dropshipper/customers`\n */\n async createCustomer(\n body: CreateDropshipperCustomerBody,\n ): Promise<CreateDropshipperCustomerResponse> {\n return this.request<CreateDropshipperCustomerResponse>(\n 'POST',\n '/admin/thor/dropshipper/customers',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customer Addresses (Solo Y) — B-06\n // -------------------------------------------------------------------------\n\n /**\n * List addresses for a customer in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers/:id/addresses`\n */\n async getCustomerAddresses(\n customerId: string,\n ): Promise<GetDropshipperAddressesResponse> {\n return this.request<GetDropshipperAddressesResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n );\n }\n\n /**\n * Create a new address for a customer.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses`\n */\n async createCustomerAddress(\n customerId: string,\n body: DropshipperAddressBody,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n body,\n );\n }\n\n /**\n * Update an existing customer address.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async updateCustomerAddress(\n customerId: string,\n addressId: string,\n body: Partial<DropshipperAddressBody>,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n body,\n );\n }\n\n /**\n * Delete a customer address.\n *\n * `DELETE /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async deleteCustomerAddress(\n customerId: string,\n addressId: string,\n ): Promise<{ deleted: true; id: string }> {\n return this.request<{ deleted: true; id: string }>(\n 'DELETE',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Account & Settlements (Y read-only)\n // -------------------------------------------------------------------------\n\n /**\n * Y's account info with current balance.\n *\n * `GET /admin/thor/dropshipper/account`\n */\n async getAccount(): Promise<GetDropshipperAccountResponse> {\n return this.request<GetDropshipperAccountResponse>(\n 'GET',\n '/admin/thor/dropshipper/account',\n );\n }\n\n /**\n * Orders where Y owes money to X (Y collected payment, needs to pay costs).\n *\n * `GET /admin/thor/dropshipper/account/payable`\n */\n async getPayable(): Promise<GetDropshipperPayableResponse> {\n return this.request<GetDropshipperPayableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/payable',\n );\n }\n\n /**\n * Orders where X owes money to Y (X collected COD, needs to transfer profit).\n *\n * `GET /admin/thor/dropshipper/account/receivable`\n */\n async getReceivable(): Promise<GetDropshipperReceivableResponse> {\n return this.request<GetDropshipperReceivableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/receivable',\n );\n }\n\n /**\n * List settlements (Y sees own; X can filter by account_id).\n *\n * `GET /admin/thor/dropshipper/settlements`\n */\n async getSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements?${qs}`,\n );\n }\n\n /**\n * Full detail for a single settlement record.\n *\n * `GET /admin/thor/dropshipper/settlements/:id`\n */\n async getSettlement(\n settlementId: string,\n ): Promise<GetSettlementDetailResponse> {\n return this.request<GetSettlementDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements/${settlementId}`,\n\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a settlement record for a dropshipper account.\n *\n * `POST /admin/thor/dropshipper/admin/settlements`\n */\n async createSettlement(\n body: CreateSettlementBody,\n ): Promise<CreateSettlementResponse> {\n return this.request<CreateSettlementResponse>(\n 'POST',\n '/admin/thor/dropshipper/admin/settlements',\n body,\n );\n }\n\n /**\n * Confirm a pending settlement (marks it as paid/received).\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/confirm`\n */\n async confirmSettlement(\n settlementId: string,\n body: ConfirmSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/confirm`,\n body,\n );\n }\n\n /**\n * Cancel a pending settlement.\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/cancel`\n */\n async cancelSettlement(\n settlementId: string,\n body: CancelSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/cancel`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements — list (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * X views all settlement records across all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/settlements`\n */\n async getAdminSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/settlements?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Account Management (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/accounts`\n */\n async getAdminAccounts(): Promise<GetAdminDropshipperAccountsResponse> {\n return this.request<GetAdminDropshipperAccountsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/accounts',\n );\n }\n\n /**\n * Full balance detail for a specific dropshipper account.\n *\n * `GET /admin/thor/dropshipper/admin/accounts/:id/balance`\n */\n async getAdminAccountBalance(\n accountId: string,\n ): Promise<GetAdminAccountBalanceResponse> {\n return this.request<GetAdminAccountBalanceResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/accounts/${accountId}/balance`,\n );\n }\n\n /**\n * List all dropshipper price lists.\n *\n * `GET /admin/thor/dropshipper/admin/price-lists`\n */\n async getAdminPriceLists(): Promise<GetAdminPriceListsResponse> {\n return this.request<GetAdminPriceListsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/price-lists',\n );\n }\n\n /**\n * Utility: look up which sales channel a user belongs to.\n *\n * `GET /admin/thor/dropshipper/admin/user-channel`\n */\n async getUserChannel(): Promise<GetUserChannelResponse> {\n return this.request<GetUserChannelResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/user-channel',\n );\n }\n\n // -------------------------------------------------------------------------\n // Promotions (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Y's promotions (discount codes).\n *\n * `GET /admin/thor/dropshipper/promotions`\n */\n async getPromotions(\n options: GetDropshipperPromotionsOptions = {},\n ): Promise<GetDropshipperPromotionsResponse> {\n const { type, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(type ? { type } : {}),\n });\n return this.request<GetDropshipperPromotionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/promotions?${qs}`,\n );\n }\n\n /**\n * Create a promotion for Y's channel.\n *\n * `POST /admin/thor/dropshipper/promotions`\n */\n async createPromotion(\n body: CreateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'POST',\n '/admin/thor/dropshipper/promotions',\n body,\n );\n }\n\n /**\n * Get a single promotion by ID.\n *\n * `GET /admin/thor/dropshipper/promotions/:id`\n */\n async getPromotion(promotionId: string): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'GET',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n /**\n * Update an existing promotion.\n *\n * `PUT /admin/thor/dropshipper/promotions/:id`\n */\n async updatePromotion(\n promotionId: string,\n body: UpdateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'PUT',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n body,\n );\n }\n\n /**\n * Delete a promotion.\n *\n * `DELETE /admin/thor/dropshipper/promotions/:id`\n */\n async deletePromotion(\n promotionId: string,\n ): Promise<DeleteDropshipperPromotionResponse> {\n return this.request<DeleteDropshipperPromotionResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Dashboard (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Aggregate stats for Y's dashboard (revenue, profit, top products).\n *\n * `GET /admin/thor/dropshipper/dashboard/stats`\n */\n async getDashboardStats(\n options: GetDashboardStatsOptions = {},\n ): Promise<GetDashboardStatsResponse> {\n const { period, from, to, currency_code } = options;\n const qs = new URLSearchParams({\n ...(period ? { period } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDashboardStatsResponse>(\n 'GET',\n `/admin/thor/dropshipper/dashboard/stats${query}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Storefront (V — end customer, uses publishable API key)\n // -------------------------------------------------------------------------\n\n /**\n * Public endpoint: dropshipper-scoped categories for the storefront.\n * Typically called with a publishable API key rather than a JWT.\n *\n * `GET /store/thor/dropshipper-categories`\n */\n async getStorefrontCategories(): Promise<GetStorefrontDropshipperCategoriesResponse> {\n return this.request<GetStorefrontDropshipperCategoriesResponse>(\n 'GET',\n '/store/thor/dropshipper-categories',\n );\n }\n}\n\n// Re-export types used by callers so they don't need to import from @thorprovider/types directly.\nexport type { DropshipperCategory, DropshipperPromotion } from '@thorprovider/types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACyCA,IAAAA,mBAA+C;;;ACzC/C,sBAAwD;AAWxD,IAAM,uBAA8C;AAAA,EAClD,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,sBAAsB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACrD;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAEA,SAAS,eAAe,SAAiB,QAAuC;AAC9E,QAAM,QAAQ,OAAO,iBAAiB,KAAK,IAAI,OAAO,mBAAmB,OAAO;AAChF,SAAO,KAAK,IAAI,OAAO,OAAO,UAAU;AAC1C;AAEA,SAAS,iBAAiB,OAAgB,QAAwC;AAChF,QAAM,MAAM;AAEZ,MAAI,IAAI,SAAS,eAAe,IAAI,SAAS,SAAS,cAAc,EAAG,QAAO;AAC9E,MAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AAC1E,MAAI,OAAO,IAAI,WAAW,YAAY,OAAO,qBAAqB,SAAS,IAAI,MAAM,EAAG,QAAO;AAC/F,SAAO;AACT;AAEA,eAAe,eAAe,KAAa,MAAmB,aAA8C;AAC1G,QAAM,SAAS,EAAE,GAAG,sBAAsB,GAAG,YAAY;AACzD,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,OAAO,YAAY,WAAW;AAC7D,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO,SAAS;AAEvE,YAAM,WAAW,MAAM,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,WAAW,OAAO,CAAC;AACxE,mBAAa,SAAS;AAEtB,UAAI,CAAC,SAAS,MAAM,OAAO,qBAAqB,SAAS,SAAS,MAAM,GAAG;AACzE,cAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AACzE,cAAM,SAAS,SAAS;AACxB,cAAM;AAAA,MACR;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,kBAAY;AACZ,YAAM,cAAc,UAAU,OAAO,cAAc,iBAAiB,OAAO,MAAM;AAEjF,UAAI,aAAa;AACf,cAAM,MAAM,eAAe,SAAS,MAAM,CAAC;AAC3C;AAAA,MACF;AAEA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,wBAAwB;AACnF;AAEA,eAAsB,2BAA2B,KAAa,MAAmB,aAA8C;AAC7H,MAAI;AACF,WAAO,MAAM,sCAAsB,QAAQ,MAAM,eAAe,KAAK,MAAM,WAAW,CAAC;AAAA,EACzF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,IAAI,iCAAiB,2BAA2B,OAAO,IAAI,WAAW,GAAG;AAAA,EACjF;AACF;;;ADCO,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAiC;AAC3C,SAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC/C,SAAK,SAAS,OAAO;AACrB,SAAK,aAAS,+BAAa,qBAAqB,OAAO,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,SAAK,OAAO,MAAM,WAAW,MAAM,IAAI,IAAI,EAAE;AAE7C,UAAM,UAAkC;AAAA,MACtC,yBAAyB,KAAK;AAAA,MAC9B,gBAAgB;AAAA,IAClB;AAEA,UAAM,OAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC7D;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,2BAA2B,KAAK,IAAI;AAAA,IACvD,SAAS,cAAmB;AAC1B,YAAM,IAAI;AAAA,QACR,4BAA4B,MAAM,IAAI,IAAI,KAAK,aAAa,OAAO;AAAA,QACnE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,UAAU,QAAQ,SAAS,MAAM;AACrC,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,kBAAU,MAAM,WAAW;AAAA,MAC7B,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,WAAW,MAAM,IAAI,IAAI,YAAY,OAAO;AAAA,QAC5C,aAAa,SAAS,MAAM;AAAA,QAC5B,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,oBACJ,gBACA,UAAsC,CAAC,GACD;AACtC,UAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,IAAI;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc,oBAAoB,KAAK,WAAW,MAAM;AAAA,IACxF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,kBAAkB,gBAA4D;AAClF,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,qBACJ,gBACA,UAAuC,CAAC,GACD;AACvC,UAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,sBAAsB,MAAM,IAAI;AAChE,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,qBAAqB,OAAO,mBAAmB;AAAA,IACjD,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,8BAA8B,cAAc,eAAe,EAAE;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,yBACJ,YAC2C;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,yBACJ,YACA,MAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,6BACJ,YACA,MACiD;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0BAA0B,UAAU;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,2BACJ,cAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,2BACJ,cACA,MAC8C;AAC9C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,+BACJ,cACA,MACkD;AAClD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,YAAY;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,oBACJ,gBAC2C;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iCAAiC,cAAc;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,uBACJ,gBACA,MACyC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,iCAAiC,cAAc;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,cAAc,gBAA6D;AAC/E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,iBACJ,gBACA,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,qBACJ,gBACA,UAA4C,CAAC,GACD;AAC5C,UAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,IAAI;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc,kBAAkB,KAAK,WAAW,MAAM;AAAA,IACnF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,kBACJ,gBACA,SACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,2BAA2B,cAAc,YAAY,mBAAmB,OAAO,CAAC;AAAA,IAClF;AAAA,EACF;AACF;;;AEzUA,IAAAC,mBAA+C;AA+CxC,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAiC;AAC3C,SAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC/C,SAAK,QAAQ,OAAO;AACpB,SAAK,aAAS,+BAAa,qBAAqB,OAAO,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,IAAI;AAClC,SAAK,OAAO,MAAM,iBAAiB,MAAM,IAAI,IAAI,EAAE;AAEnD,UAAM,UAAkC;AAAA,MACtC,eAAe,UAAU,KAAK,KAAK;AAAA,MACnC,gBAAgB;AAAA,IAClB;AAEA,UAAM,OAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC7D;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,2BAA2B,KAAK,IAAI;AAAA,IACvD,SAAS,cAAmB;AAC1B,YAAM,IAAI;AAAA,QACR,kCAAkC,MAAM,IAAI,IAAI,KAAK,aAAa,OAAO;AAAA,QACzE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,UAAU,QAAQ,SAAS,MAAM;AACrC,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,KAAK;AACjC,kBAAU,MAAM,WAAW;AAAA,MAC7B,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,iBAAiB,MAAM,IAAI,IAAI,YAAY,OAAO;AAAA,QAClD,mBAAmB,SAAS,MAAM;AAAA,QAClC,SAAS;AAAA,MACX;AAAA,IACF;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,mBACJ,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,gBACJ,UAAkC,CAAC,GACD;AAClC,UAAM,EAAE,YAAY,YAAY,eAAe,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC1E,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,MACnC,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,MACnC,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,IAC3C,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,yCAAyC,EAAE;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,MACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,MACoC;AACpC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAkB,IAAgD;AACtE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,yCAAyC,EAAE;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,YACJ,UAAyC,CAAC,GACD;AACzC,UAAM,EAAE,GAAG,aAAa,QAAQ,UAAU,QAAQ,IAAI,SAAS,EAAE,IAAI;AACrE,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,MACjB,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,MACrC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,aAAa,SAAY,EAAE,UAAU,OAAO,QAAQ,EAAE,IAAI,CAAC;AAAA,IACjE,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,oCAAoC,EAAE;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,oBACJ,WACA,MACiD;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,oCAAoC,SAAS;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aACJ,MAC0C;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,UACJ,UAAuC,CAAC,GACD;AACvC,UAAM,EAAE,QAAQ,mBAAmB,mBAAmB,MAAM,IAAI,GAAG,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC9F,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,MACjD,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,MACjD,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MACnB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,IACnB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,EAAE;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,SAA6D;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,wBACJ,QACgD;AAChD,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,eAAe,OAAO,cAAc,YAAY;AAAA,MAChD,GAAI,OAAO,eAAe,EAAE,cAAc,OAAO,aAAa,YAAY,EAAE,IAAI,CAAC;AAAA,IACnF,CAAC;AAED,WAAO,KAAK;AAAA,MACV;AAAA,MACA,mDAAmD,EAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,MACiD;AACjD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOC,MAAM,oBACJ,SACA,MACsC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACH;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF,MAAM,YAAY,SAA0D;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,OAA4B,CAAC,GACK;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,SACA,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,SACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,SAAiD;AACnE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,MACoB;AACpB,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,SACA,QACkC;AAClC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,kCAAkC,OAAO,UAAU,MAAM;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,wBAAgE;AACpE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACJ,UAA2C,CAAC,GACD;AAC3C,UAAM,EAAE,WAAW,iBAAiB,IAAI;AACxC,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,qBAAqB,SAAY,EAAE,kBAAkB,OAAO,gBAAgB,EAAE,IAAI,CAAC;AAAA,IACzF,CAAC;AACD,UAAM,QAAQ,GAAG,SAAS,IAAI,IAAI,EAAE,KAAK;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,KAAK;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,MAC8B;AAC9B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,YACA,MAC8B;AAC9B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,UAAU;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eACJ,YACA,UAA+B,CAAC,GACY;AAC5C,UAAM,KAAK,QAAQ,QAAQ,gBAAgB;AAC3C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,UAAU,GAAG,EAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBACJ,UAAsC,CAAC,GACD;AACtC,UAAM,KAAK,QAAQ,aAAa,eAAe,QAAQ,UAAU,KAAK;AACtE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,4CAA4C,EAAE;AAAA,IAChD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,MACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,WACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,SAAS;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aACJ,UAA0C,CAAC,GACD;AAC1C,UAAM,EAAE,GAAG,YAAY,MAAM,QAAQ,IAAI,SAAS,EAAE,IAAI;AACxD,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,IAAI,EAAE,EAAE,IAAI,CAAC;AAAA,MACjB,GAAI,eAAe,SAAY,EAAE,YAAY,OAAO,UAAU,EAAE,IAAI,CAAC;AAAA,MACrE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACzB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,EAAE;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,YACA,UAA0C,CAAC,GACD;AAC1C,WAAO,KAAK,aAAa,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,YAC+C;AAC/C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,MAC4C;AAC5C,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF,MAAM,qBACJ,YAC0C;AAC1C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,WACA,MACqC;AACrC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU,cAAc,SAAS;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBACJ,YACA,WACwC;AACxC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,qCAAqC,UAAU,cAAc,SAAS;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWC,MAAM,aAAqD;AACzD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAqD;AACzD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBAA2D;AAC/D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,UAAiC,CAAC,GACD;AACjC,UAAM,EAAE,QAAQ,MAAM,YAAY,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC7D,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACrC,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,uCAAuC,EAAE;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACJ,cACsC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,uCAAuC,YAAY;AAAA,IAEtD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,iBACJ,MACmC;AACnC,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBACJ,cACA,OAA8B,CAAC,GACU;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,YAAY;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,cACA,OAA6B,CAAC,GACW;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,YAAY;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,oBACJ,UAAiC,CAAC,GACD;AACjC,UAAM,EAAE,QAAQ,MAAM,YAAY,QAAQ,IAAI,SAAS,EAAE,IAAI;AAC7D,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACrC,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,6CAA6C,EAAE;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,mBAAiE;AACrE,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,uBACJ,WACyC;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0CAA0C,SAAS;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAA0D;AAC9D,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAkD;AACtD,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,cACJ,UAA2C,CAAC,GACD;AAC3C,UAAM,EAAE,MAAM,QAAQ,IAAI,SAAS,EAAE,IAAI;AACzC,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ,OAAO,MAAM;AAAA,MACrB,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACzB,CAAC;AACD,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,EAAE;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,MAC+B;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,aAAoD;AACrE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,aACA,MAC+B;AAC/B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,gBACJ,aAC6C;AAC7C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,sCAAsC,WAAW;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,kBACJ,UAAoC,CAAC,GACD;AACpC,UAAM,EAAE,QAAQ,MAAM,IAAI,cAAc,IAAI;AAC5C,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,GAAI,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MACnB,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,IAC3C,CAAC;AACD,UAAM,QAAQ,GAAG,SAAS,IAAI,IAAI,EAAE,KAAK;AACzC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,0CAA0C,KAAK;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,0BAA+E;AACnF,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","names":["import_adapters","import_adapters"]}
package/dist/index.mjs CHANGED
@@ -491,11 +491,24 @@ var DropshipperClient = class {
491
491
  `/admin/thor/dropshipper/products?${qs}`
492
492
  );
493
493
  }
494
+ /**
495
+ * Toggle whether a product is visible in the public store for the current sales channel.
496
+ * This does not mutate the shared global Medusa product status.
497
+ *
498
+ * `POST /admin/thor/dropshipper/products/:id/status`
499
+ */
500
+ async updateProductStatus(productId, body) {
501
+ return this.request(
502
+ "POST",
503
+ `/admin/thor/dropshipper/products/${productId}/status`,
504
+ body
505
+ );
506
+ }
494
507
  // -------------------------------------------------------------------------
495
508
  // Prices (Solo Y)
496
509
  // -------------------------------------------------------------------------
497
510
  /**
498
- * Bulk-update sale prices on Y's channel price list.
511
+ * Bulk-update product and variant margins on Y's channel price list.
499
512
  *
500
513
  * `PUT /admin/thor/dropshipper/prices`
501
514
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/admin.ts","../src/request-resilience.ts","../src/dropshipper.ts"],"sourcesContent":["/**\n * @fileoverview Medusa Multi-Tenant Admin Client\n * @module @thorprovider/adapters/providers/medusa/admin\n *\n * Wrapper methods for all `/admin/thor/` endpoints defined in the Thor Commerce\n * multi-tenant API contract. Requires an admin API key (`adminConfig.apiKey`)\n * to be provided when creating the Medusa provider.\n *\n * Every method performs a raw `fetch` against the Medusa backend using the\n * admin API key (`x-medusa-access-token`) — the Medusa JS-SDK's admin client\n * does not expose these custom Thor plugin routes, so we use direct HTTP calls.\n *\n * Endpoint reference: `multitenant-api-contract.md`\n */\n\nimport type {\n GetChannelCustomersOptions,\n GetChannelCustomersResponse,\n GetChannelApiKeysResponse,\n GetChannelCategoriesOptions,\n GetChannelCategoriesResponse,\n GetCategorySalesChannelsResponse,\n AssignCategoriesToChannelsBody,\n AssignCategoriesToChannelsResponse,\n UnassignCategoriesFromChannelsBody,\n UnassignCategoriesFromChannelsResponse,\n GetCollectionSalesChannelsResponse,\n AssignCollectionsToChannelsBody,\n AssignCollectionsToChannelsResponse,\n UnassignCollectionsFromChannelsBody,\n UnassignCollectionsFromChannelsResponse,\n GetAdminStorefrontConfigResponse,\n UpdateStorefrontConfigBody,\n UpdateStorefrontConfigResponse,\n GetAdminSiteConfigResponse,\n UpdateSiteConfigBody,\n UpdateSiteConfigResponse,\n GetAdminSiteConfigHistoryOptions,\n GetAdminSiteConfigHistoryResponse,\n RestoreSiteConfigResponse,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the admin client.\n */\nexport interface MedusaAdminClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /** Secret admin API key (x-medusa-access-token) */\n apiKey: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// MedusaAdminClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce multi-tenant admin endpoints (`/admin/thor/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const admin = new MedusaAdminClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * apiKey: process.env.MEDUSA_ADMIN_API_KEY!,\n * });\n *\n * const { customers } = await admin.getChannelCustomers('sc_01JXXXXX');\n * ```\n */\nexport class MedusaAdminClient {\n private baseUrl: string;\n private apiKey: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: MedusaAdminClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.logger = createLogger('MedusaAdminClient', config.debug);\n }\n\n // -----------------------------------------------------------------------\n // Private — HTTP helper\n // -----------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[admin] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n 'x-medusa-access-token': this.apiKey,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[admin] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[admin] ${method} ${path} failed: ${message}`,\n `ADMIN_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -----------------------------------------------------------------------\n // 3.1 — Sales Channel: Customers\n // -----------------------------------------------------------------------\n\n /**\n * Paginated list of customers linked to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/customers`\n */\n async getChannelCustomers(\n salesChannelId: string,\n options: GetChannelCustomersOptions = {},\n ): Promise<GetChannelCustomersResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetChannelCustomersResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.2 — Sales Channel: API Keys\n // -----------------------------------------------------------------------\n\n /**\n * Publishable API keys associated with a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/api-keys`\n */\n async getChannelApiKeys(salesChannelId: string): Promise<GetChannelApiKeysResponse> {\n return this.request<GetChannelApiKeysResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/api-keys`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.3 — Sales Channel: Categories\n // -----------------------------------------------------------------------\n\n /**\n * Product categories assigned to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/categories`\n */\n async getChannelCategories(\n salesChannelId: string,\n options: GetChannelCategoriesOptions = {},\n ): Promise<GetChannelCategoriesResponse> {\n const { limit = 20, offset = 0, include_descendants = false } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n include_descendants: String(include_descendants),\n });\n return this.request<GetChannelCategoriesResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.4 — Category: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a category is assigned.\n *\n * `GET /admin/thor/categories/:id/sales-channels`\n */\n async getCategorySalesChannels(\n categoryId: string,\n ): Promise<GetCategorySalesChannelsResponse> {\n return this.request<GetCategorySalesChannelsResponse>(\n 'GET',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.5 — Category: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a category to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/categories/:id/sales-channels`\n */\n async assignCategoryToChannels(\n categoryId: string,\n body: AssignCategoriesToChannelsBody,\n ): Promise<AssignCategoriesToChannelsResponse> {\n return this.request<AssignCategoriesToChannelsResponse>(\n 'POST',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.6 — Category: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove category assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/categories/:id/sales-channels`\n */\n async unassignCategoryFromChannels(\n categoryId: string,\n body: UnassignCategoriesFromChannelsBody,\n ): Promise<UnassignCategoriesFromChannelsResponse> {\n return this.request<UnassignCategoriesFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.7 — Collection: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a collection is assigned.\n *\n * `GET /admin/thor/collections/:id/sales-channels`\n */\n async getCollectionSalesChannels(\n collectionId: string,\n ): Promise<GetCollectionSalesChannelsResponse> {\n return this.request<GetCollectionSalesChannelsResponse>(\n 'GET',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.8 — Collection: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a collection to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/collections/:id/sales-channels`\n */\n async assignCollectionToChannels(\n collectionId: string,\n body: AssignCollectionsToChannelsBody,\n ): Promise<AssignCollectionsToChannelsResponse> {\n return this.request<AssignCollectionsToChannelsResponse>(\n 'POST',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.9 — Collection: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove collection assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/collections/:id/sales-channels`\n */\n async unassignCollectionFromChannels(\n collectionId: string,\n body: UnassignCollectionsFromChannelsBody,\n ): Promise<UnassignCollectionsFromChannelsResponse> {\n return this.request<UnassignCollectionsFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.10 — Storefront Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the visual storefront configuration for a channel.\n * `:id` is the `sales_channel_id`.\n *\n * `GET /admin/thor/storefront-config/:id`\n */\n async getStorefrontConfig(\n salesChannelId: string,\n ): Promise<GetAdminStorefrontConfigResponse> {\n return this.request<GetAdminStorefrontConfigResponse>(\n 'GET',\n `/admin/thor/storefront-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.11 — Storefront Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the visual storefront configuration for a channel.\n * Triggers the `storefront_config.updated` event → ISR webhook.\n *\n * `PUT /admin/thor/storefront-config/:id`\n */\n async updateStorefrontConfig(\n salesChannelId: string,\n body: UpdateStorefrontConfigBody,\n ): Promise<UpdateStorefrontConfigResponse> {\n return this.request<UpdateStorefrontConfigResponse>(\n 'PUT',\n `/admin/thor/storefront-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.12 — Site Designer Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the active Site Designer configuration for a channel, including the\n * last 10 history entries.\n *\n * `GET /admin/thor/site-config/:sales_channel_id`\n */\n async getSiteConfig(salesChannelId: string): Promise<GetAdminSiteConfigResponse> {\n return this.request<GetAdminSiteConfigResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.13 — Site Designer Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the Site Designer configuration for a channel.\n * Creates a new history entry on every PUT.\n *\n * `PUT /admin/thor/site-config/:sales_channel_id`\n */\n async updateSiteConfig(\n salesChannelId: string,\n body: UpdateSiteConfigBody,\n ): Promise<UpdateSiteConfigResponse> {\n return this.request<UpdateSiteConfigResponse>(\n 'PUT',\n `/admin/thor/site-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.14 — Site Designer Config: History\n // -----------------------------------------------------------------------\n\n /**\n * Full paginated history of Site Designer versions for a channel.\n * Entries are immutable — they are never deleted.\n *\n * `GET /admin/thor/site-config/:sales_channel_id/history`\n */\n async getSiteConfigHistory(\n salesChannelId: string,\n options: GetAdminSiteConfigHistoryOptions = {},\n ): Promise<GetAdminSiteConfigHistoryResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetAdminSiteConfigHistoryResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.15 — Site Designer Config: Restore\n // -----------------------------------------------------------------------\n\n /**\n * Restore a previous Site Designer version.\n * Internally runs the update workflow with the stored config of the target\n * version — this creates a **new** history entry and does NOT mutate past\n * entries.\n *\n * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`\n */\n async restoreSiteConfig(\n salesChannelId: string,\n version: string,\n ): Promise<RestoreSiteConfigResponse> {\n return this.request<RestoreSiteConfigResponse>(\n 'POST',\n `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`,\n );\n }\n}\n","import { ProviderAPIError, backendCircuitBreaker } from '@thorprovider/adapters'\n\ntype RetryConfig = {\n maxRetries?: number\n initialDelayMs?: number\n backoffMultiplier?: number\n maxDelayMs?: number\n timeoutMs?: number\n retryableStatusCodes?: number[]\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelayMs: 300,\n backoffMultiplier: 2,\n maxDelayMs: 5000,\n timeoutMs: 10000,\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction calculateDelay(attempt: number, config: Required<RetryConfig>): number {\n const delay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt)\n return Math.min(delay, config.maxDelayMs)\n}\n\nfunction isRetryableError(error: unknown, config: Required<RetryConfig>): boolean {\n const err = error as { name?: string; message?: string; status?: number }\n\n if (err.name === 'TypeError' || err.message?.includes('fetch failed')) return true\n if (err.name === 'AbortError' || err.message?.includes('timeout')) return true\n if (typeof err.status === 'number' && config.retryableStatusCodes.includes(err.status)) return true\n return false\n}\n\nasync function fetchWithRetry(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig }\n let lastError: unknown\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs)\n\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timeoutId)\n\n if (!response.ok && config.retryableStatusCodes.includes(response.status)) {\n const error = new Error(`HTTP ${response.status}: ${response.statusText}`) as Error & { status?: number }\n error.status = response.status\n throw error\n }\n\n return response\n } catch (error) {\n lastError = error\n const shouldRetry = attempt < config.maxRetries && isRetryableError(error, config)\n\n if (shouldRetry) {\n await sleep(calculateDelay(attempt, config))\n continue\n }\n\n break\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error('Backend request failed')\n}\n\nexport async function fetchBackendWithResilience(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n try {\n return await backendCircuitBreaker.execute(() => fetchWithRetry(url, init, retryConfig))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new ProviderAPIError(`Backend request failed: ${message}`, 'backend', 503)\n }\n}\n","/**\n * @fileoverview Dropshipper Client — Thor Commerce Extended\n * @module @thorprovider/medusa-extended/dropshipper\n *\n * HTTP client for all `/admin/thor/dropshipper/` endpoints.\n *\n * Used by both:\n * - X (ThorProvider admin) — authenticated via admin JWT, role \"Admin\"\n * - Y (Dropshipper panel) — authenticated via dropshipper JWT, role \"Dropshipper\"\n *\n * Access control is enforced server-side via `withDropshipperScope` middleware.\n * This client always sends `Authorization: Bearer <token>`.\n *\n * Endpoint reference: `dropshipping-api-contract.md`\n */\n\nimport type {\n // Onboarding\n OnboardDropshipperBody,\n OnboardDropshipperResponse,\n // Variant Costs\n GetVariantCostsOptions,\n GetVariantCostsResponse,\n CreateVariantCostBody,\n CreateVariantCostResponse,\n BatchVariantCostsBody,\n BatchVariantCostsResponse,\n DeleteVariantCostResponse,\n // Products & Prices\n GetDropshipperProductsOptions,\n GetDropshipperProductsResponse,\n UpdateDropshipperPricesBody,\n UpdateDropshipperPricesResponse,\n // Orders\n GetDropshipperOrdersOptions,\n GetDropshipperOrdersResponse,\n GetDropshipperShippingOptionsParams,\n GetDropshipperShippingOptionsResponse,\n GetDropshipperOrderDetailResponse,\n ExtendedCreateDropshipperOrderBody,\n ExtendedCreateDropshipperOrderResponse,\n SetPaymentCollectorBody,\n SetPaymentCollectorResponse,\n // Order Cancel & Edits\n CancelDropshipperOrderResponse,\n CreateOrderEditBody,\n CreateOrderEditResponse,\n AddOrderEditItemBody,\n AddOrderEditItemResponse,\n ConfirmOrderEditResponse,\n // Order Notes\n OrderNote,\n CreateOrderNoteBody,\n GetOrderNotesResponse,\n DeleteOrderNoteResponse,\n // Dropshipper Addresses\n DropshipperAddressBody,\n DropshipperAddressResponse,\n GetDropshipperAddressesResponse,\n // Categories\n GetDropshipperCategoriesOptions,\n GetDropshipperCategoriesResponse,\n CreateDropshipperCategoryBody,\n UpdateDropshipperCategoryBody,\n DeleteDropshipperCategoryResponse,\n GetProviderCategoriesResponse,\n GetCategoryMappingsOptions,\n GetCategoryMappingsResponse,\n CreateCategoryMappingBody,\n CreateCategoryMappingResponse,\n DeleteCategoryMappingResponse,\n // Customers\n GetDropshipperCustomersOptions,\n GetDropshipperCustomersResponse,\n GetDropshipperCustomerDetailResponse,\n CreateDropshipperCustomerBody,\n CreateDropshipperCustomerResponse,\n // Account & Settlements (Y)\n GetDropshipperAccountResponse,\n GetDropshipperPayableResponse,\n GetDropshipperReceivableResponse,\n GetSettlementsOptions,\n GetSettlementsResponse,\n GetSettlementDetailResponse,\n // Admin Settlements (X)\n CreateSettlementBody,\n CreateSettlementResponse,\n ConfirmSettlementBody,\n CancelSettlementBody,\n UpdateSettlementStatusResponse,\n // Admin Account Management (X)\n GetAdminDropshipperAccountsResponse,\n GetAdminAccountBalanceResponse,\n GetAdminPriceListsResponse,\n GetUserChannelResponse,\n // Promotions\n GetDropshipperPromotionsOptions,\n GetDropshipperPromotionsResponse,\n CreateDropshipperPromotionBody,\n UpdateDropshipperPromotionBody,\n DeleteDropshipperPromotionResponse,\n // Dashboard\n GetDashboardStatsOptions,\n GetDashboardStatsResponse,\n // Storefront (V)\n GetStorefrontDropshipperCategoriesResponse,\n // Inline return types\n DropshipperCategory,\n DropshipperPromotion,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the dropshipper client.\n */\nexport interface DropshipperClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /**\n * JWT token obtained from `POST /auth/user/emailpass`.\n * Used as `Authorization: Bearer <token>`.\n */\n token: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// DropshipperClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce dropshipping endpoints (`/admin/thor/dropshipper/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const client = new DropshipperClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * token: jwtFromLogin,\n * });\n *\n * // Y: list own products\n * const { products } = await client.getProducts();\n *\n * // X: onboard a new dropshipper\n * const { dropshipper } = await client.onboardDropshipper({ ... });\n * ```\n */\nexport class DropshipperClient {\n private baseUrl: string;\n private token: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: DropshipperClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.token = config.token;\n this.logger = createLogger('DropshipperClient', config.debug);\n }\n\n // -------------------------------------------------------------------------\n // Private — HTTP helper\n // -------------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[dropshipper] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[dropshipper] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[dropshipper] ${method} ${path} failed: ${message}`,\n `DROPSHIPPER_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -------------------------------------------------------------------------\n // Onboarding (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a new dropshipper account (sales channel + user + price list).\n *\n * `POST /admin/thor/dropshipper/onboard`\n */\n async onboardDropshipper(\n body: OnboardDropshipperBody,\n ): Promise<OnboardDropshipperResponse> {\n return this.request<OnboardDropshipperResponse>(\n 'POST',\n '/admin/thor/dropshipper/onboard',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Variant Costs (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List variant cost records, optionally filtered by account/variant/currency.\n *\n * `GET /admin/thor/dropshipper/variant-costs`\n */\n async getVariantCosts(\n options: GetVariantCostsOptions = {},\n ): Promise<GetVariantCostsResponse> {\n const { account_id, variant_id, currency_code, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(account_id ? { account_id } : {}),\n ...(variant_id ? { variant_id } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n return this.request<GetVariantCostsResponse>(\n 'GET',\n `/admin/thor/dropshipper/variant-costs?${qs}`,\n );\n }\n\n /**\n * Upsert a single variant cost record.\n *\n * `POST /admin/thor/dropshipper/variant-costs`\n */\n async createVariantCost(\n body: CreateVariantCostBody,\n ): Promise<CreateVariantCostResponse> {\n return this.request<CreateVariantCostResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs',\n body,\n );\n }\n\n /**\n * Batch-upsert variant costs for a given account and currency.\n *\n * `POST /admin/thor/dropshipper/variant-costs/batch`\n */\n async batchVariantCosts(\n body: BatchVariantCostsBody,\n ): Promise<BatchVariantCostsResponse> {\n return this.request<BatchVariantCostsResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs/batch',\n body,\n );\n }\n\n /**\n * Delete a variant cost record by ID.\n *\n * `DELETE /admin/thor/dropshipper/variant-costs/:id`\n */\n async deleteVariantCost(id: string): Promise<DeleteVariantCostResponse> {\n return this.request<DeleteVariantCostResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/variant-costs/${id}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Products (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List products available in Y's channel with cost/margin data.\n *\n * `GET /admin/thor/dropshipper/products`\n */\n async getProducts(\n options: GetDropshipperProductsOptions = {},\n ): Promise<GetDropshipperProductsResponse> {\n const { q, category_id, status, in_stock, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(category_id ? { category_id } : {}),\n ...(status ? { status } : {}),\n ...(in_stock !== undefined ? { in_stock: String(in_stock) } : {}),\n });\n return this.request<GetDropshipperProductsResponse>(\n 'GET',\n `/admin/thor/dropshipper/products?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Prices (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Bulk-update sale prices on Y's channel price list.\n *\n * `PUT /admin/thor/dropshipper/prices`\n */\n async updatePrices(\n body: UpdateDropshipperPricesBody,\n ): Promise<UpdateDropshipperPricesResponse> {\n return this.request<UpdateDropshipperPricesResponse>(\n 'PUT',\n '/admin/thor/dropshipper/prices',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Orders (Y + X for set-payment-collector)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of orders in Y's channel.\n *\n * `GET /admin/thor/dropshipper/orders`\n */\n async getOrders(\n options: GetDropshipperOrdersOptions = {},\n ): Promise<GetDropshipperOrdersResponse> {\n const { status, payment_collector, settlement_status, from, to, q, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(payment_collector ? { payment_collector } : {}),\n ...(settlement_status ? { settlement_status } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(q ? { q } : {}),\n });\n return this.request<GetDropshipperOrdersResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders?${qs}`,\n );\n }\n\n /**\n * Full detail for a single order with profit breakdown.\n *\n * `GET /admin/thor/dropshipper/orders/:id`\n */\n async getOrder(orderId: string): Promise<GetDropshipperOrderDetailResponse> {\n return this.request<GetDropshipperOrderDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}`,\n );\n }\n\n /**\n * List shipping options for a manual dropshipper order.\n *\n * `GET /admin/thor/dropshipper/orders/shipping-options`\n */\n async getOrderShippingOptions(\n params: GetDropshipperShippingOptionsParams,\n ): Promise<GetDropshipperShippingOptionsResponse> {\n const qs = new URLSearchParams({\n currency_code: params.currency_code.toLowerCase(),\n ...(params.country_code ? { country_code: params.country_code.toLowerCase() } : {}),\n });\n\n return this.request<GetDropshipperShippingOptionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/shipping-options?${qs}`,\n );\n }\n\n /**\n * Manually create an order on behalf of a customer.\n *\n * `POST /admin/thor/dropshipper/orders`\n */\n async createOrder(\n body: ExtendedCreateDropshipperOrderBody,\n ): Promise<ExtendedCreateDropshipperOrderResponse> {\n return this.request<ExtendedCreateDropshipperOrderResponse>(\n 'POST',\n '/admin/thor/dropshipper/orders',\n body,\n );\n }\n\n /**\n * Set who collects payment for an order (Solo X).\n *\n * `POST /admin/thor/dropshipper/orders/:id/set-payment-collector`\n */\n async setPaymentCollector(\n orderId: string,\n body: SetPaymentCollectorBody,\n ): Promise<SetPaymentCollectorResponse> {\n return this.request<SetPaymentCollectorResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/set-payment-collector`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Order Cancel & Edits (Solo Y) — B-04\n // -------------------------------------------------------------------------\n\n /**\n * Cancel a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/cancel`\n */\n async cancelOrder(orderId: string): Promise<CancelDropshipperOrderResponse> {\n return this.request<CancelDropshipperOrderResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/cancel`,\n );\n }\n\n /**\n * Create an order edit for a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit`\n */\n async createOrderEdit(\n orderId: string,\n body: CreateOrderEditBody = {},\n ): Promise<CreateOrderEditResponse> {\n return this.request<CreateOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit`,\n body,\n );\n }\n\n /**\n * Add an item to the active order edit.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/items`\n */\n async addOrderEditItem(\n orderId: string,\n body: AddOrderEditItemBody,\n ): Promise<AddOrderEditItemResponse> {\n return this.request<AddOrderEditItemResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/items`,\n body,\n );\n }\n\n /**\n * Confirm the active order edit, applying changes to the order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/confirm`\n */\n async confirmOrderEdit(\n orderId: string,\n ): Promise<ConfirmOrderEditResponse> {\n return this.request<ConfirmOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/confirm`,\n );\n }\n\n /**\n * Get all notes for an order.\n *\n * `GET /admin/thor/dropshipper/orders/:id/notes`\n */\n async getOrderNotes(orderId: string): Promise<GetOrderNotesResponse> {\n return this.request<GetOrderNotesResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n );\n }\n\n /**\n * Create a new note for an order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/notes`\n */\n async createOrderNote(\n orderId: string,\n body: CreateOrderNoteBody,\n ): Promise<OrderNote> {\n return this.request<OrderNote>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n body,\n );\n }\n\n /**\n * Delete a note from an order.\n *\n * `DELETE /admin/thor/dropshipper/orders/:id/notes/:noteId`\n */\n async deleteOrderNote(\n orderId: string,\n noteId: string,\n ): Promise<DeleteOrderNoteResponse> {\n return this.request<DeleteOrderNoteResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/orders/${orderId}/notes/${noteId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Custom Categories (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Medusa provider categories linked to Y's channel (read-only).\n *\n * `GET /admin/thor/dropshipper/categories/provider`\n */\n async getProviderCategories(): Promise<GetProviderCategoriesResponse> {\n return this.request<GetProviderCategoriesResponse>(\n 'GET',\n '/admin/thor/dropshipper/categories/provider',\n );\n }\n\n /**\n * List Y's custom product categories.\n *\n * `GET /admin/thor/dropshipper/categories`\n */\n async getCategories(\n options: GetDropshipperCategoriesOptions = {},\n ): Promise<GetDropshipperCategoriesResponse> {\n const { parent_id, include_children } = options;\n const qs = new URLSearchParams({\n ...(parent_id ? { parent_id } : {}),\n ...(include_children !== undefined ? { include_children: String(include_children) } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDropshipperCategoriesResponse>(\n 'GET',\n `/admin/thor/dropshipper/categories${query}`,\n );\n }\n\n /**\n * Create a custom category in Y's channel.\n *\n * `POST /admin/thor/dropshipper/categories`\n */\n async createCategory(\n body: CreateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'POST',\n '/admin/thor/dropshipper/categories',\n body,\n );\n }\n\n /**\n * Update a custom category.\n *\n * `PUT /admin/thor/dropshipper/categories/:id`\n */\n async updateCategory(\n categoryId: string,\n body: UpdateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'PUT',\n `/admin/thor/dropshipper/categories/${categoryId}`,\n body,\n );\n }\n\n /**\n * Delete a custom category.\n *\n * Pass `{ force: true }` to cascade-delete child categories.\n *\n * `DELETE /admin/thor/dropshipper/categories/:id`\n */\n async deleteCategory(\n categoryId: string,\n options: { force?: boolean } = {},\n ): Promise<DeleteDropshipperCategoryResponse> {\n const qs = options.force ? '?force=true' : '';\n return this.request<DeleteDropshipperCategoryResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/categories/${categoryId}${qs}`,\n );\n }\n\n /**\n * List product-to-category mappings, optionally filtered by product.\n *\n * `GET /admin/thor/dropshipper/category-mappings`\n */\n async getCategoryMappings(\n options: GetCategoryMappingsOptions = {},\n ): Promise<GetCategoryMappingsResponse> {\n const qs = options.product_id ? `?product_id=${options.product_id}` : '';\n return this.request<GetCategoryMappingsResponse>(\n 'GET',\n `/admin/thor/dropshipper/category-mappings${qs}`,\n );\n }\n\n /**\n * Map a product to a custom category.\n *\n * `POST /admin/thor/dropshipper/category-mappings`\n */\n async createCategoryMapping(\n body: CreateCategoryMappingBody,\n ): Promise<CreateCategoryMappingResponse> {\n return this.request<CreateCategoryMappingResponse>(\n 'POST',\n '/admin/thor/dropshipper/category-mappings',\n body,\n );\n }\n\n /**\n * Remove a product-to-category mapping.\n *\n * `DELETE /admin/thor/dropshipper/category-mappings/:id`\n */\n async deleteCategoryMapping(\n mappingId: string,\n ): Promise<DeleteCategoryMappingResponse> {\n return this.request<DeleteCategoryMappingResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/category-mappings/${mappingId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customers (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of customers in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers`\n */\n async getCustomers(\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n const { q, has_orders, from, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(has_orders !== undefined ? { has_orders: String(has_orders) } : {}),\n ...(from ? { from } : {}),\n });\n return this.request<GetDropshipperCustomersResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers?${qs}`,\n );\n }\n\n /**\n * Backwards-compatible alias used by the dashboard checkout flow.\n */\n async getChannelCustomers(\n _channelId: string,\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n return this.getCustomers(options);\n }\n\n /**\n * Full detail for a single customer.\n *\n * `GET /admin/thor/dropshipper/customers/:id`\n */\n async getCustomer(\n customerId: string,\n ): Promise<GetDropshipperCustomerDetailResponse> {\n return this.request<GetDropshipperCustomerDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}`,\n );\n }\n\n /**\n * Create a customer scoped to Y's channel.\n *\n * `POST /admin/thor/dropshipper/customers`\n */\n async createCustomer(\n body: CreateDropshipperCustomerBody,\n ): Promise<CreateDropshipperCustomerResponse> {\n return this.request<CreateDropshipperCustomerResponse>(\n 'POST',\n '/admin/thor/dropshipper/customers',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customer Addresses (Solo Y) — B-06\n // -------------------------------------------------------------------------\n\n /**\n * List addresses for a customer in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers/:id/addresses`\n */\n async getCustomerAddresses(\n customerId: string,\n ): Promise<GetDropshipperAddressesResponse> {\n return this.request<GetDropshipperAddressesResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n );\n }\n\n /**\n * Create a new address for a customer.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses`\n */\n async createCustomerAddress(\n customerId: string,\n body: DropshipperAddressBody,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n body,\n );\n }\n\n /**\n * Update an existing customer address.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async updateCustomerAddress(\n customerId: string,\n addressId: string,\n body: Partial<DropshipperAddressBody>,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n body,\n );\n }\n\n /**\n * Delete a customer address.\n *\n * `DELETE /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async deleteCustomerAddress(\n customerId: string,\n addressId: string,\n ): Promise<{ deleted: true; id: string }> {\n return this.request<{ deleted: true; id: string }>(\n 'DELETE',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Account & Settlements (Y read-only)\n // -------------------------------------------------------------------------\n\n /**\n * Y's account info with current balance.\n *\n * `GET /admin/thor/dropshipper/account`\n */\n async getAccount(): Promise<GetDropshipperAccountResponse> {\n return this.request<GetDropshipperAccountResponse>(\n 'GET',\n '/admin/thor/dropshipper/account',\n );\n }\n\n /**\n * Orders where Y owes money to X (Y collected payment, needs to pay costs).\n *\n * `GET /admin/thor/dropshipper/account/payable`\n */\n async getPayable(): Promise<GetDropshipperPayableResponse> {\n return this.request<GetDropshipperPayableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/payable',\n );\n }\n\n /**\n * Orders where X owes money to Y (X collected COD, needs to transfer profit).\n *\n * `GET /admin/thor/dropshipper/account/receivable`\n */\n async getReceivable(): Promise<GetDropshipperReceivableResponse> {\n return this.request<GetDropshipperReceivableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/receivable',\n );\n }\n\n /**\n * List settlements (Y sees own; X can filter by account_id).\n *\n * `GET /admin/thor/dropshipper/settlements`\n */\n async getSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements?${qs}`,\n );\n }\n\n /**\n * Full detail for a single settlement record.\n *\n * `GET /admin/thor/dropshipper/settlements/:id`\n */\n async getSettlement(\n settlementId: string,\n ): Promise<GetSettlementDetailResponse> {\n return this.request<GetSettlementDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements/${settlementId}`,\n\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a settlement record for a dropshipper account.\n *\n * `POST /admin/thor/dropshipper/admin/settlements`\n */\n async createSettlement(\n body: CreateSettlementBody,\n ): Promise<CreateSettlementResponse> {\n return this.request<CreateSettlementResponse>(\n 'POST',\n '/admin/thor/dropshipper/admin/settlements',\n body,\n );\n }\n\n /**\n * Confirm a pending settlement (marks it as paid/received).\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/confirm`\n */\n async confirmSettlement(\n settlementId: string,\n body: ConfirmSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/confirm`,\n body,\n );\n }\n\n /**\n * Cancel a pending settlement.\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/cancel`\n */\n async cancelSettlement(\n settlementId: string,\n body: CancelSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/cancel`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements — list (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * X views all settlement records across all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/settlements`\n */\n async getAdminSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/settlements?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Account Management (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/accounts`\n */\n async getAdminAccounts(): Promise<GetAdminDropshipperAccountsResponse> {\n return this.request<GetAdminDropshipperAccountsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/accounts',\n );\n }\n\n /**\n * Full balance detail for a specific dropshipper account.\n *\n * `GET /admin/thor/dropshipper/admin/accounts/:id/balance`\n */\n async getAdminAccountBalance(\n accountId: string,\n ): Promise<GetAdminAccountBalanceResponse> {\n return this.request<GetAdminAccountBalanceResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/accounts/${accountId}/balance`,\n );\n }\n\n /**\n * List all dropshipper price lists.\n *\n * `GET /admin/thor/dropshipper/admin/price-lists`\n */\n async getAdminPriceLists(): Promise<GetAdminPriceListsResponse> {\n return this.request<GetAdminPriceListsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/price-lists',\n );\n }\n\n /**\n * Utility: look up which sales channel a user belongs to.\n *\n * `GET /admin/thor/dropshipper/admin/user-channel`\n */\n async getUserChannel(): Promise<GetUserChannelResponse> {\n return this.request<GetUserChannelResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/user-channel',\n );\n }\n\n // -------------------------------------------------------------------------\n // Promotions (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Y's promotions (discount codes).\n *\n * `GET /admin/thor/dropshipper/promotions`\n */\n async getPromotions(\n options: GetDropshipperPromotionsOptions = {},\n ): Promise<GetDropshipperPromotionsResponse> {\n const { type, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(type ? { type } : {}),\n });\n return this.request<GetDropshipperPromotionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/promotions?${qs}`,\n );\n }\n\n /**\n * Create a promotion for Y's channel.\n *\n * `POST /admin/thor/dropshipper/promotions`\n */\n async createPromotion(\n body: CreateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'POST',\n '/admin/thor/dropshipper/promotions',\n body,\n );\n }\n\n /**\n * Get a single promotion by ID.\n *\n * `GET /admin/thor/dropshipper/promotions/:id`\n */\n async getPromotion(promotionId: string): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'GET',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n /**\n * Update an existing promotion.\n *\n * `PUT /admin/thor/dropshipper/promotions/:id`\n */\n async updatePromotion(\n promotionId: string,\n body: UpdateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'PUT',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n body,\n );\n }\n\n /**\n * Delete a promotion.\n *\n * `DELETE /admin/thor/dropshipper/promotions/:id`\n */\n async deletePromotion(\n promotionId: string,\n ): Promise<DeleteDropshipperPromotionResponse> {\n return this.request<DeleteDropshipperPromotionResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Dashboard (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Aggregate stats for Y's dashboard (revenue, profit, top products).\n *\n * `GET /admin/thor/dropshipper/dashboard/stats`\n */\n async getDashboardStats(\n options: GetDashboardStatsOptions = {},\n ): Promise<GetDashboardStatsResponse> {\n const { period, from, to, currency_code } = options;\n const qs = new URLSearchParams({\n ...(period ? { period } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDashboardStatsResponse>(\n 'GET',\n `/admin/thor/dropshipper/dashboard/stats${query}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Storefront (V — end customer, uses publishable API key)\n // -------------------------------------------------------------------------\n\n /**\n * Public endpoint: dropshipper-scoped categories for the storefront.\n * Typically called with a publishable API key rather than a JWT.\n *\n * `GET /store/thor/dropshipper-categories`\n */\n async getStorefrontCategories(): Promise<GetStorefrontDropshipperCategoriesResponse> {\n return this.request<GetStorefrontDropshipperCategoriesResponse>(\n 'GET',\n '/store/thor/dropshipper-categories',\n );\n }\n}\n\n// Re-export types used by callers so they don't need to import from @thorprovider/types directly.\nexport type { DropshipperCategory, DropshipperPromotion } from '@thorprovider/types';\n"],"mappings":"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","names":["ProviderAPIError","ProviderAPIError","createLogger","ProviderAPIError","createLogger","ProviderAPIError"]}
1
+ {"version":3,"sources":["../src/admin.ts","../src/request-resilience.ts","../src/dropshipper.ts"],"sourcesContent":["/**\n * @fileoverview Medusa Multi-Tenant Admin Client\n * @module @thorprovider/adapters/providers/medusa/admin\n *\n * Wrapper methods for all `/admin/thor/` endpoints defined in the Thor Commerce\n * multi-tenant API contract. Requires an admin API key (`adminConfig.apiKey`)\n * to be provided when creating the Medusa provider.\n *\n * Every method performs a raw `fetch` against the Medusa backend using the\n * admin API key (`x-medusa-access-token`) — the Medusa JS-SDK's admin client\n * does not expose these custom Thor plugin routes, so we use direct HTTP calls.\n *\n * Endpoint reference: `multitenant-api-contract.md`\n */\n\nimport type {\n GetChannelCustomersOptions,\n GetChannelCustomersResponse,\n GetChannelApiKeysResponse,\n GetChannelCategoriesOptions,\n GetChannelCategoriesResponse,\n GetCategorySalesChannelsResponse,\n AssignCategoriesToChannelsBody,\n AssignCategoriesToChannelsResponse,\n UnassignCategoriesFromChannelsBody,\n UnassignCategoriesFromChannelsResponse,\n GetCollectionSalesChannelsResponse,\n AssignCollectionsToChannelsBody,\n AssignCollectionsToChannelsResponse,\n UnassignCollectionsFromChannelsBody,\n UnassignCollectionsFromChannelsResponse,\n GetAdminStorefrontConfigResponse,\n UpdateStorefrontConfigBody,\n UpdateStorefrontConfigResponse,\n GetAdminSiteConfigResponse,\n UpdateSiteConfigBody,\n UpdateSiteConfigResponse,\n GetAdminSiteConfigHistoryOptions,\n GetAdminSiteConfigHistoryResponse,\n RestoreSiteConfigResponse,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the admin client.\n */\nexport interface MedusaAdminClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /** Secret admin API key (x-medusa-access-token) */\n apiKey: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// MedusaAdminClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce multi-tenant admin endpoints (`/admin/thor/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const admin = new MedusaAdminClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * apiKey: process.env.MEDUSA_ADMIN_API_KEY!,\n * });\n *\n * const { customers } = await admin.getChannelCustomers('sc_01JXXXXX');\n * ```\n */\nexport class MedusaAdminClient {\n private baseUrl: string;\n private apiKey: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: MedusaAdminClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.logger = createLogger('MedusaAdminClient', config.debug);\n }\n\n // -----------------------------------------------------------------------\n // Private — HTTP helper\n // -----------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[admin] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n 'x-medusa-access-token': this.apiKey,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[admin] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[admin] ${method} ${path} failed: ${message}`,\n `ADMIN_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -----------------------------------------------------------------------\n // 3.1 — Sales Channel: Customers\n // -----------------------------------------------------------------------\n\n /**\n * Paginated list of customers linked to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/customers`\n */\n async getChannelCustomers(\n salesChannelId: string,\n options: GetChannelCustomersOptions = {},\n ): Promise<GetChannelCustomersResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetChannelCustomersResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/customers?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.2 — Sales Channel: API Keys\n // -----------------------------------------------------------------------\n\n /**\n * Publishable API keys associated with a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/api-keys`\n */\n async getChannelApiKeys(salesChannelId: string): Promise<GetChannelApiKeysResponse> {\n return this.request<GetChannelApiKeysResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/api-keys`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.3 — Sales Channel: Categories\n // -----------------------------------------------------------------------\n\n /**\n * Product categories assigned to a sales channel.\n *\n * `GET /admin/thor/sales-channels/:id/categories`\n */\n async getChannelCategories(\n salesChannelId: string,\n options: GetChannelCategoriesOptions = {},\n ): Promise<GetChannelCategoriesResponse> {\n const { limit = 20, offset = 0, include_descendants = false } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n include_descendants: String(include_descendants),\n });\n return this.request<GetChannelCategoriesResponse>(\n 'GET',\n `/admin/thor/sales-channels/${salesChannelId}/categories?${qs}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.4 — Category: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a category is assigned.\n *\n * `GET /admin/thor/categories/:id/sales-channels`\n */\n async getCategorySalesChannels(\n categoryId: string,\n ): Promise<GetCategorySalesChannelsResponse> {\n return this.request<GetCategorySalesChannelsResponse>(\n 'GET',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.5 — Category: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a category to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/categories/:id/sales-channels`\n */\n async assignCategoryToChannels(\n categoryId: string,\n body: AssignCategoriesToChannelsBody,\n ): Promise<AssignCategoriesToChannelsResponse> {\n return this.request<AssignCategoriesToChannelsResponse>(\n 'POST',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.6 — Category: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove category assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/categories/:id/sales-channels`\n */\n async unassignCategoryFromChannels(\n categoryId: string,\n body: UnassignCategoriesFromChannelsBody,\n ): Promise<UnassignCategoriesFromChannelsResponse> {\n return this.request<UnassignCategoriesFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/categories/${categoryId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.7 — Collection: Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Sales channels to which a collection is assigned.\n *\n * `GET /admin/thor/collections/:id/sales-channels`\n */\n async getCollectionSalesChannels(\n collectionId: string,\n ): Promise<GetCollectionSalesChannelsResponse> {\n return this.request<GetCollectionSalesChannelsResponse>(\n 'GET',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.8 — Collection: Assign to Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Assign a collection to one or more sales channels (idempotent).\n *\n * `POST /admin/thor/collections/:id/sales-channels`\n */\n async assignCollectionToChannels(\n collectionId: string,\n body: AssignCollectionsToChannelsBody,\n ): Promise<AssignCollectionsToChannelsResponse> {\n return this.request<AssignCollectionsToChannelsResponse>(\n 'POST',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.9 — Collection: Unassign from Sales Channels\n // -----------------------------------------------------------------------\n\n /**\n * Remove collection assignment from one or more sales channels (idempotent).\n *\n * `DELETE /admin/thor/collections/:id/sales-channels`\n */\n async unassignCollectionFromChannels(\n collectionId: string,\n body: UnassignCollectionsFromChannelsBody,\n ): Promise<UnassignCollectionsFromChannelsResponse> {\n return this.request<UnassignCollectionsFromChannelsResponse>(\n 'DELETE',\n `/admin/thor/collections/${collectionId}/sales-channels`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.10 — Storefront Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the visual storefront configuration for a channel.\n * `:id` is the `sales_channel_id`.\n *\n * `GET /admin/thor/storefront-config/:id`\n */\n async getStorefrontConfig(\n salesChannelId: string,\n ): Promise<GetAdminStorefrontConfigResponse> {\n return this.request<GetAdminStorefrontConfigResponse>(\n 'GET',\n `/admin/thor/storefront-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.11 — Storefront Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the visual storefront configuration for a channel.\n * Triggers the `storefront_config.updated` event → ISR webhook.\n *\n * `PUT /admin/thor/storefront-config/:id`\n */\n async updateStorefrontConfig(\n salesChannelId: string,\n body: UpdateStorefrontConfigBody,\n ): Promise<UpdateStorefrontConfigResponse> {\n return this.request<UpdateStorefrontConfigResponse>(\n 'PUT',\n `/admin/thor/storefront-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.12 — Site Designer Config: Read\n // -----------------------------------------------------------------------\n\n /**\n * Read the active Site Designer configuration for a channel, including the\n * last 10 history entries.\n *\n * `GET /admin/thor/site-config/:sales_channel_id`\n */\n async getSiteConfig(salesChannelId: string): Promise<GetAdminSiteConfigResponse> {\n return this.request<GetAdminSiteConfigResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.13 — Site Designer Config: Update\n // -----------------------------------------------------------------------\n\n /**\n * Update the Site Designer configuration for a channel.\n * Creates a new history entry on every PUT.\n *\n * `PUT /admin/thor/site-config/:sales_channel_id`\n */\n async updateSiteConfig(\n salesChannelId: string,\n body: UpdateSiteConfigBody,\n ): Promise<UpdateSiteConfigResponse> {\n return this.request<UpdateSiteConfigResponse>(\n 'PUT',\n `/admin/thor/site-config/${salesChannelId}`,\n body,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.14 — Site Designer Config: History\n // -----------------------------------------------------------------------\n\n /**\n * Full paginated history of Site Designer versions for a channel.\n * Entries are immutable — they are never deleted.\n *\n * `GET /admin/thor/site-config/:sales_channel_id/history`\n */\n async getSiteConfigHistory(\n salesChannelId: string,\n options: GetAdminSiteConfigHistoryOptions = {},\n ): Promise<GetAdminSiteConfigHistoryResponse> {\n const { limit = 20, offset = 0 } = options;\n return this.request<GetAdminSiteConfigHistoryResponse>(\n 'GET',\n `/admin/thor/site-config/${salesChannelId}/history?limit=${limit}&offset=${offset}`,\n );\n }\n\n // -----------------------------------------------------------------------\n // 3.15 — Site Designer Config: Restore\n // -----------------------------------------------------------------------\n\n /**\n * Restore a previous Site Designer version.\n * Internally runs the update workflow with the stored config of the target\n * version — this creates a **new** history entry and does NOT mutate past\n * entries.\n *\n * `POST /admin/thor/site-config/:sales_channel_id/restore/:version`\n */\n async restoreSiteConfig(\n salesChannelId: string,\n version: string,\n ): Promise<RestoreSiteConfigResponse> {\n return this.request<RestoreSiteConfigResponse>(\n 'POST',\n `/admin/thor/site-config/${salesChannelId}/restore/${encodeURIComponent(version)}`,\n );\n }\n}\n","import { ProviderAPIError, backendCircuitBreaker } from '@thorprovider/adapters'\n\ntype RetryConfig = {\n maxRetries?: number\n initialDelayMs?: number\n backoffMultiplier?: number\n maxDelayMs?: number\n timeoutMs?: number\n retryableStatusCodes?: number[]\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelayMs: 300,\n backoffMultiplier: 2,\n maxDelayMs: 5000,\n timeoutMs: 10000,\n retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction calculateDelay(attempt: number, config: Required<RetryConfig>): number {\n const delay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt)\n return Math.min(delay, config.maxDelayMs)\n}\n\nfunction isRetryableError(error: unknown, config: Required<RetryConfig>): boolean {\n const err = error as { name?: string; message?: string; status?: number }\n\n if (err.name === 'TypeError' || err.message?.includes('fetch failed')) return true\n if (err.name === 'AbortError' || err.message?.includes('timeout')) return true\n if (typeof err.status === 'number' && config.retryableStatusCodes.includes(err.status)) return true\n return false\n}\n\nasync function fetchWithRetry(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig }\n let lastError: unknown\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), config.timeoutMs)\n\n const response = await fetch(url, { ...init, signal: controller.signal })\n clearTimeout(timeoutId)\n\n if (!response.ok && config.retryableStatusCodes.includes(response.status)) {\n const error = new Error(`HTTP ${response.status}: ${response.statusText}`) as Error & { status?: number }\n error.status = response.status\n throw error\n }\n\n return response\n } catch (error) {\n lastError = error\n const shouldRetry = attempt < config.maxRetries && isRetryableError(error, config)\n\n if (shouldRetry) {\n await sleep(calculateDelay(attempt, config))\n continue\n }\n\n break\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error('Backend request failed')\n}\n\nexport async function fetchBackendWithResilience(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {\n try {\n return await backendCircuitBreaker.execute(() => fetchWithRetry(url, init, retryConfig))\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new ProviderAPIError(`Backend request failed: ${message}`, 'backend', 503)\n }\n}\n","/**\n * @fileoverview Dropshipper Client — Thor Commerce Extended\n * @module @thorprovider/medusa-extended/dropshipper\n *\n * HTTP client for all `/admin/thor/dropshipper/` endpoints.\n *\n * Used by both:\n * - X (ThorProvider admin) — authenticated via admin JWT, role \"Admin\"\n * - Y (Dropshipper panel) — authenticated via dropshipper JWT, role \"Dropshipper\"\n *\n * Access control is enforced server-side via `withDropshipperScope` middleware.\n * This client always sends `Authorization: Bearer <token>`.\n *\n * Endpoint reference: `dropshipping-api-contract.md`\n */\n\nimport type {\n // Onboarding\n OnboardDropshipperBody,\n OnboardDropshipperResponse,\n // Variant Costs\n GetVariantCostsOptions,\n GetVariantCostsResponse,\n CreateVariantCostBody,\n CreateVariantCostResponse,\n BatchVariantCostsBody,\n BatchVariantCostsResponse,\n DeleteVariantCostResponse,\n // Products & Prices\n GetDropshipperProductsOptions,\n GetDropshipperProductsResponse,\n UpdateDropshipperProductStatusBody,\n UpdateDropshipperProductStatusResponse,\n UpdateDropshipperPricesBody,\n UpdateDropshipperPricesResponse,\n // Orders\n GetDropshipperOrdersOptions,\n GetDropshipperOrdersResponse,\n GetDropshipperShippingOptionsParams,\n GetDropshipperShippingOptionsResponse,\n GetDropshipperOrderDetailResponse,\n ExtendedCreateDropshipperOrderBody,\n ExtendedCreateDropshipperOrderResponse,\n SetPaymentCollectorBody,\n SetPaymentCollectorResponse,\n // Order Cancel & Edits\n CancelDropshipperOrderResponse,\n CreateOrderEditBody,\n CreateOrderEditResponse,\n AddOrderEditItemBody,\n AddOrderEditItemResponse,\n ConfirmOrderEditResponse,\n // Order Notes\n OrderNote,\n CreateOrderNoteBody,\n GetOrderNotesResponse,\n DeleteOrderNoteResponse,\n // Dropshipper Addresses\n DropshipperAddressBody,\n DropshipperAddressResponse,\n GetDropshipperAddressesResponse,\n // Categories\n GetDropshipperCategoriesOptions,\n GetDropshipperCategoriesResponse,\n CreateDropshipperCategoryBody,\n UpdateDropshipperCategoryBody,\n DeleteDropshipperCategoryResponse,\n GetProviderCategoriesResponse,\n GetCategoryMappingsOptions,\n GetCategoryMappingsResponse,\n CreateCategoryMappingBody,\n CreateCategoryMappingResponse,\n DeleteCategoryMappingResponse,\n // Customers\n GetDropshipperCustomersOptions,\n GetDropshipperCustomersResponse,\n GetDropshipperCustomerDetailResponse,\n CreateDropshipperCustomerBody,\n CreateDropshipperCustomerResponse,\n // Account & Settlements (Y)\n GetDropshipperAccountResponse,\n GetDropshipperPayableResponse,\n GetDropshipperReceivableResponse,\n GetSettlementsOptions,\n GetSettlementsResponse,\n GetSettlementDetailResponse,\n // Admin Settlements (X)\n CreateSettlementBody,\n CreateSettlementResponse,\n ConfirmSettlementBody,\n CancelSettlementBody,\n UpdateSettlementStatusResponse,\n // Admin Account Management (X)\n GetAdminDropshipperAccountsResponse,\n GetAdminAccountBalanceResponse,\n GetAdminPriceListsResponse,\n GetUserChannelResponse,\n // Promotions\n GetDropshipperPromotionsOptions,\n GetDropshipperPromotionsResponse,\n CreateDropshipperPromotionBody,\n UpdateDropshipperPromotionBody,\n DeleteDropshipperPromotionResponse,\n // Dashboard\n GetDashboardStatsOptions,\n GetDashboardStatsResponse,\n // Storefront (V)\n GetStorefrontDropshipperCategoriesResponse,\n // Inline return types\n DropshipperCategory,\n DropshipperPromotion,\n} from '@thorprovider/types';\nimport { createLogger, ProviderAPIError } from '@thorprovider/adapters';\nimport { fetchBackendWithResilience } from './request-resilience';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\n/**\n * Configuration required to instantiate the dropshipper client.\n */\nexport interface DropshipperClientConfig {\n /** Medusa backend base URL */\n baseUrl: string;\n /**\n * JWT token obtained from `POST /auth/user/emailpass`.\n * Used as `Authorization: Bearer <token>`.\n */\n token: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// DropshipperClient\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP client for Thor Commerce dropshipping endpoints (`/admin/thor/dropshipper/`).\n *\n * All methods throw `ProviderAPIError` on non-2xx responses.\n *\n * @example\n * ```typescript\n * const client = new DropshipperClient({\n * baseUrl: process.env.MEDUSA_BACKEND_URL!,\n * token: jwtFromLogin,\n * });\n *\n * // Y: list own products\n * const { products } = await client.getProducts();\n *\n * // X: onboard a new dropshipper\n * const { dropshipper } = await client.onboardDropshipper({ ... });\n * ```\n */\nexport class DropshipperClient {\n private baseUrl: string;\n private token: string;\n private logger: ReturnType<typeof createLogger>;\n\n constructor(config: DropshipperClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.token = config.token;\n this.logger = createLogger('DropshipperClient', config.debug);\n }\n\n // -------------------------------------------------------------------------\n // Private — HTTP helper\n // -------------------------------------------------------------------------\n\n private async request<T>(\n method: FetchMethod,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n this.logger.debug(`[dropshipper] ${method} ${path}`);\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n };\n\n const init: RequestInit = {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n };\n\n let response: Response;\n try {\n response = await fetchBackendWithResilience(url, init);\n } catch (networkError: any) {\n throw new ProviderAPIError(\n `[dropshipper] Network error on ${method} ${path}: ${networkError.message}`,\n 'NETWORK_ERROR',\n networkError,\n );\n }\n\n if (!response.ok) {\n let message = `HTTP ${response.status}`;\n try {\n const json = await response.json();\n message = json?.message ?? message;\n } catch {\n // ignore parse errors\n }\n throw new ProviderAPIError(\n `[dropshipper] ${method} ${path} failed: ${message}`,\n `DROPSHIPPER_API_${response.status}`,\n response.status,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n // -------------------------------------------------------------------------\n // Onboarding (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a new dropshipper account (sales channel + user + price list).\n *\n * `POST /admin/thor/dropshipper/onboard`\n */\n async onboardDropshipper(\n body: OnboardDropshipperBody,\n ): Promise<OnboardDropshipperResponse> {\n return this.request<OnboardDropshipperResponse>(\n 'POST',\n '/admin/thor/dropshipper/onboard',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Variant Costs (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List variant cost records, optionally filtered by account/variant/currency.\n *\n * `GET /admin/thor/dropshipper/variant-costs`\n */\n async getVariantCosts(\n options: GetVariantCostsOptions = {},\n ): Promise<GetVariantCostsResponse> {\n const { account_id, variant_id, currency_code, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(account_id ? { account_id } : {}),\n ...(variant_id ? { variant_id } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n return this.request<GetVariantCostsResponse>(\n 'GET',\n `/admin/thor/dropshipper/variant-costs?${qs}`,\n );\n }\n\n /**\n * Upsert a single variant cost record.\n *\n * `POST /admin/thor/dropshipper/variant-costs`\n */\n async createVariantCost(\n body: CreateVariantCostBody,\n ): Promise<CreateVariantCostResponse> {\n return this.request<CreateVariantCostResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs',\n body,\n );\n }\n\n /**\n * Batch-upsert variant costs for a given account and currency.\n *\n * `POST /admin/thor/dropshipper/variant-costs/batch`\n */\n async batchVariantCosts(\n body: BatchVariantCostsBody,\n ): Promise<BatchVariantCostsResponse> {\n return this.request<BatchVariantCostsResponse>(\n 'POST',\n '/admin/thor/dropshipper/variant-costs/batch',\n body,\n );\n }\n\n /**\n * Delete a variant cost record by ID.\n *\n * `DELETE /admin/thor/dropshipper/variant-costs/:id`\n */\n async deleteVariantCost(id: string): Promise<DeleteVariantCostResponse> {\n return this.request<DeleteVariantCostResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/variant-costs/${id}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Products (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List products available in Y's channel with cost/margin data.\n *\n * `GET /admin/thor/dropshipper/products`\n */\n async getProducts(\n options: GetDropshipperProductsOptions = {},\n ): Promise<GetDropshipperProductsResponse> {\n const { q, category_id, status, in_stock, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(category_id ? { category_id } : {}),\n ...(status ? { status } : {}),\n ...(in_stock !== undefined ? { in_stock: String(in_stock) } : {}),\n });\n return this.request<GetDropshipperProductsResponse>(\n 'GET',\n `/admin/thor/dropshipper/products?${qs}`,\n );\n }\n\n /**\n * Toggle whether a product is visible in the public store for the current sales channel.\n * This does not mutate the shared global Medusa product status.\n *\n * `POST /admin/thor/dropshipper/products/:id/status`\n */\n async updateProductStatus(\n productId: string,\n body: UpdateDropshipperProductStatusBody,\n ): Promise<UpdateDropshipperProductStatusResponse> {\n return this.request<UpdateDropshipperProductStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/products/${productId}/status`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Prices (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Bulk-update product and variant margins on Y's channel price list.\n *\n * `PUT /admin/thor/dropshipper/prices`\n */\n async updatePrices(\n body: UpdateDropshipperPricesBody,\n ): Promise<UpdateDropshipperPricesResponse> {\n return this.request<UpdateDropshipperPricesResponse>(\n 'PUT',\n '/admin/thor/dropshipper/prices',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Orders (Y + X for set-payment-collector)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of orders in Y's channel.\n *\n * `GET /admin/thor/dropshipper/orders`\n */\n async getOrders(\n options: GetDropshipperOrdersOptions = {},\n ): Promise<GetDropshipperOrdersResponse> {\n const { status, payment_collector, settlement_status, from, to, q, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(payment_collector ? { payment_collector } : {}),\n ...(settlement_status ? { settlement_status } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(q ? { q } : {}),\n });\n return this.request<GetDropshipperOrdersResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders?${qs}`,\n );\n }\n\n /**\n * Full detail for a single order with profit breakdown.\n *\n * `GET /admin/thor/dropshipper/orders/:id`\n */\n async getOrder(orderId: string): Promise<GetDropshipperOrderDetailResponse> {\n return this.request<GetDropshipperOrderDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}`,\n );\n }\n\n /**\n * List shipping options for a manual dropshipper order.\n *\n * `GET /admin/thor/dropshipper/orders/shipping-options`\n */\n async getOrderShippingOptions(\n params: GetDropshipperShippingOptionsParams,\n ): Promise<GetDropshipperShippingOptionsResponse> {\n const qs = new URLSearchParams({\n currency_code: params.currency_code.toLowerCase(),\n ...(params.country_code ? { country_code: params.country_code.toLowerCase() } : {}),\n });\n\n return this.request<GetDropshipperShippingOptionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/shipping-options?${qs}`,\n );\n }\n\n /**\n * Manually create an order on behalf of a customer.\n *\n * `POST /admin/thor/dropshipper/orders`\n */\n async createOrder(\n body: ExtendedCreateDropshipperOrderBody,\n ): Promise<ExtendedCreateDropshipperOrderResponse> {\n return this.request<ExtendedCreateDropshipperOrderResponse>(\n 'POST',\n '/admin/thor/dropshipper/orders',\n body,\n );\n }\n\n /**\n * Set who collects payment for an order (Solo X).\n *\n * `POST /admin/thor/dropshipper/orders/:id/set-payment-collector`\n */\n async setPaymentCollector(\n orderId: string,\n body: SetPaymentCollectorBody,\n ): Promise<SetPaymentCollectorResponse> {\n return this.request<SetPaymentCollectorResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/set-payment-collector`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Order Cancel & Edits (Solo Y) — B-04\n // -------------------------------------------------------------------------\n\n /**\n * Cancel a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/cancel`\n */\n async cancelOrder(orderId: string): Promise<CancelDropshipperOrderResponse> {\n return this.request<CancelDropshipperOrderResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/cancel`,\n );\n }\n\n /**\n * Create an order edit for a dropshipper order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit`\n */\n async createOrderEdit(\n orderId: string,\n body: CreateOrderEditBody = {},\n ): Promise<CreateOrderEditResponse> {\n return this.request<CreateOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit`,\n body,\n );\n }\n\n /**\n * Add an item to the active order edit.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/items`\n */\n async addOrderEditItem(\n orderId: string,\n body: AddOrderEditItemBody,\n ): Promise<AddOrderEditItemResponse> {\n return this.request<AddOrderEditItemResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/items`,\n body,\n );\n }\n\n /**\n * Confirm the active order edit, applying changes to the order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/edit/confirm`\n */\n async confirmOrderEdit(\n orderId: string,\n ): Promise<ConfirmOrderEditResponse> {\n return this.request<ConfirmOrderEditResponse>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/edit/confirm`,\n );\n }\n\n /**\n * Get all notes for an order.\n *\n * `GET /admin/thor/dropshipper/orders/:id/notes`\n */\n async getOrderNotes(orderId: string): Promise<GetOrderNotesResponse> {\n return this.request<GetOrderNotesResponse>(\n 'GET',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n );\n }\n\n /**\n * Create a new note for an order.\n *\n * `POST /admin/thor/dropshipper/orders/:id/notes`\n */\n async createOrderNote(\n orderId: string,\n body: CreateOrderNoteBody,\n ): Promise<OrderNote> {\n return this.request<OrderNote>(\n 'POST',\n `/admin/thor/dropshipper/orders/${orderId}/notes`,\n body,\n );\n }\n\n /**\n * Delete a note from an order.\n *\n * `DELETE /admin/thor/dropshipper/orders/:id/notes/:noteId`\n */\n async deleteOrderNote(\n orderId: string,\n noteId: string,\n ): Promise<DeleteOrderNoteResponse> {\n return this.request<DeleteOrderNoteResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/orders/${orderId}/notes/${noteId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Custom Categories (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Medusa provider categories linked to Y's channel (read-only).\n *\n * `GET /admin/thor/dropshipper/categories/provider`\n */\n async getProviderCategories(): Promise<GetProviderCategoriesResponse> {\n return this.request<GetProviderCategoriesResponse>(\n 'GET',\n '/admin/thor/dropshipper/categories/provider',\n );\n }\n\n /**\n * List Y's custom product categories.\n *\n * `GET /admin/thor/dropshipper/categories`\n */\n async getCategories(\n options: GetDropshipperCategoriesOptions = {},\n ): Promise<GetDropshipperCategoriesResponse> {\n const { parent_id, include_children } = options;\n const qs = new URLSearchParams({\n ...(parent_id ? { parent_id } : {}),\n ...(include_children !== undefined ? { include_children: String(include_children) } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDropshipperCategoriesResponse>(\n 'GET',\n `/admin/thor/dropshipper/categories${query}`,\n );\n }\n\n /**\n * Create a custom category in Y's channel.\n *\n * `POST /admin/thor/dropshipper/categories`\n */\n async createCategory(\n body: CreateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'POST',\n '/admin/thor/dropshipper/categories',\n body,\n );\n }\n\n /**\n * Update a custom category.\n *\n * `PUT /admin/thor/dropshipper/categories/:id`\n */\n async updateCategory(\n categoryId: string,\n body: UpdateDropshipperCategoryBody,\n ): Promise<DropshipperCategory> {\n return this.request<DropshipperCategory>(\n 'PUT',\n `/admin/thor/dropshipper/categories/${categoryId}`,\n body,\n );\n }\n\n /**\n * Delete a custom category.\n *\n * Pass `{ force: true }` to cascade-delete child categories.\n *\n * `DELETE /admin/thor/dropshipper/categories/:id`\n */\n async deleteCategory(\n categoryId: string,\n options: { force?: boolean } = {},\n ): Promise<DeleteDropshipperCategoryResponse> {\n const qs = options.force ? '?force=true' : '';\n return this.request<DeleteDropshipperCategoryResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/categories/${categoryId}${qs}`,\n );\n }\n\n /**\n * List product-to-category mappings, optionally filtered by product.\n *\n * `GET /admin/thor/dropshipper/category-mappings`\n */\n async getCategoryMappings(\n options: GetCategoryMappingsOptions = {},\n ): Promise<GetCategoryMappingsResponse> {\n const qs = options.product_id ? `?product_id=${options.product_id}` : '';\n return this.request<GetCategoryMappingsResponse>(\n 'GET',\n `/admin/thor/dropshipper/category-mappings${qs}`,\n );\n }\n\n /**\n * Map a product to a custom category.\n *\n * `POST /admin/thor/dropshipper/category-mappings`\n */\n async createCategoryMapping(\n body: CreateCategoryMappingBody,\n ): Promise<CreateCategoryMappingResponse> {\n return this.request<CreateCategoryMappingResponse>(\n 'POST',\n '/admin/thor/dropshipper/category-mappings',\n body,\n );\n }\n\n /**\n * Remove a product-to-category mapping.\n *\n * `DELETE /admin/thor/dropshipper/category-mappings/:id`\n */\n async deleteCategoryMapping(\n mappingId: string,\n ): Promise<DeleteCategoryMappingResponse> {\n return this.request<DeleteCategoryMappingResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/category-mappings/${mappingId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customers (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Paginated list of customers in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers`\n */\n async getCustomers(\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n const { q, has_orders, from, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(q ? { q } : {}),\n ...(has_orders !== undefined ? { has_orders: String(has_orders) } : {}),\n ...(from ? { from } : {}),\n });\n return this.request<GetDropshipperCustomersResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers?${qs}`,\n );\n }\n\n /**\n * Backwards-compatible alias used by the dashboard checkout flow.\n */\n async getChannelCustomers(\n _channelId: string,\n options: GetDropshipperCustomersOptions = {},\n ): Promise<GetDropshipperCustomersResponse> {\n return this.getCustomers(options);\n }\n\n /**\n * Full detail for a single customer.\n *\n * `GET /admin/thor/dropshipper/customers/:id`\n */\n async getCustomer(\n customerId: string,\n ): Promise<GetDropshipperCustomerDetailResponse> {\n return this.request<GetDropshipperCustomerDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}`,\n );\n }\n\n /**\n * Create a customer scoped to Y's channel.\n *\n * `POST /admin/thor/dropshipper/customers`\n */\n async createCustomer(\n body: CreateDropshipperCustomerBody,\n ): Promise<CreateDropshipperCustomerResponse> {\n return this.request<CreateDropshipperCustomerResponse>(\n 'POST',\n '/admin/thor/dropshipper/customers',\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Customer Addresses (Solo Y) — B-06\n // -------------------------------------------------------------------------\n\n /**\n * List addresses for a customer in Y's channel.\n *\n * `GET /admin/thor/dropshipper/customers/:id/addresses`\n */\n async getCustomerAddresses(\n customerId: string,\n ): Promise<GetDropshipperAddressesResponse> {\n return this.request<GetDropshipperAddressesResponse>(\n 'GET',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n );\n }\n\n /**\n * Create a new address for a customer.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses`\n */\n async createCustomerAddress(\n customerId: string,\n body: DropshipperAddressBody,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses`,\n body,\n );\n }\n\n /**\n * Update an existing customer address.\n *\n * `POST /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async updateCustomerAddress(\n customerId: string,\n addressId: string,\n body: Partial<DropshipperAddressBody>,\n ): Promise<DropshipperAddressResponse> {\n return this.request<DropshipperAddressResponse>(\n 'POST',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n body,\n );\n }\n\n /**\n * Delete a customer address.\n *\n * `DELETE /admin/thor/dropshipper/customers/:id/addresses/:addressId`\n */\n async deleteCustomerAddress(\n customerId: string,\n addressId: string,\n ): Promise<{ deleted: true; id: string }> {\n return this.request<{ deleted: true; id: string }>(\n 'DELETE',\n `/admin/thor/dropshipper/customers/${customerId}/addresses/${addressId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Account & Settlements (Y read-only)\n // -------------------------------------------------------------------------\n\n /**\n * Y's account info with current balance.\n *\n * `GET /admin/thor/dropshipper/account`\n */\n async getAccount(): Promise<GetDropshipperAccountResponse> {\n return this.request<GetDropshipperAccountResponse>(\n 'GET',\n '/admin/thor/dropshipper/account',\n );\n }\n\n /**\n * Orders where Y owes money to X (Y collected payment, needs to pay costs).\n *\n * `GET /admin/thor/dropshipper/account/payable`\n */\n async getPayable(): Promise<GetDropshipperPayableResponse> {\n return this.request<GetDropshipperPayableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/payable',\n );\n }\n\n /**\n * Orders where X owes money to Y (X collected COD, needs to transfer profit).\n *\n * `GET /admin/thor/dropshipper/account/receivable`\n */\n async getReceivable(): Promise<GetDropshipperReceivableResponse> {\n return this.request<GetDropshipperReceivableResponse>(\n 'GET',\n '/admin/thor/dropshipper/account/receivable',\n );\n }\n\n /**\n * List settlements (Y sees own; X can filter by account_id).\n *\n * `GET /admin/thor/dropshipper/settlements`\n */\n async getSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements?${qs}`,\n );\n }\n\n /**\n * Full detail for a single settlement record.\n *\n * `GET /admin/thor/dropshipper/settlements/:id`\n */\n async getSettlement(\n settlementId: string,\n ): Promise<GetSettlementDetailResponse> {\n return this.request<GetSettlementDetailResponse>(\n 'GET',\n `/admin/thor/dropshipper/settlements/${settlementId}`,\n\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * Create a settlement record for a dropshipper account.\n *\n * `POST /admin/thor/dropshipper/admin/settlements`\n */\n async createSettlement(\n body: CreateSettlementBody,\n ): Promise<CreateSettlementResponse> {\n return this.request<CreateSettlementResponse>(\n 'POST',\n '/admin/thor/dropshipper/admin/settlements',\n body,\n );\n }\n\n /**\n * Confirm a pending settlement (marks it as paid/received).\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/confirm`\n */\n async confirmSettlement(\n settlementId: string,\n body: ConfirmSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/confirm`,\n body,\n );\n }\n\n /**\n * Cancel a pending settlement.\n *\n * `POST /admin/thor/dropshipper/admin/settlements/:id/cancel`\n */\n async cancelSettlement(\n settlementId: string,\n body: CancelSettlementBody = {},\n ): Promise<UpdateSettlementStatusResponse> {\n return this.request<UpdateSettlementStatusResponse>(\n 'POST',\n `/admin/thor/dropshipper/admin/settlements/${settlementId}/cancel`,\n body,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Settlements — list (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * X views all settlement records across all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/settlements`\n */\n async getAdminSettlements(\n options: GetSettlementsOptions = {},\n ): Promise<GetSettlementsResponse> {\n const { status, type, account_id, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(status ? { status } : {}),\n ...(type ? { type } : {}),\n ...(account_id ? { account_id } : {}),\n });\n return this.request<GetSettlementsResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/settlements?${qs}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Admin Account Management (Solo X)\n // -------------------------------------------------------------------------\n\n /**\n * List all dropshipper accounts.\n *\n * `GET /admin/thor/dropshipper/admin/accounts`\n */\n async getAdminAccounts(): Promise<GetAdminDropshipperAccountsResponse> {\n return this.request<GetAdminDropshipperAccountsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/accounts',\n );\n }\n\n /**\n * Full balance detail for a specific dropshipper account.\n *\n * `GET /admin/thor/dropshipper/admin/accounts/:id/balance`\n */\n async getAdminAccountBalance(\n accountId: string,\n ): Promise<GetAdminAccountBalanceResponse> {\n return this.request<GetAdminAccountBalanceResponse>(\n 'GET',\n `/admin/thor/dropshipper/admin/accounts/${accountId}/balance`,\n );\n }\n\n /**\n * List all dropshipper price lists.\n *\n * `GET /admin/thor/dropshipper/admin/price-lists`\n */\n async getAdminPriceLists(): Promise<GetAdminPriceListsResponse> {\n return this.request<GetAdminPriceListsResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/price-lists',\n );\n }\n\n /**\n * Utility: look up which sales channel a user belongs to.\n *\n * `GET /admin/thor/dropshipper/admin/user-channel`\n */\n async getUserChannel(): Promise<GetUserChannelResponse> {\n return this.request<GetUserChannelResponse>(\n 'GET',\n '/admin/thor/dropshipper/admin/user-channel',\n );\n }\n\n // -------------------------------------------------------------------------\n // Promotions (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * List Y's promotions (discount codes).\n *\n * `GET /admin/thor/dropshipper/promotions`\n */\n async getPromotions(\n options: GetDropshipperPromotionsOptions = {},\n ): Promise<GetDropshipperPromotionsResponse> {\n const { type, limit = 20, offset = 0 } = options;\n const qs = new URLSearchParams({\n limit: String(limit),\n offset: String(offset),\n ...(type ? { type } : {}),\n });\n return this.request<GetDropshipperPromotionsResponse>(\n 'GET',\n `/admin/thor/dropshipper/promotions?${qs}`,\n );\n }\n\n /**\n * Create a promotion for Y's channel.\n *\n * `POST /admin/thor/dropshipper/promotions`\n */\n async createPromotion(\n body: CreateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'POST',\n '/admin/thor/dropshipper/promotions',\n body,\n );\n }\n\n /**\n * Get a single promotion by ID.\n *\n * `GET /admin/thor/dropshipper/promotions/:id`\n */\n async getPromotion(promotionId: string): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'GET',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n /**\n * Update an existing promotion.\n *\n * `PUT /admin/thor/dropshipper/promotions/:id`\n */\n async updatePromotion(\n promotionId: string,\n body: UpdateDropshipperPromotionBody,\n ): Promise<DropshipperPromotion> {\n return this.request<DropshipperPromotion>(\n 'PUT',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n body,\n );\n }\n\n /**\n * Delete a promotion.\n *\n * `DELETE /admin/thor/dropshipper/promotions/:id`\n */\n async deletePromotion(\n promotionId: string,\n ): Promise<DeleteDropshipperPromotionResponse> {\n return this.request<DeleteDropshipperPromotionResponse>(\n 'DELETE',\n `/admin/thor/dropshipper/promotions/${promotionId}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Dashboard (Solo Y)\n // -------------------------------------------------------------------------\n\n /**\n * Aggregate stats for Y's dashboard (revenue, profit, top products).\n *\n * `GET /admin/thor/dropshipper/dashboard/stats`\n */\n async getDashboardStats(\n options: GetDashboardStatsOptions = {},\n ): Promise<GetDashboardStatsResponse> {\n const { period, from, to, currency_code } = options;\n const qs = new URLSearchParams({\n ...(period ? { period } : {}),\n ...(from ? { from } : {}),\n ...(to ? { to } : {}),\n ...(currency_code ? { currency_code } : {}),\n });\n const query = qs.toString() ? `?${qs}` : '';\n return this.request<GetDashboardStatsResponse>(\n 'GET',\n `/admin/thor/dropshipper/dashboard/stats${query}`,\n );\n }\n\n // -------------------------------------------------------------------------\n // Storefront (V — end customer, uses publishable API key)\n // -------------------------------------------------------------------------\n\n /**\n * Public endpoint: dropshipper-scoped categories for the storefront.\n * Typically called with a publishable API key rather than a JWT.\n *\n * `GET /store/thor/dropshipper-categories`\n */\n async getStorefrontCategories(): Promise<GetStorefrontDropshipperCategoriesResponse> {\n return this.request<GetStorefrontDropshipperCategoriesResponse>(\n 'GET',\n '/store/thor/dropshipper-categories',\n );\n }\n}\n\n// Re-export types used by callers so they don't need to import from @thorprovider/types directly.\nexport type { DropshipperCategory, DropshipperPromotion } from '@thorprovider/types';\n"],"mappings":"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","names":["ProviderAPIError","ProviderAPIError","createLogger","ProviderAPIError","createLogger","ProviderAPIError"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thorprovider/medusa-extended",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Thor Commerce multi-tenant admin extensions for Medusa v2",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@thorprovider/adapters": "^4.2.2",
28
- "@thorprovider/types": "^3.5.0"
28
+ "@thorprovider/types": "^3.6.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "msw": "^2.12.3",
@@ -201,6 +201,52 @@ describe('DropshipperClient.getProducts', () => {
201
201
  })
202
202
  })
203
203
 
204
+ describe('DropshipperClient.updateProductStatus', () => {
205
+ it('POST /admin/thor/dropshipper/products/:id/status', async () => {
206
+ server.use(
207
+ http.post(`${BASE}/admin/thor/dropshipper/products/prod_1/status`, async ({ request }) => {
208
+ requireBearerToken(request)
209
+ const body = await request.json() as any
210
+ expect(body.status).toBe('draft')
211
+
212
+ return HttpResponse.json({
213
+ product_id: 'prod_1',
214
+ status: 'draft',
215
+ previous_status: 'published',
216
+ })
217
+ }),
218
+ )
219
+
220
+ const result = await client().updateProductStatus('prod_1', { status: 'draft' })
221
+ expect(result.product_id).toBe('prod_1')
222
+ expect(result.status).toBe('draft')
223
+ expect(result.previous_status).toBe('published')
224
+ })
225
+
226
+ it('throws when the channel publication is blocked by missing price', async () => {
227
+ server.use(
228
+ http.post(`${BASE}/admin/thor/dropshipper/products/prod_1/status`, async ({ request }) => {
229
+ requireBearerToken(request)
230
+ const body = await request.json() as any
231
+ expect(body.status).toBe('published')
232
+
233
+ return HttpResponse.json(
234
+ {
235
+ message: 'Product needs a configured sale price before it can be published',
236
+ reason: 'missing_price',
237
+ },
238
+ { status: 422 },
239
+ )
240
+ }),
241
+ )
242
+
243
+ await expect(client().updateProductStatus('prod_1', { status: 'published' })).rejects.toMatchObject({
244
+ name: 'ProviderAPIError',
245
+ provider: 'DROPSHIPPER_API_422',
246
+ })
247
+ })
248
+ })
249
+
204
250
  // ---------------------------------------------------------------------------
205
251
  // Prices (Solo Y)
206
252
  // ---------------------------------------------------------------------------
@@ -320,6 +366,7 @@ describe('DropshipperClient.createOrder', () => {
320
366
  currency_code: 'usd',
321
367
  items: [{ variant_id: 'var_1', quantity: 1 }],
322
368
  shipping_address: { full_name: 'John', address_1: '123 Main', city: 'NY', province: null, postal_code: '10001', country_code: 'us' },
369
+ payment_method_id: 'pm_1',
323
370
  billing_address: { full_name: 'Jane Doe', address_1: '456 Main', city: 'NY', province: null, postal_code: '10001', country_code: 'us' },
324
371
  promo_codes: ['SAVE10'],
325
372
  })
@@ -27,10 +27,12 @@ import type {
27
27
  BatchVariantCostsResponse,
28
28
  DeleteVariantCostResponse,
29
29
  // Products & Prices
30
- GetDropshipperProductsOptions,
31
- GetDropshipperProductsResponse,
32
- UpdateDropshipperPricesBody,
33
- UpdateDropshipperPricesResponse,
30
+ GetDropshipperProductsOptions,
31
+ GetDropshipperProductsResponse,
32
+ UpdateDropshipperProductStatusBody,
33
+ UpdateDropshipperProductStatusResponse,
34
+ UpdateDropshipperPricesBody,
35
+ UpdateDropshipperPricesResponse,
34
36
  // Orders
35
37
  GetDropshipperOrdersOptions,
36
38
  GetDropshipperOrdersResponse,
@@ -332,12 +334,29 @@ export class DropshipperClient {
332
334
  );
333
335
  }
334
336
 
337
+ /**
338
+ * Toggle whether a product is visible in the public store for the current sales channel.
339
+ * This does not mutate the shared global Medusa product status.
340
+ *
341
+ * `POST /admin/thor/dropshipper/products/:id/status`
342
+ */
343
+ async updateProductStatus(
344
+ productId: string,
345
+ body: UpdateDropshipperProductStatusBody,
346
+ ): Promise<UpdateDropshipperProductStatusResponse> {
347
+ return this.request<UpdateDropshipperProductStatusResponse>(
348
+ 'POST',
349
+ `/admin/thor/dropshipper/products/${productId}/status`,
350
+ body,
351
+ );
352
+ }
353
+
335
354
  // -------------------------------------------------------------------------
336
355
  // Prices (Solo Y)
337
356
  // -------------------------------------------------------------------------
338
357
 
339
358
  /**
340
- * Bulk-update sale prices on Y's channel price list.
359
+ * Bulk-update product and variant margins on Y's channel price list.
341
360
  *
342
361
  * `PUT /admin/thor/dropshipper/prices`
343
362
  */