@yoryoboy/bi-mcp 1.10.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +4 -5
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +398 -8
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +2 -2
  6. package/dist/src/config/__tests__/meta.test.js +35 -0
  7. package/dist/src/config/__tests__/meta.test.js.map +7 -0
  8. package/dist/src/config/mercadolibre-profile-store.js +25 -0
  9. package/dist/src/config/mercadolibre-profile-store.js.map +2 -2
  10. package/dist/src/config/meta-store.js +109 -0
  11. package/dist/src/config/meta-store.js.map +7 -0
  12. package/dist/src/config/meta.js +0 -2
  13. package/dist/src/config/meta.js.map +2 -2
  14. package/dist/src/meta/__tests__/meta-utils.test.js +155 -0
  15. package/dist/src/meta/__tests__/meta-utils.test.js.map +7 -0
  16. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +265 -0
  17. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +7 -0
  18. package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js +311 -0
  19. package/dist/src/services/mercadolibre/__tests__/mercadolibre-items.test.js.map +7 -0
  20. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +220 -0
  21. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +7 -0
  22. package/dist/src/services/meta/__tests__/meta-ads.test.js +126 -0
  23. package/dist/src/services/meta/__tests__/meta-ads.test.js.map +7 -0
  24. package/dist/src/services/meta/__tests__/meta-api.test.js +70 -0
  25. package/dist/src/services/meta/__tests__/meta-api.test.js.map +7 -0
  26. package/dist/src/services/meta/meta-ads.js +94 -40
  27. package/dist/src/services/meta/meta-ads.js.map +2 -2
  28. package/dist/src/services/meta/meta-api.js +8 -6
  29. package/dist/src/services/meta/meta-api.js.map +2 -2
  30. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +165 -0
  31. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +7 -0
  32. package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js +92 -0
  33. package/dist/src/services/vtex/__tests__/vtex-catalog-write-eans.test.js.map +7 -0
  34. package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js +41 -0
  35. package/dist/src/services/vtex/__tests__/vtex-catalog-write-products.test.js.map +7 -0
  36. package/dist/src/services/vtex/__tests__/vtex-catalog.test.js +80 -0
  37. package/dist/src/services/vtex/__tests__/vtex-catalog.test.js.map +7 -0
  38. package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js +85 -0
  39. package/dist/src/services/vtex/__tests__/vtex-orders-write-http.test.js.map +7 -0
  40. package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js +251 -0
  41. package/dist/src/services/vtex/__tests__/vtex-orders-write-state-validation.test.js.map +7 -0
  42. package/dist/src/services/vtex/__tests__/vtex-write.test.js +111 -0
  43. package/dist/src/services/vtex/__tests__/vtex-write.test.js.map +7 -0
  44. package/dist/src/services/vtex/vtex-catalog-write.js +194 -1
  45. package/dist/src/services/vtex/vtex-catalog-write.js.map +2 -2
  46. package/dist/src/services/vtex/vtex-catalog.js +118 -1
  47. package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
  48. package/dist/src/services/vtex/vtex-pricing-write.js +5 -0
  49. package/dist/src/services/vtex/vtex-pricing-write.js.map +2 -2
  50. package/dist/src/services/vtex/vtex-write.js +67 -1
  51. package/dist/src/services/vtex/vtex-write.js.map +2 -2
  52. package/dist/src/tools/config/list-profiles.js +85 -11
  53. package/dist/src/tools/config/list-profiles.js.map +2 -2
  54. package/dist/src/tools/index.js.map +2 -2
  55. package/dist/src/tools/mercadolibre/__tests__/helpers.test.js +37 -0
  56. package/dist/src/tools/mercadolibre/__tests__/helpers.test.js.map +7 -0
  57. package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js +30 -0
  58. package/dist/src/tools/mercadolibre/__tests__/profile-resolution.test.js.map +7 -0
  59. package/dist/src/tools/mercadolibre/profile-resolution.js +4 -50
  60. package/dist/src/tools/mercadolibre/profile-resolution.js.map +2 -2
  61. package/dist/src/tools/meta/__tests__/pagination.test.js +133 -0
  62. package/dist/src/tools/meta/__tests__/pagination.test.js.map +7 -0
  63. package/dist/src/tools/meta/__tests__/profile-access.test.js +262 -0
  64. package/dist/src/tools/meta/__tests__/profile-access.test.js.map +7 -0
  65. package/dist/src/tools/meta/__tests__/read-tools.test.js +722 -0
  66. package/dist/src/tools/meta/__tests__/read-tools.test.js.map +7 -0
  67. package/dist/src/tools/meta/__tests__/schemas.test.js +103 -0
  68. package/dist/src/tools/meta/__tests__/schemas.test.js.map +7 -0
  69. package/dist/src/tools/meta/account-overview.js +37 -19
  70. package/dist/src/tools/meta/account-overview.js.map +2 -2
  71. package/dist/src/tools/meta/ad-account-info.js +31 -6
  72. package/dist/src/tools/meta/ad-account-info.js.map +2 -2
  73. package/dist/src/tools/meta/ads-performance.js +35 -21
  74. package/dist/src/tools/meta/ads-performance.js.map +2 -2
  75. package/dist/src/tools/meta/campaign-performance.js +35 -18
  76. package/dist/src/tools/meta/campaign-performance.js.map +2 -2
  77. package/dist/src/tools/meta/list-accessible-ad-accounts.js +39 -10
  78. package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +2 -2
  79. package/dist/src/tools/meta/list-accessible-businesses.js +37 -13
  80. package/dist/src/tools/meta/list-accessible-businesses.js.map +2 -2
  81. package/dist/src/tools/meta/placement-mix.js +37 -22
  82. package/dist/src/tools/meta/placement-mix.js.map +2 -2
  83. package/dist/src/tools/meta/profile-access.js +215 -0
  84. package/dist/src/tools/meta/profile-access.js.map +7 -0
  85. package/dist/src/tools/meta/schema-helpers.js +19 -0
  86. package/dist/src/tools/meta/schema-helpers.js.map +7 -0
  87. package/dist/src/tools/meta/time-series.js +40 -23
  88. package/dist/src/tools/meta/time-series.js.map +2 -2
  89. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +233 -0
  90. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +7 -0
  91. package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js +649 -0
  92. package/dist/src/tools/vtex/__tests__/catalog-admin-categories.test.js.map +7 -0
  93. package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js +339 -0
  94. package/dist/src/tools/vtex/__tests__/catalog-admin-product-specifications.test.js.map +7 -0
  95. package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js +235 -0
  96. package/dist/src/tools/vtex/__tests__/catalog-admin-products-skus.test.js.map +7 -0
  97. package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js +372 -0
  98. package/dist/src/tools/vtex/__tests__/catalog-navigation-reads.test.js.map +7 -0
  99. package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js +57 -0
  100. package/dist/src/tools/vtex/__tests__/catalog-navigation-surface.test.js.map +7 -0
  101. package/dist/src/tools/vtex/__tests__/write-helpers.test.js +97 -0
  102. package/dist/src/tools/vtex/__tests__/write-helpers.test.js.map +7 -0
  103. package/dist/src/tools/vtex/activate-sku.js +1 -48
  104. package/dist/src/tools/vtex/activate-sku.js.map +2 -2
  105. package/dist/src/tools/vtex/associate-specification.js +3 -54
  106. package/dist/src/tools/vtex/associate-specification.js.map +2 -2
  107. package/dist/src/tools/vtex/attach-catalog-image.js +3 -57
  108. package/dist/src/tools/vtex/attach-catalog-image.js.map +2 -2
  109. package/dist/src/tools/vtex/catalog-admin-batch.js +298 -0
  110. package/dist/src/tools/vtex/catalog-admin-batch.js.map +7 -0
  111. package/dist/src/tools/vtex/catalog-admin-categories.js +542 -0
  112. package/dist/src/tools/vtex/catalog-admin-categories.js.map +7 -0
  113. package/dist/src/tools/vtex/catalog-admin-product-specifications.js +275 -0
  114. package/dist/src/tools/vtex/catalog-admin-product-specifications.js.map +7 -0
  115. package/dist/src/tools/vtex/catalog-admin-products-skus.js +475 -0
  116. package/dist/src/tools/vtex/catalog-admin-products-skus.js.map +7 -0
  117. package/dist/src/tools/vtex/catalog-navigation-reads.js +430 -0
  118. package/dist/src/tools/vtex/catalog-navigation-reads.js.map +7 -0
  119. package/dist/src/tools/vtex/create-brand.js +1 -64
  120. package/dist/src/tools/vtex/create-brand.js.map +2 -2
  121. package/dist/src/tools/vtex/create-category.js +1 -76
  122. package/dist/src/tools/vtex/create-category.js.map +2 -2
  123. package/dist/src/tools/vtex/create-product-with-sku.js +3 -114
  124. package/dist/src/tools/vtex/create-product-with-sku.js.map +2 -2
  125. package/dist/src/tools/vtex/create-specification-value.js +3 -47
  126. package/dist/src/tools/vtex/create-specification-value.js.map +2 -2
  127. package/dist/src/tools/vtex/create-specification.js +1 -80
  128. package/dist/src/tools/vtex/create-specification.js.map +2 -2
  129. package/dist/src/tools/vtex/deactivate-sku.js +1 -48
  130. package/dist/src/tools/vtex/deactivate-sku.js.map +2 -2
  131. package/dist/src/tools/vtex/delete-all-product-specifications.js +9 -0
  132. package/dist/src/tools/vtex/delete-all-product-specifications.js.map +7 -0
  133. package/dist/src/tools/vtex/delete-all-sku-specifications.js +9 -0
  134. package/dist/src/tools/vtex/delete-all-sku-specifications.js.map +7 -0
  135. package/dist/src/tools/vtex/delete-brand.js +9 -0
  136. package/dist/src/tools/vtex/delete-brand.js.map +7 -0
  137. package/dist/src/tools/vtex/delete-catalog-image.js +9 -0
  138. package/dist/src/tools/vtex/delete-catalog-image.js.map +7 -0
  139. package/dist/src/tools/vtex/delete-product-specification.js +9 -0
  140. package/dist/src/tools/vtex/delete-product-specification.js.map +7 -0
  141. package/dist/src/tools/vtex/delete-sku-price.js +55 -0
  142. package/dist/src/tools/vtex/delete-sku-price.js.map +7 -0
  143. package/dist/src/tools/vtex/delete-sku-specification.js +9 -0
  144. package/dist/src/tools/vtex/delete-sku-specification.js.map +7 -0
  145. package/dist/src/tools/vtex/get-brand.js +6 -0
  146. package/dist/src/tools/vtex/get-brand.js.map +7 -0
  147. package/dist/src/tools/vtex/get-category-tree.js +6 -0
  148. package/dist/src/tools/vtex/get-category-tree.js.map +7 -0
  149. package/dist/src/tools/vtex/get-category.js +6 -0
  150. package/dist/src/tools/vtex/get-category.js.map +7 -0
  151. package/dist/src/tools/vtex/get-product-specifications.js +9 -0
  152. package/dist/src/tools/vtex/get-product-specifications.js.map +7 -0
  153. package/dist/src/tools/vtex/get-product.js +6 -0
  154. package/dist/src/tools/vtex/get-product.js.map +7 -0
  155. package/dist/src/tools/vtex/get-sku.js +6 -0
  156. package/dist/src/tools/vtex/get-sku.js.map +7 -0
  157. package/dist/src/tools/vtex/index.js +23 -1
  158. package/dist/src/tools/vtex/index.js.map +2 -2
  159. package/dist/src/tools/vtex/list-brands.js +6 -0
  160. package/dist/src/tools/vtex/list-brands.js.map +7 -0
  161. package/dist/src/tools/vtex/list-categories.js +6 -0
  162. package/dist/src/tools/vtex/list-categories.js.map +7 -0
  163. package/dist/src/tools/vtex/list-products-by-category.js +6 -0
  164. package/dist/src/tools/vtex/list-products-by-category.js.map +7 -0
  165. package/dist/src/tools/vtex/list-products.js +6 -0
  166. package/dist/src/tools/vtex/list-products.js.map +7 -0
  167. package/dist/src/tools/vtex/list-skus-by-product.js +6 -0
  168. package/dist/src/tools/vtex/list-skus-by-product.js.map +7 -0
  169. package/dist/src/tools/vtex/list-specification-groups.js +9 -0
  170. package/dist/src/tools/vtex/list-specification-groups.js.map +7 -0
  171. package/dist/src/tools/vtex/move-category.js +6 -0
  172. package/dist/src/tools/vtex/move-category.js.map +7 -0
  173. package/dist/src/tools/vtex/profile-resolution.js +4 -51
  174. package/dist/src/tools/vtex/profile-resolution.js.map +2 -2
  175. package/dist/src/tools/vtex/update-brand.js +6 -0
  176. package/dist/src/tools/vtex/update-brand.js.map +7 -0
  177. package/dist/src/tools/vtex/update-category.js +6 -0
  178. package/dist/src/tools/vtex/update-category.js.map +7 -0
  179. package/dist/src/tools/vtex/update-product-basic-fields.js +3 -65
  180. package/dist/src/tools/vtex/update-product-basic-fields.js.map +2 -2
  181. package/dist/src/tools/vtex/update-sku-basic-fields.js +1 -87
  182. package/dist/src/tools/vtex/update-sku-basic-fields.js.map +2 -2
  183. package/dist/src/tools/vtex/update-sku-price.js +21 -1
  184. package/dist/src/tools/vtex/update-sku-price.js.map +2 -2
  185. package/dist/src/tools/vtex/write-helpers.js +104 -14
  186. package/dist/src/tools/vtex/write-helpers.js.map +2 -2
  187. package/dist/src/utils/provider-profile-selection.js +117 -0
  188. package/dist/src/utils/provider-profile-selection.js.map +7 -0
  189. package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js +678 -0
  190. package/dist/tests/meli/mercadolibre-tool-handlers-medium-batch4.test.js.map +7 -0
  191. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js +564 -0
  192. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch5.test.js.map +7 -0
  193. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js +387 -0
  194. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch6.test.js.map +7 -0
  195. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js +368 -0
  196. package/dist/tests/meli/mercadolibre-tool-handlers-monster-batch7.test.js.map +7 -0
  197. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +626 -0
  198. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +7 -0
  199. package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js +480 -0
  200. package/dist/tests/meli/mercadolibre-tool-handlers-write-batch8.test.js.map +7 -0
  201. package/dist/tests/setup.js +2 -0
  202. package/dist/tests/setup.js.map +7 -0
  203. package/dist/tests/smoke/test-harness.test.js +7 -0
  204. package/dist/tests/smoke/test-harness.test.js.map +7 -0
  205. package/dist/tests/vtex/read-only-utils.test.js +161 -0
  206. package/dist/tests/vtex/read-only-utils.test.js.map +7 -0
  207. package/dist/tests/vtex/vtex-catalog-admin-docs.test.js +24 -0
  208. package/dist/tests/vtex/vtex-catalog-admin-docs.test.js.map +7 -0
  209. package/dist/tests/vtex/vtex-catalog-admin-surface.test.js +30 -0
  210. package/dist/tests/vtex/vtex-catalog-admin-surface.test.js.map +7 -0
  211. package/dist/tests/vtex/vtex-catalog-write-tools.test.js +712 -0
  212. package/dist/tests/vtex/vtex-catalog-write-tools.test.js.map +7 -0
  213. package/dist/tests/vtex/vtex-catalog.service.test.js +51 -0
  214. package/dist/tests/vtex/vtex-catalog.service.test.js.map +7 -0
  215. package/dist/tests/vtex/vtex-inventory-tools.test.js +201 -0
  216. package/dist/tests/vtex/vtex-inventory-tools.test.js.map +7 -0
  217. package/dist/tests/vtex/vtex-logistics.service.test.js +134 -0
  218. package/dist/tests/vtex/vtex-logistics.service.test.js.map +7 -0
  219. package/dist/tests/vtex/vtex-order-details.tool.test.js +141 -0
  220. package/dist/tests/vtex/vtex-order-details.tool.test.js.map +7 -0
  221. package/dist/tests/vtex/vtex-order-write-tools.test.js +483 -0
  222. package/dist/tests/vtex/vtex-order-write-tools.test.js.map +7 -0
  223. package/dist/tests/vtex/vtex-orders-summary.tool.test.js +185 -0
  224. package/dist/tests/vtex/vtex-orders-summary.tool.test.js.map +7 -0
  225. package/dist/tests/vtex/vtex-orders.service.test.js +120 -0
  226. package/dist/tests/vtex/vtex-orders.service.test.js.map +7 -0
  227. package/dist/tests/vtex/vtex-pricing-write-tools.test.js +202 -0
  228. package/dist/tests/vtex/vtex-pricing-write-tools.test.js.map +7 -0
  229. package/dist/tests/vtex/vtex-pricing-write.service.test.js +106 -0
  230. package/dist/tests/vtex/vtex-pricing-write.service.test.js.map +7 -0
  231. package/dist/tests/vtex/vtex-pricing.service.test.js +88 -0
  232. package/dist/tests/vtex/vtex-pricing.service.test.js.map +7 -0
  233. package/dist/tests/vtex/vtex-small-tools.test.js +190 -0
  234. package/dist/tests/vtex/vtex-small-tools.test.js.map +7 -0
  235. package/dist/tests/vtex/vtex-write-simple-tools.test.js +647 -0
  236. package/dist/tests/vtex/vtex-write-simple-tools.test.js.map +7 -0
  237. package/dist/vitest.config.js +15 -0
  238. package/dist/vitest.config.js.map +7 -0
  239. package/package.json +6 -2
