@thorprovider/medusa-extended 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,6 +55,16 @@ import type {
55
55
  CreateOrderNoteBody,
56
56
  GetOrderNotesResponse,
57
57
  DeleteOrderNoteResponse,
58
+ // Draft Orders
59
+ GetDropshipperDraftOrdersOptions,
60
+ GetDropshipperDraftOrdersResponse,
61
+ GetDropshipperDraftOrderDetailResponse,
62
+ CreateDropshipperDraftOrderBody,
63
+ CreateDropshipperDraftOrderResponse,
64
+ UpdateDropshipperDraftOrderBody,
65
+ UpdateDropshipperDraftOrderResponse,
66
+ ConvertDropshipperDraftOrderBody,
67
+ ConvertDropshipperDraftOrderResponse,
58
68
  // Dropshipper Addresses
59
69
  DropshipperAddressBody,
60
70
  DropshipperAddressResponse,
@@ -77,6 +87,8 @@ import type {
77
87
  GetDropshipperCustomerDetailResponse,
78
88
  CreateDropshipperCustomerBody,
79
89
  CreateDropshipperCustomerResponse,
90
+ UpdateDropshipperCustomerBody,
91
+ UpdateDropshipperCustomerResponse,
80
92
  // Account & Settlements (Y)
81
93
  GetDropshipperAccountResponse,
82
94
  GetDropshipperPayableResponse,
@@ -809,6 +821,22 @@ export class DropshipperClient {
809
821
  );
810
822
  }
811
823
 
824
+ /**
825
+ * Update a customer scoped to Y's channel.
826
+ *
827
+ * `POST /admin/thor/dropshipper/customers/:id`
828
+ */
829
+ async updateCustomer(
830
+ customerId: string,
831
+ body: UpdateDropshipperCustomerBody,
832
+ ): Promise<UpdateDropshipperCustomerResponse> {
833
+ return this.request<UpdateDropshipperCustomerResponse>(
834
+ 'POST',
835
+ `/admin/thor/dropshipper/customers/${customerId}`,
836
+ body,
837
+ );
838
+ }
839
+
812
840
  // -------------------------------------------------------------------------
813
841
  // Customer Addresses (Solo Y) — B-06
814
842
  // -------------------------------------------------------------------------
@@ -1456,6 +1484,94 @@ export class DropshipperClient {
1456
1484
  );
1457
1485
  }
1458
1486
 
1487
+ // -------------------------------------------------------------------------
1488
+ // Draft Orders
1489
+ // -------------------------------------------------------------------------
1490
+
1491
+ /**
1492
+ * List all draft orders in the dropshipper's channel.
1493
+ *
1494
+ * `GET /admin/thor/dropshipper/draft-orders`
1495
+ */
1496
+ async getDraftOrders(
1497
+ options: GetDropshipperDraftOrdersOptions = {},
1498
+ ): Promise<GetDropshipperDraftOrdersResponse> {
1499
+ const { customer_id, from, to, q, limit = 20, offset = 0 } = options;
1500
+ const qs = new URLSearchParams({
1501
+ limit: String(limit),
1502
+ offset: String(offset),
1503
+ ...(customer_id ? { customer_id } : {}),
1504
+ ...(from ? { from } : {}),
1505
+ ...(to ? { to } : {}),
1506
+ ...(q ? { q } : {}),
1507
+ });
1508
+ return this.request<GetDropshipperDraftOrdersResponse>(
1509
+ 'GET',
1510
+ `/admin/thor/dropshipper/draft-orders?${qs}`,
1511
+ );
1512
+ }
1513
+
1514
+ /**
1515
+ * Get a specific draft order by ID.
1516
+ *
1517
+ * `GET /admin/thor/dropshipper/draft-orders/:id`
1518
+ */
1519
+ async getDraftOrder(
1520
+ draftOrderId: string,
1521
+ ): Promise<GetDropshipperDraftOrderDetailResponse> {
1522
+ return this.request<GetDropshipperDraftOrderDetailResponse>(
1523
+ 'GET',
1524
+ `/admin/thor/dropshipper/draft-orders/${draftOrderId}`,
1525
+ );
1526
+ }
1527
+
1528
+ /**
1529
+ * Create a new draft order.
1530
+ *
1531
+ * `POST /admin/thor/dropshipper/draft-orders`
1532
+ */
1533
+ async createDraftOrder(
1534
+ body: CreateDropshipperDraftOrderBody,
1535
+ ): Promise<CreateDropshipperDraftOrderResponse> {
1536
+ return this.request<CreateDropshipperDraftOrderResponse>(
1537
+ 'POST',
1538
+ '/admin/thor/dropshipper/draft-orders',
1539
+ body,
1540
+ );
1541
+ }
1542
+
1543
+ /**
1544
+ * Update a draft order.
1545
+ *
1546
+ * `POST /admin/thor/dropshipper/draft-orders/:id`
1547
+ */
1548
+ async updateDraftOrder(
1549
+ draftOrderId: string,
1550
+ body: UpdateDropshipperDraftOrderBody,
1551
+ ): Promise<UpdateDropshipperDraftOrderResponse> {
1552
+ return this.request<UpdateDropshipperDraftOrderResponse>(
1553
+ 'POST',
1554
+ `/admin/thor/dropshipper/draft-orders/${draftOrderId}`,
1555
+ body,
1556
+ );
1557
+ }
1558
+
1559
+ /**
1560
+ * Convert a draft order to a real order.
1561
+ *
1562
+ * `POST /admin/thor/dropshipper/draft-orders/:id/convert`
1563
+ */
1564
+ async convertDraftOrder(
1565
+ draftOrderId: string,
1566
+ body: ConvertDropshipperDraftOrderBody,
1567
+ ): Promise<ConvertDropshipperDraftOrderResponse> {
1568
+ return this.request<ConvertDropshipperDraftOrderResponse>(
1569
+ 'POST',
1570
+ `/admin/thor/dropshipper/draft-orders/${draftOrderId}/convert`,
1571
+ body,
1572
+ );
1573
+ }
1574
+
1459
1575
  // -------------------------------------------------------------------------
1460
1576
  // Geo-reference
1461
1577
  // -------------------------------------------------------------------------
@@ -38,6 +38,8 @@ function isRetryableError(error: unknown, config: Required<RetryConfig>): boolea
38
38
 
39
39
  async function fetchWithRetry(url: string, init: RequestInit, retryConfig?: RetryConfig): Promise<Response> {
40
40
  const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig }
41
+ const method = (init.method || 'GET').toUpperCase()
42
+ const isMutation = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)
41
43
  let lastError: unknown
42
44
 
43
45
  for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
@@ -57,6 +59,16 @@ async function fetchWithRetry(url: string, init: RequestInit, retryConfig?: Retr
57
59
  return response
58
60
  } catch (error) {
59
61
  lastError = error
62
+
63
+ // Never retry mutations (POST/PUT/PATCH/DELETE) on timeout/network error.
64
+ // The first request may have succeeded on the backend, and retrying would
65
+ // create duplicate resources (customers, orders, etc.).
66
+ const isTimeoutOrNetwork = error instanceof Error &&
67
+ (error.name === 'AbortError' || error.message?.includes('timeout') || error.message?.includes('fetch failed'))
68
+ if (isMutation && isTimeoutOrNetwork) {
69
+ break
70
+ }
71
+
60
72
  const shouldRetry = attempt < config.maxRetries && isRetryableError(error, config)
61
73
 
62
74
  if (shouldRetry) {