@@ -0,0 +1,311 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ addMercadoLibreItemPicture,
4
+ createMercadoLibreItem,
5
+ createMercadoLibreItemDescription,
6
+ estimateMercadoLibreListingPrice,
7
+ getMercadoLibreCategoryAttributes,
8
+ getMercadoLibreCategoryShippingPreferences,
9
+ getMercadoLibreItem,
10
+ getMercadoLibreItemDescription,
11
+ getMercadoLibreItemDetailsBatch,
12
+ getMercadoLibreItemDetailsWithFallbackBatch,
13
+ getMercadoLibreItemPerformance,
14
+ getMercadoLibreItemVisitsWindow,
15
+ getMercadoLibreSiteCategoriesAndListingTypes,
16
+ getMercadoLibreUserItemsVisits,
17
+ replaceMercadoLibreItemDescription,
18
+ searchMercadoLibreDomainDiscovery,
19
+ searchMercadoLibreItems,
20
+ searchMercadoLibreItemsBatch,
21
+ updateMercadoLibreItem
22
+ } from "../mercadolibre-items.js";
23
+ import {
24
+ getMercadoLibreApiContext,
25
+ parseMercadoLibreMultiget,
26
+ runMercadoLibreBatch
27
+ } from "../mercadolibre-api.js";
28
+ vi.mock("../mercadolibre-api.js", async () => {
29
+ const actual = await vi.importActual(
30
+ "../mercadolibre-api.js"
31
+ );
32
+ return {
33
+ ...actual,
34
+ getMercadoLibreApiContext: vi.fn(),
35
+ parseMercadoLibreMultiget: vi.fn(),
36
+ runMercadoLibreBatch: vi.fn()
37
+ };
38
+ });
39
+ describe("mercadolibre-items service", () => {
40
+ const getMock = vi.fn();
41
+ const postMock = vi.fn();
42
+ const putMock = vi.fn();
43
+ beforeEach(() => {
44
+ vi.clearAllMocks();
45
+ vi.mocked(getMercadoLibreApiContext).mockResolvedValue({
46
+ api: { get: getMock, post: postMock, put: putMock },
47
+ sellerId: "seller-1",
48
+ accessToken: "token"
49
+ });
50
+ });
51
+ it("searches seller items with the expected MercadoLibre query params", async () => {
52
+ getMock.mockResolvedValueOnce({ data: { results: ["MLA1"] } });
53
+ const result = await searchMercadoLibreItems("profile-1", {
54
+ sellerId: "seller-99",
55
+ status: "active",
56
+ q: "shoes",
57
+ listingTypeId: "gold_special",
58
+ limit: 30,
59
+ offset: 60
60
+ });
61
+ expect(result).toEqual({ results: ["MLA1"] });
62
+ expect(getMock).toHaveBeenCalledWith("/users/seller-99/items/search", {
63
+ params: {
64
+ status: "active",
65
+ q: "shoes",
66
+ category: void 0,
67
+ listing_type_id: "gold_special",
68
+ orders: void 0,
69
+ limit: 30,
70
+ offset: 60
71
+ }
72
+ });
73
+ });
74
+ it("applies default pagination and optional filters for item searches", async () => {
75
+ getMock.mockResolvedValueOnce({ data: { results: [] } });
76
+ await searchMercadoLibreItems("profile-1", {
77
+ sellerId: "seller-1",
78
+ category: "MLA1055",
79
+ orders: "start_time_desc"
80
+ });
81
+ expect(getMock).toHaveBeenCalledWith("/users/seller-1/items/search", {
82
+ params: {
83
+ status: void 0,
84
+ q: void 0,
85
+ category: "MLA1055",
86
+ listing_type_id: void 0,
87
+ orders: "start_time_desc",
88
+ limit: 20,
89
+ offset: 0
90
+ }
91
+ });
92
+ });
93
+ it("delegates paginated item searches to the shared batch runner", async () => {
94
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
95
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
96
+ failed: []
97
+ }));
98
+ getMock.mockResolvedValueOnce({ data: { results: ["MLA1"], paging: { total: 1 } } });
99
+ const result = await searchMercadoLibreItemsBatch(
100
+ "profile-1",
101
+ {
102
+ sellerId: "seller-1",
103
+ q: "boots"
104
+ },
105
+ [40],
106
+ { maxConcurrency: 4 }
107
+ );
108
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["40"], expect.any(Function), {
109
+ maxConcurrency: 4
110
+ });
111
+ expect(getMock).toHaveBeenCalledWith("/users/seller-1/items/search", {
112
+ params: {
113
+ status: void 0,
114
+ q: "boots",
115
+ category: void 0,
116
+ listing_type_id: void 0,
117
+ orders: void 0,
118
+ limit: 20,
119
+ offset: 40
120
+ }
121
+ });
122
+ expect(result).toEqual({
123
+ successful: [{ id: "40", document: { results: ["MLA1"], paging: { total: 1 } } }],
124
+ failed: []
125
+ });
126
+ });
127
+ it("requests multiget item details with compact ids and attributes", async () => {
128
+ vi.mocked(parseMercadoLibreMultiget).mockResolvedValue([{ id: "MLA1" }]);
129
+ const response = { data: [{ code: 200, body: { id: "MLA1" } }] };
130
+ getMock.mockResolvedValueOnce(response);
131
+ const result = await getMercadoLibreItemDetailsBatch("profile-1", ["MLA1", "MLA2"], [
132
+ "id",
133
+ "title"
134
+ ]);
135
+ expect(getMock).toHaveBeenCalledWith("/items", {
136
+ params: {
137
+ ids: "MLA1,MLA2",
138
+ attributes: "id,title"
139
+ }
140
+ });
141
+ expect(parseMercadoLibreMultiget).toHaveBeenCalledWith(response);
142
+ expect(result).toEqual([{ id: "MLA1" }]);
143
+ });
144
+ it("keeps multiget request params stable when ids or attributes are empty", async () => {
145
+ vi.mocked(parseMercadoLibreMultiget).mockResolvedValue([]);
146
+ getMock.mockResolvedValueOnce({ data: [] });
147
+ await getMercadoLibreItemDetailsBatch("profile-1", [], []);
148
+ expect(getMock).toHaveBeenCalledWith("/items", {
149
+ params: {
150
+ ids: "",
151
+ attributes: ""
152
+ }
153
+ });
154
+ });
155
+ it("falls back to individual item fetches through the shared batch runner", async () => {
156
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
157
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
158
+ failed: []
159
+ }));
160
+ getMock.mockResolvedValueOnce({ data: { id: "MLA1", title: "Boots" } });
161
+ const result = await getMercadoLibreItemDetailsWithFallbackBatch("profile-1", ["MLA1"], {
162
+ maxRetries: 1
163
+ });
164
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["MLA1"], expect.any(Function), {
165
+ maxRetries: 1
166
+ });
167
+ expect(getMock).toHaveBeenCalledWith("/items/MLA1");
168
+ expect(result).toEqual({
169
+ successful: [{ id: "MLA1", document: { id: "MLA1", title: "Boots" } }],
170
+ failed: []
171
+ });
172
+ });
173
+ it.each([
174
+ {
175
+ label: "single item",
176
+ call: () => getMercadoLibreItem("profile-1", "MLA1"),
177
+ path: "/items/MLA1",
178
+ data: { id: "MLA1" }
179
+ },
180
+ {
181
+ label: "item description",
182
+ call: () => getMercadoLibreItemDescription("profile-1", "MLA1"),
183
+ path: "/items/MLA1/description",
184
+ data: { plain_text: "desc" }
185
+ },
186
+ {
187
+ label: "domain discovery with default site",
188
+ call: () => searchMercadoLibreDomainDiscovery("profile-1", "zapatillas", 5),
189
+ path: "/sites/MLA/domain_discovery/search",
190
+ config: { params: { q: "zapatillas", limit: 5 } },
191
+ data: [{ domain_id: "MLA-SNEAKERS" }]
192
+ },
193
+ {
194
+ label: "category attributes",
195
+ call: () => getMercadoLibreCategoryAttributes("profile-1", "MLA1055"),
196
+ path: "/categories/MLA1055/attributes",
197
+ data: [{ id: "COLOR" }]
198
+ },
199
+ {
200
+ label: "category shipping preferences",
201
+ call: () => getMercadoLibreCategoryShippingPreferences("profile-1", "MLA1055"),
202
+ path: "/categories/MLA1055/shipping_preferences",
203
+ data: { mode: "me2" }
204
+ },
205
+ {
206
+ label: "listing price estimate",
207
+ call: () => estimateMercadoLibreListingPrice("profile-1", { price: 1e4, listing_type_id: "gold_special" }),
208
+ path: "/sites/MLA/listing_prices",
209
+ config: { params: { price: 1e4, listing_type_id: "gold_special" } },
210
+ data: [{ sale_fee_amount: 1700 }]
211
+ },
212
+ {
213
+ label: "seller item visits",
214
+ call: () => getMercadoLibreUserItemsVisits("profile-1", "seller-1", "2026-01-01", "2026-01-31"),
215
+ path: "/users/seller-1/items_visits",
216
+ config: { params: { date_from: "2026-01-01", date_to: "2026-01-31" } },
217
+ data: { results: [] }
218
+ },
219
+ {
220
+ label: "item visits window",
221
+ call: () => getMercadoLibreItemVisitsWindow("profile-1", "MLA1", 7),
222
+ path: "/items/MLA1/visits/time_window",
223
+ config: { params: { last: 7, unit: "day", ending: void 0 } },
224
+ data: { total_visits: 11 }
225
+ },
226
+ {
227
+ label: "item performance",
228
+ call: () => getMercadoLibreItemPerformance("profile-1", "MLA1"),
229
+ path: "/item/MLA1/performance",
230
+ data: { health: 0.95 }
231
+ }
232
+ ])("fetches $label from the expected MercadoLibre endpoint", async ({ call, path, config, data }) => {
233
+ getMock.mockResolvedValueOnce({ data });
234
+ await expect(call()).resolves.toEqual(data);
235
+ if (config) {
236
+ expect(getMock).toHaveBeenCalledWith(path, config);
237
+ } else {
238
+ expect(getMock).toHaveBeenCalledWith(path);
239
+ }
240
+ });
241
+ it("supports custom sites and explicit ending windows in item helper endpoints", async () => {
242
+ getMock.mockResolvedValueOnce({ data: [{ domain_id: "MLB-CUSTOM" }] }).mockResolvedValueOnce({ data: { total_visits: 22 } });
243
+ await searchMercadoLibreDomainDiscovery("profile-1", "tenis", 3, "MLB");
244
+ await getMercadoLibreItemVisitsWindow("profile-1", "MLA1", 30, "week", "2026-03-31");
245
+ expect(getMock).toHaveBeenNthCalledWith(1, "/sites/MLB/domain_discovery/search", {
246
+ params: { q: "tenis", limit: 3 }
247
+ });
248
+ expect(getMock).toHaveBeenNthCalledWith(2, "/items/MLA1/visits/time_window", {
249
+ params: { last: 30, unit: "week", ending: "2026-03-31" }
250
+ });
251
+ });
252
+ it.each([
253
+ {
254
+ label: "create item",
255
+ call: () => createMercadoLibreItem("profile-1", { title: "Boots" }),
256
+ method: postMock,
257
+ path: "/items",
258
+ payload: { title: "Boots" },
259
+ data: { id: "MLA1" }
260
+ },
261
+ {
262
+ label: "update item",
263
+ call: () => updateMercadoLibreItem("profile-1", "MLA1", { price: 12e3 }),
264
+ method: putMock,
265
+ path: "/items/MLA1",
266
+ payload: { price: 12e3 },
267
+ data: { id: "MLA1", price: 12e3 }
268
+ },
269
+ {
270
+ label: "create item description",
271
+ call: () => createMercadoLibreItemDescription("profile-1", "MLA1", "new description"),
272
+ method: postMock,
273
+ path: "/items/MLA1/description",
274
+ payload: { plain_text: "new description" },
275
+ data: { plain_text: "new description" }
276
+ },
277
+ {
278
+ label: "replace item description",
279
+ call: () => replaceMercadoLibreItemDescription("profile-1", "MLA1", "fresh description"),
280
+ method: putMock,
281
+ path: "/items/MLA1/description?api_version=2",
282
+ payload: { plain_text: "fresh description" },
283
+ data: { plain_text: "fresh description" }
284
+ },
285
+ {
286
+ label: "add item picture",
287
+ call: () => addMercadoLibreItemPicture("profile-1", "MLA1", "https://img/1.png"),
288
+ method: postMock,
289
+ path: "/items/MLA1/pictures",
290
+ payload: { source: "https://img/1.png" },
291
+ data: { id: "pic-1" }
292
+ }
293
+ ])("sends the expected payload for $label", async ({ call, method, path, payload, data }) => {
294
+ method.mockResolvedValueOnce({ data });
295
+ await expect(call()).resolves.toEqual(data);
296
+ expect(method).toHaveBeenCalledWith(path, payload);
297
+ });
298
+ it("loads categories and listing types together for the same site", async () => {
299
+ getMock.mockResolvedValueOnce({ data: [{ id: "MLA1055" }] });
300
+ getMock.mockResolvedValueOnce({ data: [{ id: "gold_special" }] });
301
+ const result = await getMercadoLibreSiteCategoriesAndListingTypes("profile-1", "MLA");
302
+ expect(getMock).toHaveBeenNthCalledWith(1, "/sites/MLA/categories");
303
+ expect(getMock).toHaveBeenNthCalledWith(2, "/sites/MLA/listing_types");
304
+ expect(result).toEqual({
305
+ siteId: "MLA",
306
+ categories: [{ id: "MLA1055" }],
307
+ listingTypes: [{ id: "gold_special" }]
308
+ });
309
+ });
310
+ });
311
+ //# sourceMappingURL=mercadolibre-items.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-items.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n addMercadoLibreItemPicture,\n createMercadoLibreItem,\n createMercadoLibreItemDescription,\n estimateMercadoLibreListingPrice,\n getMercadoLibreCategoryAttributes,\n getMercadoLibreCategoryShippingPreferences,\n getMercadoLibreItem,\n getMercadoLibreItemDescription,\n getMercadoLibreItemDetailsBatch,\n getMercadoLibreItemDetailsWithFallbackBatch,\n getMercadoLibreItemPerformance,\n getMercadoLibreItemVisitsWindow,\n getMercadoLibreSiteCategoriesAndListingTypes,\n getMercadoLibreUserItemsVisits,\n replaceMercadoLibreItemDescription,\n searchMercadoLibreDomainDiscovery,\n searchMercadoLibreItems,\n searchMercadoLibreItemsBatch,\n updateMercadoLibreItem,\n} from \"../mercadolibre-items.js\";\nimport {\n getMercadoLibreApiContext,\n parseMercadoLibreMultiget,\n runMercadoLibreBatch,\n} from \"../mercadolibre-api.js\";\n\nvi.mock(\"../mercadolibre-api.js\", async () => {\n const actual = await vi.importActual<typeof import(\"../mercadolibre-api.js\")>(\n \"../mercadolibre-api.js\"\n );\n\n return {\n ...actual,\n getMercadoLibreApiContext: vi.fn(),\n parseMercadoLibreMultiget: vi.fn(),\n runMercadoLibreBatch: vi.fn(),\n };\n});\n\ndescribe(\"mercadolibre-items service\", () => {\n const getMock = vi.fn();\n const postMock = vi.fn();\n const putMock = vi.fn();\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({\n api: { get: getMock, post: postMock, put: putMock },\n sellerId: \"seller-1\",\n accessToken: \"token\",\n } as never);\n });\n\n it(\"searches seller items with the expected MercadoLibre query params\", async () => {\n getMock.mockResolvedValueOnce({ data: { results: [\"MLA1\"] } });\n\n const result = await searchMercadoLibreItems(\"profile-1\", {\n sellerId: \"seller-99\",\n status: \"active\",\n q: \"shoes\",\n listingTypeId: \"gold_special\",\n limit: 30,\n offset: 60,\n });\n\n expect(result).toEqual({ results: [\"MLA1\"] });\n expect(getMock).toHaveBeenCalledWith(\"/users/seller-99/items/search\", {\n params: {\n status: \"active\",\n q: \"shoes\",\n category: undefined,\n listing_type_id: \"gold_special\",\n orders: undefined,\n limit: 30,\n offset: 60,\n },\n });\n });\n\n it(\"applies default pagination and optional filters for item searches\", async () => {\n getMock.mockResolvedValueOnce({ data: { results: [] } });\n\n await searchMercadoLibreItems(\"profile-1\", {\n sellerId: \"seller-1\",\n category: \"MLA1055\",\n orders: \"start_time_desc\",\n });\n\n expect(getMock).toHaveBeenCalledWith(\"/users/seller-1/items/search\", {\n params: {\n status: undefined,\n q: undefined,\n category: \"MLA1055\",\n listing_type_id: undefined,\n orders: \"start_time_desc\",\n limit: 20,\n offset: 0,\n },\n });\n });\n\n it(\"delegates paginated item searches to the shared batch runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data: { results: [\"MLA1\"], paging: { total: 1 } } });\n\n const result = await searchMercadoLibreItemsBatch(\n \"profile-1\",\n {\n sellerId: \"seller-1\",\n q: \"boots\",\n },\n [40],\n { maxConcurrency: 4 }\n );\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"40\"], expect.any(Function), {\n maxConcurrency: 4,\n });\n expect(getMock).toHaveBeenCalledWith(\"/users/seller-1/items/search\", {\n params: {\n status: undefined,\n q: \"boots\",\n category: undefined,\n listing_type_id: undefined,\n orders: undefined,\n limit: 20,\n offset: 40,\n },\n });\n expect(result).toEqual({\n successful: [{ id: \"40\", document: { results: [\"MLA1\"], paging: { total: 1 } } }],\n failed: [],\n });\n });\n\n it(\"requests multiget item details with compact ids and attributes\", async () => {\n vi.mocked(parseMercadoLibreMultiget).mockResolvedValue([{ id: \"MLA1\" }] as never);\n const response = { data: [{ code: 200, body: { id: \"MLA1\" } }] };\n getMock.mockResolvedValueOnce(response);\n\n const result = await getMercadoLibreItemDetailsBatch(\"profile-1\", [\"MLA1\", \"MLA2\"], [\n \"id\",\n \"title\",\n ]);\n\n expect(getMock).toHaveBeenCalledWith(\"/items\", {\n params: {\n ids: \"MLA1,MLA2\",\n attributes: \"id,title\",\n },\n });\n expect(parseMercadoLibreMultiget).toHaveBeenCalledWith(response);\n expect(result).toEqual([{ id: \"MLA1\" }]);\n });\n\n it(\"keeps multiget request params stable when ids or attributes are empty\", async () => {\n vi.mocked(parseMercadoLibreMultiget).mockResolvedValue([] as never);\n getMock.mockResolvedValueOnce({ data: [] });\n\n await getMercadoLibreItemDetailsBatch(\"profile-1\", [], []);\n\n expect(getMock).toHaveBeenCalledWith(\"/items\", {\n params: {\n ids: \"\",\n attributes: \"\",\n },\n });\n });\n\n it(\"falls back to individual item fetches through the shared batch runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data: { id: \"MLA1\", title: \"Boots\" } });\n\n const result = await getMercadoLibreItemDetailsWithFallbackBatch(\"profile-1\", [\"MLA1\"], {\n maxRetries: 1,\n });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"MLA1\"], expect.any(Function), {\n maxRetries: 1,\n });\n expect(getMock).toHaveBeenCalledWith(\"/items/MLA1\");\n expect(result).toEqual({\n successful: [{ id: \"MLA1\", document: { id: \"MLA1\", title: \"Boots\" } }],\n failed: [],\n });\n });\n\n it.each([\n {\n label: \"single item\",\n call: () => getMercadoLibreItem(\"profile-1\", \"MLA1\"),\n path: \"/items/MLA1\",\n data: { id: \"MLA1\" },\n },\n {\n label: \"item description\",\n call: () => getMercadoLibreItemDescription(\"profile-1\", \"MLA1\"),\n path: \"/items/MLA1/description\",\n data: { plain_text: \"desc\" },\n },\n {\n label: \"domain discovery with default site\",\n call: () => searchMercadoLibreDomainDiscovery(\"profile-1\", \"zapatillas\", 5),\n path: \"/sites/MLA/domain_discovery/search\",\n config: { params: { q: \"zapatillas\", limit: 5 } },\n data: [{ domain_id: \"MLA-SNEAKERS\" }],\n },\n {\n label: \"category attributes\",\n call: () => getMercadoLibreCategoryAttributes(\"profile-1\", \"MLA1055\"),\n path: \"/categories/MLA1055/attributes\",\n data: [{ id: \"COLOR\" }],\n },\n {\n label: \"category shipping preferences\",\n call: () => getMercadoLibreCategoryShippingPreferences(\"profile-1\", \"MLA1055\"),\n path: \"/categories/MLA1055/shipping_preferences\",\n data: { mode: \"me2\" },\n },\n {\n label: \"listing price estimate\",\n call: () => estimateMercadoLibreListingPrice(\"profile-1\", { price: 10000, listing_type_id: \"gold_special\" }),\n path: \"/sites/MLA/listing_prices\",\n config: { params: { price: 10000, listing_type_id: \"gold_special\" } },\n data: [{ sale_fee_amount: 1700 }],\n },\n {\n label: \"seller item visits\",\n call: () => getMercadoLibreUserItemsVisits(\"profile-1\", \"seller-1\", \"2026-01-01\", \"2026-01-31\"),\n path: \"/users/seller-1/items_visits\",\n config: { params: { date_from: \"2026-01-01\", date_to: \"2026-01-31\" } },\n data: { results: [] },\n },\n {\n label: \"item visits window\",\n call: () => getMercadoLibreItemVisitsWindow(\"profile-1\", \"MLA1\", 7),\n path: \"/items/MLA1/visits/time_window\",\n config: { params: { last: 7, unit: \"day\", ending: undefined } },\n data: { total_visits: 11 },\n },\n {\n label: \"item performance\",\n call: () => getMercadoLibreItemPerformance(\"profile-1\", \"MLA1\"),\n path: \"/item/MLA1/performance\",\n data: { health: 0.95 },\n },\n ])(\"fetches $label from the expected MercadoLibre endpoint\", async ({ call, path, config, data }) => {\n getMock.mockResolvedValueOnce({ data });\n\n await expect(call()).resolves.toEqual(data);\n if (config) {\n expect(getMock).toHaveBeenCalledWith(path, config);\n } else {\n expect(getMock).toHaveBeenCalledWith(path);\n }\n });\n\n it(\"supports custom sites and explicit ending windows in item helper endpoints\", async () => {\n getMock\n .mockResolvedValueOnce({ data: [{ domain_id: \"MLB-CUSTOM\" }] })\n .mockResolvedValueOnce({ data: { total_visits: 22 } });\n\n await searchMercadoLibreDomainDiscovery(\"profile-1\", \"tenis\", 3, \"MLB\");\n await getMercadoLibreItemVisitsWindow(\"profile-1\", \"MLA1\", 30, \"week\", \"2026-03-31\");\n\n expect(getMock).toHaveBeenNthCalledWith(1, \"/sites/MLB/domain_discovery/search\", {\n params: { q: \"tenis\", limit: 3 },\n });\n expect(getMock).toHaveBeenNthCalledWith(2, \"/items/MLA1/visits/time_window\", {\n params: { last: 30, unit: \"week\", ending: \"2026-03-31\" },\n });\n });\n\n it.each([\n {\n label: \"create item\",\n call: () => createMercadoLibreItem(\"profile-1\", { title: \"Boots\" }),\n method: postMock,\n path: \"/items\",\n payload: { title: \"Boots\" },\n data: { id: \"MLA1\" },\n },\n {\n label: \"update item\",\n call: () => updateMercadoLibreItem(\"profile-1\", \"MLA1\", { price: 12000 }),\n method: putMock,\n path: \"/items/MLA1\",\n payload: { price: 12000 },\n data: { id: \"MLA1\", price: 12000 },\n },\n {\n label: \"create item description\",\n call: () => createMercadoLibreItemDescription(\"profile-1\", \"MLA1\", \"new description\"),\n method: postMock,\n path: \"/items/MLA1/description\",\n payload: { plain_text: \"new description\" },\n data: { plain_text: \"new description\" },\n },\n {\n label: \"replace item description\",\n call: () => replaceMercadoLibreItemDescription(\"profile-1\", \"MLA1\", \"fresh description\"),\n method: putMock,\n path: \"/items/MLA1/description?api_version=2\",\n payload: { plain_text: \"fresh description\" },\n data: { plain_text: \"fresh description\" },\n },\n {\n label: \"add item picture\",\n call: () => addMercadoLibreItemPicture(\"profile-1\", \"MLA1\", \"https://img/1.png\"),\n method: postMock,\n path: \"/items/MLA1/pictures\",\n payload: { source: \"https://img/1.png\" },\n data: { id: \"pic-1\" },\n },\n ])(\"sends the expected payload for $label\", async ({ call, method, path, payload, data }) => {\n method.mockResolvedValueOnce({ data });\n\n await expect(call()).resolves.toEqual(data);\n expect(method).toHaveBeenCalledWith(path, payload);\n });\n\n it(\"loads categories and listing types together for the same site\", async () => {\n getMock.mockResolvedValueOnce({ data: [{ id: \"MLA1055\" }] });\n getMock.mockResolvedValueOnce({ data: [{ id: \"gold_special\" }] });\n\n const result = await getMercadoLibreSiteCategoriesAndListingTypes(\"profile-1\", \"MLA\");\n\n expect(getMock).toHaveBeenNthCalledWith(1, \"/sites/MLA/categories\");\n expect(getMock).toHaveBeenNthCalledWith(2, \"/sites/MLA/listing_types\");\n expect(result).toEqual({\n siteId: \"MLA\",\n categories: [{ id: \"MLA1055\" }],\n listingTypes: [{ id: \"gold_special\" }],\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,220 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ getMercadoLibreOrder,
4
+ getMercadoLibreOrderDetailsBatch,
5
+ getMercadoLibreOrderShipments,
6
+ getMercadoLibreShipment,
7
+ getMercadoLibreShipmentBatch,
8
+ getMercadoLibreShipmentCosts,
9
+ getMercadoLibreShipmentCostsBatch,
10
+ getMercadoLibreShipmentItems,
11
+ searchMercadoLibreOrders,
12
+ searchMercadoLibreOrdersBatch
13
+ } from "../mercadolibre-orders.js";
14
+ import { getMercadoLibreApiContext, runMercadoLibreBatch } from "../mercadolibre-api.js";
15
+ vi.mock("../mercadolibre-api.js", () => ({
16
+ getMercadoLibreApiContext: vi.fn(),
17
+ runMercadoLibreBatch: vi.fn()
18
+ }));
19
+ describe("mercadolibre-orders service", () => {
20
+ const getMock = vi.fn();
21
+ beforeEach(() => {
22
+ vi.clearAllMocks();
23
+ vi.mocked(getMercadoLibreApiContext).mockResolvedValue({
24
+ api: { get: getMock },
25
+ sellerId: "seller-from-profile",
26
+ accessToken: "token"
27
+ });
28
+ });
29
+ it("uses the orders search endpoint with seller fallback and normalized dates", async () => {
30
+ getMock.mockResolvedValueOnce({ data: { results: [{ id: 1 }] } });
31
+ const result = await searchMercadoLibreOrders("profile-1", {
32
+ seller: "",
33
+ from: "2026-01-01",
34
+ to: "2026-01-31",
35
+ status: "paid",
36
+ limit: 25,
37
+ offset: 50
38
+ });
39
+ expect(result).toEqual({ results: [{ id: 1 }] });
40
+ expect(getMock).toHaveBeenCalledWith("/orders/search", {
41
+ params: {
42
+ seller: "seller-from-profile",
43
+ "order.date_created.from": "2026-01-01T00:00:00.000-00:00",
44
+ "order.date_created.to": "2026-01-31T23:59:59.999-00:00",
45
+ "order.status": "paid",
46
+ q: void 0,
47
+ sort: void 0,
48
+ offset: 50,
49
+ limit: 25
50
+ }
51
+ });
52
+ });
53
+ it("preserves explicit seller, q and sort filters in order searches", async () => {
54
+ getMock.mockResolvedValueOnce({ data: { results: [{ id: 2 }] } });
55
+ await searchMercadoLibreOrders("profile-1", {
56
+ seller: "seller-override",
57
+ from: "2026-02-01",
58
+ to: "2026-02-02",
59
+ q: "SKU-123",
60
+ sort: "date_desc"
61
+ });
62
+ expect(getMock).toHaveBeenCalledWith("/orders/search", {
63
+ params: {
64
+ seller: "seller-override",
65
+ "order.date_created.from": "2026-02-01T00:00:00.000-00:00",
66
+ "order.date_created.to": "2026-02-02T23:59:59.999-00:00",
67
+ "order.status": void 0,
68
+ q: "SKU-123",
69
+ sort: "date_desc",
70
+ offset: 0,
71
+ limit: 50
72
+ }
73
+ });
74
+ });
75
+ it("builds batch order searches from offset ids", async () => {
76
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
77
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
78
+ failed: []
79
+ }));
80
+ getMock.mockResolvedValueOnce({ data: { results: [], paging: { total: 0 } } });
81
+ const result = await searchMercadoLibreOrdersBatch(
82
+ "profile-1",
83
+ {
84
+ seller: "",
85
+ from: "2026-02-01",
86
+ to: "2026-02-28"
87
+ },
88
+ [100],
89
+ { maxConcurrency: 2 }
90
+ );
91
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["100"], expect.any(Function), {
92
+ maxConcurrency: 2
93
+ });
94
+ expect(getMock).toHaveBeenCalledWith("/orders/search", {
95
+ params: {
96
+ seller: "seller-from-profile",
97
+ "order.date_created.from": "2026-02-01T00:00:00.000-00:00",
98
+ "order.date_created.to": "2026-02-28T23:59:59.999-00:00",
99
+ "order.status": void 0,
100
+ q: void 0,
101
+ sort: void 0,
102
+ offset: 100,
103
+ limit: 50
104
+ }
105
+ });
106
+ expect(result).toEqual({
107
+ successful: [{ id: "100", document: { results: [], paging: { total: 0 } } }],
108
+ failed: []
109
+ });
110
+ });
111
+ it("passes explicit seller and empty offsets through the shared batch order search runner", async () => {
112
+ vi.mocked(runMercadoLibreBatch).mockResolvedValue({ successful: [], failed: [] });
113
+ const result = await searchMercadoLibreOrdersBatch(
114
+ "profile-1",
115
+ {
116
+ seller: "seller-explicit",
117
+ from: "2026-03-01",
118
+ to: "2026-03-31",
119
+ status: "confirmed"
120
+ },
121
+ [],
122
+ { maxRetries: 1 }
123
+ );
124
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith([], expect.any(Function), { maxRetries: 1 });
125
+ expect(getMock).not.toHaveBeenCalled();
126
+ expect(result).toEqual({ successful: [], failed: [] });
127
+ });
128
+ it("loads order details in batch through the shared batch runner", async () => {
129
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher, options) => ({
130
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
131
+ failed: options?.maxRetries ? [] : []
132
+ }));
133
+ getMock.mockResolvedValueOnce({ data: { id: "2001", status: "paid" } });
134
+ const result = await getMercadoLibreOrderDetailsBatch("profile-1", ["2001"], {
135
+ maxRetries: 1
136
+ });
137
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["2001"], expect.any(Function), {
138
+ maxRetries: 1
139
+ });
140
+ expect(getMock).toHaveBeenCalledWith("/orders/2001");
141
+ expect(result).toEqual({
142
+ successful: [{ id: "2001", document: { id: "2001", status: "paid" } }],
143
+ failed: []
144
+ });
145
+ });
146
+ it.each([
147
+ {
148
+ label: "single order",
149
+ call: () => getMercadoLibreOrder("profile-1", "2001"),
150
+ path: "/orders/2001",
151
+ data: { id: "2001" }
152
+ },
153
+ {
154
+ label: "order shipments",
155
+ call: () => getMercadoLibreOrderShipments("profile-1", "2001"),
156
+ path: "/orders/2001/shipments",
157
+ data: { shipments: [] }
158
+ },
159
+ {
160
+ label: "single shipment",
161
+ call: () => getMercadoLibreShipment("profile-1", "ship-1"),
162
+ path: "/shipments/ship-1",
163
+ data: { id: "ship-1" }
164
+ },
165
+ {
166
+ label: "shipment items",
167
+ call: () => getMercadoLibreShipmentItems("profile-1", "ship-1"),
168
+ path: "/shipments/ship-1/items",
169
+ data: { items: [] }
170
+ },
171
+ {
172
+ label: "shipment costs",
173
+ call: () => getMercadoLibreShipmentCosts("profile-1", "ship-1"),
174
+ path: "/shipments/ship-1/costs",
175
+ data: { gross_amount: 99 }
176
+ }
177
+ ])("fetches $label from the expected MercadoLibre endpoint", async ({ call, path, data }) => {
178
+ getMock.mockResolvedValueOnce({ data });
179
+ await expect(call()).resolves.toEqual(data);
180
+ expect(getMock).toHaveBeenCalledWith(path);
181
+ });
182
+ it.each([
183
+ {
184
+ label: "shipment details batch",
185
+ call: () => getMercadoLibreShipmentBatch("profile-1", ["ship-1"], { maxConcurrency: 3 }),
186
+ expectedIds: ["ship-1"],
187
+ expectedOptions: { maxConcurrency: 3 },
188
+ responsePath: "/shipments/ship-1",
189
+ data: { id: "ship-1", status: "ready_to_ship" }
190
+ },
191
+ {
192
+ label: "shipment costs batch",
193
+ call: () => getMercadoLibreShipmentCostsBatch("profile-1", ["ship-2"], { maxRetries: 2 }),
194
+ expectedIds: ["ship-2"],
195
+ expectedOptions: { maxRetries: 2 },
196
+ responsePath: "/shipments/ship-2/costs",
197
+ data: { id: "ship-2", gross_amount: 15 }
198
+ }
199
+ ])("delegates $label to the shared batch runner with the right fetcher", async ({
200
+ call,
201
+ expectedIds,
202
+ expectedOptions,
203
+ responsePath,
204
+ data
205
+ }) => {
206
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
207
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
208
+ failed: []
209
+ }));
210
+ getMock.mockResolvedValueOnce({ data });
211
+ const result = await call();
212
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(expectedIds, expect.any(Function), expectedOptions);
213
+ expect(getMock).toHaveBeenCalledWith(responsePath);
214
+ expect(result).toEqual({
215
+ successful: [{ id: expectedIds[0], document: data }],
216
+ failed: []
217
+ });
218
+ });
219
+ });
220
+ //# sourceMappingURL=mercadolibre-orders.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-orders.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n getMercadoLibreOrder,\n getMercadoLibreOrderDetailsBatch,\n getMercadoLibreOrderShipments,\n getMercadoLibreShipment,\n getMercadoLibreShipmentBatch,\n getMercadoLibreShipmentCosts,\n getMercadoLibreShipmentCostsBatch,\n getMercadoLibreShipmentItems,\n searchMercadoLibreOrders,\n searchMercadoLibreOrdersBatch,\n} from \"../mercadolibre-orders.js\";\nimport { getMercadoLibreApiContext, runMercadoLibreBatch } from \"../mercadolibre-api.js\";\n\nvi.mock(\"../mercadolibre-api.js\", () => ({\n getMercadoLibreApiContext: vi.fn(),\n runMercadoLibreBatch: vi.fn(),\n}));\n\ndescribe(\"mercadolibre-orders service\", () => {\n const getMock = vi.fn();\n\n beforeEach(() => {\n vi.clearAllMocks();\n\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({\n api: { get: getMock },\n sellerId: \"seller-from-profile\",\n accessToken: \"token\",\n } as never);\n });\n\n it(\"uses the orders search endpoint with seller fallback and normalized dates\", async () => {\n getMock.mockResolvedValueOnce({ data: { results: [{ id: 1 }] } });\n\n const result = await searchMercadoLibreOrders(\"profile-1\", {\n seller: \"\",\n from: \"2026-01-01\",\n to: \"2026-01-31\",\n status: \"paid\",\n limit: 25,\n offset: 50,\n });\n\n expect(result).toEqual({ results: [{ id: 1 }] });\n expect(getMock).toHaveBeenCalledWith(\"/orders/search\", {\n params: {\n seller: \"seller-from-profile\",\n \"order.date_created.from\": \"2026-01-01T00:00:00.000-00:00\",\n \"order.date_created.to\": \"2026-01-31T23:59:59.999-00:00\",\n \"order.status\": \"paid\",\n q: undefined,\n sort: undefined,\n offset: 50,\n limit: 25,\n },\n });\n });\n\n it(\"preserves explicit seller, q and sort filters in order searches\", async () => {\n getMock.mockResolvedValueOnce({ data: { results: [{ id: 2 }] } });\n\n await searchMercadoLibreOrders(\"profile-1\", {\n seller: \"seller-override\",\n from: \"2026-02-01\",\n to: \"2026-02-02\",\n q: \"SKU-123\",\n sort: \"date_desc\",\n });\n\n expect(getMock).toHaveBeenCalledWith(\"/orders/search\", {\n params: {\n seller: \"seller-override\",\n \"order.date_created.from\": \"2026-02-01T00:00:00.000-00:00\",\n \"order.date_created.to\": \"2026-02-02T23:59:59.999-00:00\",\n \"order.status\": undefined,\n q: \"SKU-123\",\n sort: \"date_desc\",\n offset: 0,\n limit: 50,\n },\n });\n });\n\n it(\"builds batch order searches from offset ids\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data: { results: [], paging: { total: 0 } } });\n\n const result = await searchMercadoLibreOrdersBatch(\n \"profile-1\",\n {\n seller: \"\",\n from: \"2026-02-01\",\n to: \"2026-02-28\",\n },\n [100],\n { maxConcurrency: 2 }\n );\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"100\"], expect.any(Function), {\n maxConcurrency: 2,\n });\n expect(getMock).toHaveBeenCalledWith(\"/orders/search\", {\n params: {\n seller: \"seller-from-profile\",\n \"order.date_created.from\": \"2026-02-01T00:00:00.000-00:00\",\n \"order.date_created.to\": \"2026-02-28T23:59:59.999-00:00\",\n \"order.status\": undefined,\n q: undefined,\n sort: undefined,\n offset: 100,\n limit: 50,\n },\n });\n expect(result).toEqual({\n successful: [{ id: \"100\", document: { results: [], paging: { total: 0 } } }],\n failed: [],\n });\n });\n\n it(\"passes explicit seller and empty offsets through the shared batch order search runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockResolvedValue({ successful: [], failed: [] } as never);\n\n const result = await searchMercadoLibreOrdersBatch(\n \"profile-1\",\n {\n seller: \"seller-explicit\",\n from: \"2026-03-01\",\n to: \"2026-03-31\",\n status: \"confirmed\",\n },\n [],\n { maxRetries: 1 }\n );\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([], expect.any(Function), { maxRetries: 1 });\n expect(getMock).not.toHaveBeenCalled();\n expect(result).toEqual({ successful: [], failed: [] });\n });\n\n it(\"loads order details in batch through the shared batch runner\", async () => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher, options) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: options?.maxRetries ? [] : [],\n }));\n getMock.mockResolvedValueOnce({ data: { id: \"2001\", status: \"paid\" } });\n\n const result = await getMercadoLibreOrderDetailsBatch(\"profile-1\", [\"2001\"], {\n maxRetries: 1,\n });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"2001\"], expect.any(Function), {\n maxRetries: 1,\n });\n expect(getMock).toHaveBeenCalledWith(\"/orders/2001\");\n expect(result).toEqual({\n successful: [{ id: \"2001\", document: { id: \"2001\", status: \"paid\" } }],\n failed: [],\n });\n });\n\n it.each([\n {\n label: \"single order\",\n call: () => getMercadoLibreOrder(\"profile-1\", \"2001\"),\n path: \"/orders/2001\",\n data: { id: \"2001\" },\n },\n {\n label: \"order shipments\",\n call: () => getMercadoLibreOrderShipments(\"profile-1\", \"2001\"),\n path: \"/orders/2001/shipments\",\n data: { shipments: [] },\n },\n {\n label: \"single shipment\",\n call: () => getMercadoLibreShipment(\"profile-1\", \"ship-1\"),\n path: \"/shipments/ship-1\",\n data: { id: \"ship-1\" },\n },\n {\n label: \"shipment items\",\n call: () => getMercadoLibreShipmentItems(\"profile-1\", \"ship-1\"),\n path: \"/shipments/ship-1/items\",\n data: { items: [] },\n },\n {\n label: \"shipment costs\",\n call: () => getMercadoLibreShipmentCosts(\"profile-1\", \"ship-1\"),\n path: \"/shipments/ship-1/costs\",\n data: { gross_amount: 99 },\n },\n ])(\"fetches $label from the expected MercadoLibre endpoint\", async ({ call, path, data }) => {\n getMock.mockResolvedValueOnce({ data });\n\n await expect(call()).resolves.toEqual(data);\n expect(getMock).toHaveBeenCalledWith(path);\n });\n\n it.each([\n {\n label: \"shipment details batch\",\n call: () => getMercadoLibreShipmentBatch(\"profile-1\", [\"ship-1\"], { maxConcurrency: 3 }),\n expectedIds: [\"ship-1\"],\n expectedOptions: { maxConcurrency: 3 },\n responsePath: \"/shipments/ship-1\",\n data: { id: \"ship-1\", status: \"ready_to_ship\" },\n },\n {\n label: \"shipment costs batch\",\n call: () => getMercadoLibreShipmentCostsBatch(\"profile-1\", [\"ship-2\"], { maxRetries: 2 }),\n expectedIds: [\"ship-2\"],\n expectedOptions: { maxRetries: 2 },\n responsePath: \"/shipments/ship-2/costs\",\n data: { id: \"ship-2\", gross_amount: 15 },\n },\n ])(\"delegates $label to the shared batch runner with the right fetcher\", async ({\n call,\n expectedIds,\n expectedOptions,\n responsePath,\n data,\n }) => {\n vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({\n successful: [{ id: ids[0], document: await fetcher(ids[0]) }],\n failed: [],\n }));\n getMock.mockResolvedValueOnce({ data });\n\n const result = await call();\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith(expectedIds, expect.any(Function), expectedOptions);\n expect(getMock).toHaveBeenCalledWith(responsePath);\n expect(result).toEqual({\n successful: [{ id: expectedIds[0], document: data }],\n failed: [],\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }