@yoryoboy/bi-mcp 1.16.0 → 1.19.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 (158) hide show
  1. package/README.md +12 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +179 -6
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +3 -6
  6. package/dist/src/config/__tests__/google-store.test.js +30 -0
  7. package/dist/src/config/__tests__/google-store.test.js.map +7 -0
  8. package/dist/src/config/__tests__/mcp-tool-deadline.test.js +64 -0
  9. package/dist/src/config/__tests__/mcp-tool-deadline.test.js.map +7 -0
  10. package/dist/src/config/google-store.js +18 -0
  11. package/dist/src/config/google-store.js.map +2 -2
  12. package/dist/src/config/mcp-tool-deadline-context.js +34 -0
  13. package/dist/src/config/mcp-tool-deadline-context.js.map +7 -0
  14. package/dist/src/config/mcp-tool-deadline.js +67 -0
  15. package/dist/src/config/mcp-tool-deadline.js.map +7 -0
  16. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +38 -3
  17. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +2 -2
  18. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js +226 -0
  19. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js.map +7 -0
  20. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js +127 -0
  21. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js.map +7 -0
  22. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js +103 -0
  23. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js.map +7 -0
  24. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js +582 -0
  25. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js.map +7 -0
  26. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +10 -0
  27. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +2 -2
  28. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js +36 -0
  29. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js.map +7 -0
  30. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js +137 -0
  31. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js.map +7 -0
  32. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js +105 -0
  33. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js.map +7 -0
  34. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js +143 -0
  35. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js.map +7 -0
  36. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js +100 -0
  37. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js.map +7 -0
  38. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js +350 -0
  39. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js.map +7 -0
  40. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js +228 -0
  41. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js.map +7 -0
  42. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js +58 -0
  43. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js.map +7 -0
  44. package/dist/src/services/mercadolibre/mercadolibre-api.js +15 -3
  45. package/dist/src/services/mercadolibre/mercadolibre-api.js.map +2 -2
  46. package/dist/src/services/mercadolibre/mercadolibre-billing.js +110 -3
  47. package/dist/src/services/mercadolibre/mercadolibre-billing.js.map +2 -2
  48. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js +368 -0
  49. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js.map +7 -0
  50. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js +399 -0
  51. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js.map +7 -0
  52. package/dist/src/services/mercadolibre/mercadolibre-kits.js +55 -0
  53. package/dist/src/services/mercadolibre/mercadolibre-kits.js.map +7 -0
  54. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js +392 -0
  55. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js.map +7 -0
  56. package/dist/src/services/mercadolibre/mercadolibre-orders.js +8 -8
  57. package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +2 -2
  58. package/dist/src/services/mercadolibre/mercadolibre-packs.js +21 -0
  59. package/dist/src/services/mercadolibre/mercadolibre-packs.js.map +7 -0
  60. package/dist/src/services/mercadolibre/mercadolibre-payments.js +60 -0
  61. package/dist/src/services/mercadolibre/mercadolibre-payments.js.map +7 -0
  62. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js +429 -0
  63. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js.map +7 -0
  64. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js +436 -0
  65. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js.map +7 -0
  66. package/dist/src/services/mercadolibre/mercadolibre-shipping.js +35 -0
  67. package/dist/src/services/mercadolibre/mercadolibre-shipping.js.map +7 -0
  68. package/dist/src/services/vtex/__tests__/vtex-api.test.js +67 -0
  69. package/dist/src/services/vtex/__tests__/vtex-api.test.js.map +7 -0
  70. package/dist/src/services/vtex/vtex-api.js +6 -0
  71. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  72. package/dist/src/tools/config/__tests__/list-profiles.test.js +154 -0
  73. package/dist/src/tools/config/__tests__/list-profiles.test.js.map +7 -0
  74. package/dist/src/tools/config/list-profiles.js +39 -3
  75. package/dist/src/tools/config/list-profiles.js.map +2 -2
  76. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js +339 -0
  77. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js.map +7 -0
  78. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js +225 -0
  79. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js.map +7 -0
  80. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js +148 -0
  81. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js.map +7 -0
  82. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js +60 -0
  83. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js.map +7 -0
  84. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js +128 -0
  85. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js.map +7 -0
  86. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js +435 -0
  87. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js.map +7 -0
  88. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js +31 -0
  89. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js.map +7 -0
  90. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js +36 -0
  91. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js.map +7 -0
  92. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js +205 -0
  93. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js.map +7 -0
  94. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js +313 -0
  95. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js.map +7 -0
  96. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js +176 -0
  97. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js.map +7 -0
  98. package/dist/src/tools/mercadolibre/get-full-storage-charges.js +183 -0
  99. package/dist/src/tools/mercadolibre/get-full-storage-charges.js.map +7 -0
  100. package/dist/src/tools/mercadolibre/get-order-billing-info.js +189 -0
  101. package/dist/src/tools/mercadolibre/get-order-billing-info.js.map +7 -0
  102. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js +150 -0
  103. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js.map +7 -0
  104. package/dist/src/tools/mercadolibre/get-payment-details.js +322 -0
  105. package/dist/src/tools/mercadolibre/get-payment-details.js.map +7 -0
  106. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js +144 -0
  107. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js.map +7 -0
  108. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js +59 -0
  109. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js.map +7 -0
  110. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js +104 -0
  111. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js.map +7 -0
  112. package/dist/src/tools/mercadolibre/index.js +32 -0
  113. package/dist/src/tools/mercadolibre/index.js.map +2 -2
  114. package/dist/src/tools/mercadolibre/product-ads-helpers.js +130 -0
  115. package/dist/src/tools/mercadolibre/product-ads-helpers.js.map +7 -0
  116. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js +27 -0
  117. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js.map +7 -0
  118. package/dist/src/tools/mercadolibre/reconcile-claim-data.js +46 -0
  119. package/dist/src/tools/mercadolibre/reconcile-claim-data.js.map +7 -0
  120. package/dist/src/tools/mercadolibre/reconcile-return-data.js +25 -0
  121. package/dist/src/tools/mercadolibre/reconcile-return-data.js.map +7 -0
  122. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js +162 -0
  123. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js.map +7 -0
  124. package/dist/src/tools/mercadolibre/search-product-ads-ads.js +216 -0
  125. package/dist/src/tools/mercadolibre/search-product-ads-ads.js.map +7 -0
  126. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js +116 -0
  127. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js.map +7 -0
  128. package/dist/src/tools/mercadolibre/validate-connection.js +40 -12
  129. package/dist/src/tools/mercadolibre/validate-connection.js.map +2 -2
  130. package/dist/tests/meli/mercadolibre-billing-provisions.test.js +378 -0
  131. package/dist/tests/meli/mercadolibre-billing-provisions.test.js.map +2 -2
  132. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js +123 -0
  133. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js.map +7 -0
  134. package/dist/tests/meli/mercadolibre-payment-details.test.js +356 -0
  135. package/dist/tests/meli/mercadolibre-payment-details.test.js.map +7 -0
  136. package/dist/tests/meli/mercadolibre-payments.test.js +62 -0
  137. package/dist/tests/meli/mercadolibre-payments.test.js.map +7 -0
  138. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js +90 -0
  139. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js.map +7 -0
  140. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js +72 -0
  141. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js.map +7 -0
  142. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js +400 -0
  143. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js.map +7 -0
  144. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +31 -12
  145. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +2 -2
  146. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js +1 -1
  147. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js.map +1 -1
  148. package/package.json +1 -1
  149. package/dist/src/google-ads/report-utils.js +0 -78
  150. package/dist/src/google-ads/report-utils.js.map +0 -7
  151. package/dist/src/search-console/search-console-utils.js +0 -275
  152. package/dist/src/search-console/search-console-utils.js.map +0 -7
  153. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +0 -165
  154. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +0 -7
  155. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +0 -233
  156. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +0 -7
  157. package/dist/src/tools/vtex/catalog-admin-batch.js +0 -298
  158. package/dist/src/tools/vtex/catalog-admin-batch.js.map +0 -7
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst { billingMock, orderMock, shipmentMock, ownershipMock } = vi.hoisted(() => ({\n billingMock: vi.fn(), orderMock: vi.fn(), shipmentMock: vi.fn(), ownershipMock: vi.fn(),\n}));\nvi.mock(\"../mercadolibre-order-billing-info.js\", () => ({ getMercadoLibreSaleBillingInfo: billingMock, verifyMercadoLibreOrderOwnership: ownershipMock }));\nvi.mock(\"../mercadolibre-orders.js\", () => ({ getMercadoLibreOrder: orderMock, getMercadoLibreShipment: shipmentMock }));\n\nimport { MercadoLibreApiError } from \"../mercadolibre-api.js\";\nimport { getBuyerReconciliationSafetyMarginMs, reconcileMercadoLibreBuyerData } from \"../mercadolibre-buyer-reconciliation.js\";\nimport { createMcpToolDeadlineMiddleware } from \"../../../config/mcp-tool-deadline.js\";\n\nconst order = (id: string, shipment = \"1001\") => ({ id, seller: { id: \"seller-1\" }, buyer: { nickname: \"buyer-nick\" }, shipping: { id: shipment } });\nconst available = (id: string, type = \"DNI\", number = \"123\", shipment = \"1001\") => ({\n available: true as const,\n order: order(id, shipment),\n billingInfo: { buyer: { billing_info: {\n name: \"Ada\", last_name: \"Lovelace\", identification: { type, number },\n address: { street_name: \"Main\", street_number: 10, city_name: \"City\", state: { code: \"S\", name: \"State\" }, zip_code: \"1000\", country_id: \"AR\" },\n taxes: { taxpayer_type: { id: \"CONSUMIDOR_FINAL\", description: \"Consumidor Final\" } },\n } } },\n});\nconst missingFiscal = { available: false as const, reason: \"billing_info_fiscal_fields_missing\" as const };\nconst shipment = { destination: { shipping_address: { street_name: \"Shipping\", street_number: \"20\", city_name: \"Port\", state: { name: \"Province\" }, zip_code: \"2000\", country_id: \"AR\" } } };\n\ndescribe(\"reconcileMercadoLibreBuyerData\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n ownershipMock.mockResolvedValue(\"owned\");\n shipmentMock.mockResolvedValue(shipment);\n });\n\n it(\"derives a bounded safety margin from the global timeout\", () => {\n expect(getBuyerReconciliationSafetyMarginMs(300_000)).toBe(10_000);\n expect(getBuyerReconciliationSafetyMarginMs(2_000)).toBe(100);\n expect(getBuyerReconciliationSafetyMarginMs(1_000_000)).toBe(10_000);\n });\n\n it(\"returns a complete direct order with buyer, document, fiscal and shipping addresses\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\", \"DNI\", \"111\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n const item = result.results[0];\n expect(item).toMatchObject({ sale_reference: \"sale-1\", resolution: { kind: \"order\", status: \"resolved\" }, data: { completeness: \"complete\" } });\n expect(item.data.buyer).toMatchObject({ full_name: \"Ada Lovelace\", nickname: \"buyer-nick\", document: { type: \"DNI\", number: \"111\" }, fiscal_address: { state: \"State\" }, shipping_address: { street: \"Shipping 20\" } });\n expect(item.data).not.toHaveProperty(\"sources\");\n expect(item.data).not.toHaveProperty(\"missing_fields\");\n expect(item.data).not.toHaveProperty(\"reasons\");\n expect(item).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toEqual({ requested: 1, complete: 1, partial: 0, unavailable: 0, orders: 1, packs: 0, unknown: 0 });\n });\n\n it(\"keeps useful order buyer data when fiscal fields are partial\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: missingFiscal });\n orderMock.mockResolvedValue(order(\"o-1\"));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data).toMatchObject({ completeness: \"partial\", buyer: { nickname: \"buyer-nick\" } });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"fiscal_address\", code: \"billing_info_fiscal_fields_missing\" }));\n });\n\n it.each([[\"DNI\", \"DNI\"], [\"CUIT\", \"CUIT\"]] as const)(\"normalizes %s documents without changing the number\", async (source, expected) => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\", source, \"999\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data.buyer?.document).toEqual({ type: expected, number: \"999\" });\n });\n\n it(\"consolidates a unanimous pack at top-level data and hides member identifiers\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"123\", \"1001\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"DNI\", \"123\", \"1002\") },\n ] });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0]).toMatchObject({ pack: { agreement: \"unanimous\" }, data: { completeness: \"complete\" } });\n expect(result.results[0].data).not.toHaveProperty(\"issues\");\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result.results[0].pack).not.toHaveProperty(\"consolidated\");\n expect(result.results[0].pack).not.toHaveProperty(\"members\");\n expect(JSON.stringify(result)).not.toMatch(/pack-secret|m-1|m-2/);\n });\n\n it(\"does not consolidate a pack when shipping destinations differ\", async () => {\n const secondShipment = { destination: { shipping_address: { street_name: \"Other\", street_number: \"20\", city_name: \"Port\", state: { name: \"Province\" }, zip_code: \"2000\", country_id: \"AR\" } } };\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"123\", \"1001\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"DNI\", \"123\", \"1002\") },\n ] });\n shipmentMock.mockImplementation(async (_profile: string, shipmentId: string) => shipmentId === \"1002\" ? secondShipment : shipment);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.agreement).toBe(\"disagreement\");\n expect(result.results[0].data.completeness).toBe(\"partial\");\n expect(result.results[0].pack).toHaveProperty(\"members\");\n expect(result.summary).toMatchObject({ complete: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"returns opaque indexed members for disagreement and partial packs\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: true, result: available(\"m-1\", \"DNI\", \"1\") }, { orderId: \"m-2\", accessible: true, result: available(\"m-2\", \"CUIT\", \"2\") },\n ] });\n let result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack).toMatchObject({ agreement: \"disagreement\", members: [{ member_index: 0 }, { member_index: 1 }] });\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [{ orderId: \"m-1\", accessible: true, result: missingFiscal }, { orderId: \"m-2\", accessible: false, failureReason: \"access_denied\" }] });\n result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.agreement).toBe(\"partial\");\n expect(result.results[0].pack?.members?.[1]).toMatchObject({ member_index: 1, data: { completeness: \"unavailable\" } });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"pack_members\", code: \"pack_partial_coverage\" }));\n expect(result.summary).toMatchObject({ complete: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"exposes a safe shipping issue without operational metadata\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\") });\n shipmentMock.mockRejectedValue(new MercadoLibreApiError(\"temporary\", 503));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 1, sleep: async () => undefined });\n expect(result.results[0].data.issues).toContainEqual(expect.objectContaining({ field: \"shipping_address\", code: \"shipping_source_unavailable\" }));\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n });\n\n it(\"counts only actual shipping retry exhaustion in the degraded event\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-1\", result: available(\"o-1\") });\n shipmentMock.mockRejectedValue(new MercadoLibreApiError(\"temporary\", 503));\n\n const withoutRetry = vi.fn();\n await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 0, onDegradedOutcome: withoutRetry });\n expect(withoutRetry).toHaveBeenCalledWith(expect.objectContaining({ retry: 0 }));\n\n const exhausted = vi.fn();\n await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { maxRetries: 1, sleep: async () => undefined, onDegradedOutcome: exhausted });\n expect(exhausted).toHaveBeenCalledWith(expect.objectContaining({ retry: 1 }));\n expect(shipmentMock).toHaveBeenCalledTimes(3);\n });\n\n it(\"reports pack member issues without operational metadata or upstream details\", async () => {\n billingMock.mockResolvedValue({ resolutionKind: \"pack\", packId: \"pack-secret\", metadata: { memberCount: 2 }, members: [\n { orderId: \"m-1\", accessible: false, failureReason: \"operation_deadline_exceeded\" },\n { orderId: \"m-2\", accessible: false, failureReason: \"upstream_unavailable\", attempts: 3, retryable: true },\n ] });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0].pack?.members?.[0].data.issues).toContainEqual(expect.objectContaining({ code: \"operation_deadline_exceeded\" }));\n expect(result.results[0].pack?.members?.[1].data.issues).toContainEqual(expect.objectContaining({ code: \"upstream_unavailable\" }));\n expect(result.results[0]).not.toHaveProperty(\"metadata\");\n expect(result).not.toHaveProperty(\"metadata\");\n expect(JSON.stringify(result)).not.toContain(\"temporary\");\n });\n\n it(\"propagates an unavailable pack deadline as a safe issue\", async () => {\n billingMock.mockResolvedValue({\n resolutionKind: \"pack\",\n packId: \"pack-secret\",\n members: [],\n unavailableReason: \"pack_operation_deadline_exceeded\",\n metadata: { memberCount: 0 },\n });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"pack-sale\"]);\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"pack\", status: \"unavailable\" }, data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0 });\n });\n\n it.each([\"mismatch\", \"unverifiable\"] as const)(\"returns no PII when ownership is %s\", async (ownership) => {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"foreign-order\", result: missingFiscal });\n orderMock.mockResolvedValue({ ...order(\"foreign-order\"), buyer: { nickname: \"secret-buyer\" } });\n ownershipMock.mockResolvedValue(ownership);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0].data.buyer).toBeUndefined();\n expect(JSON.stringify(result)).not.toContain(\"secret-buyer\");\n expect(shipmentMock).not.toHaveBeenCalled();\n });\n\n it(\"does not turn a deadline during order lookup into pack fallback\", async () => {\n billingMock.mockRejectedValue(new MercadoLibreApiError(\"timeout\", undefined));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { operationDeadlineMs: 1, now: () => 10 });\n expect(result.results[0].resolution.kind).toBe(\"unknown\");\n expect(billingMock).toHaveBeenCalledTimes(1);\n expect(orderMock).not.toHaveBeenCalled();\n });\n\n it(\"marks already-expired references as partial processing\", async () => {\n const now = vi.fn().mockReturnValueOnce(10).mockReturnValue(11);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"], { operationDeadlineMs: 1, now });\n expect(result.results[0]).toMatchObject({ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0 });\n });\n\n it(\"returns a structured reference issue before the outer middleware deadline\", async () => {\n vi.useFakeTimers();\n billingMock.mockImplementation(() => new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"billing source unavailable\")), 10);\n }));\n const middleware = createMcpToolDeadlineMiddleware(25);\n const resultPromise = middleware({}, () => reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]));\n\n await vi.advanceTimersByTimeAsync(10);\n await expect(resultPromise).resolves.toMatchObject({\n results: [{ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } }],\n });\n vi.useRealTimers();\n });\n\n it.each([\n [\"AbortError\", Object.assign(new Error(\"cancelled\"), { name: \"AbortError\" })],\n [\"timeout sentinel\", Object.assign(new Error(\"request timed out\"), { code: \"ETIMEDOUT\" })],\n ])(\"classifies %s as an operation deadline\", async (_label, failure) => {\n billingMock.mockRejectedValue(failure);\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0]).toMatchObject({ data: { issues: [expect.objectContaining({ code: \"operation_deadline_exceeded\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n });\n\n it(\"keeps nondeadline resolution failures as reference_unavailable\", async () => {\n billingMock.mockRejectedValue(new Error(\"billing source unavailable\"));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-1\"]);\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"unknown\", status: \"unavailable\" }, data: { issues: [expect.objectContaining({ code: \"reference_unavailable\" })] } });\n expect(result).not.toHaveProperty(\"metadata\");\n expect(result.summary).toMatchObject({ requested: 1, unavailable: 1, partial: 0, unknown: 1 });\n });\n\n it(\"preserves duplicate occurrences and input order\", async () => {\n billingMock.mockImplementation(async (_profile: string, reference: string) => ({ resolutionKind: \"order\", orderId: reference, result: available(reference) }));\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"second\", \"first\", \"second\"]);\n expect(result.results.map((item) => item.sale_reference)).toEqual([\"second\", \"first\", \"second\"]);\n expect(result.summary.requested).toBe(3);\n });\n\n it(\"emits only aggregate degraded events and keeps the public response unchanged\", async () => {\n const warn = vi.spyOn(console, \"warn\").mockImplementation(() => undefined);\n const error = vi.spyOn(console, \"error\").mockImplementation(() => undefined);\n try {\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-secret\", result: available(\"o-secret\", \"CUIT\", \"secret-doc\") });\n const result = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-secret\"]);\n expect(warn).not.toHaveBeenCalled();\n expect(error).not.toHaveBeenCalled();\n expect(result.results[0].data.buyer?.document?.number).toBe(\"secret-doc\");\n\n billingMock.mockResolvedValue({ resolutionKind: \"order\", orderId: \"o-secret\", result: missingFiscal });\n const degraded = await reconcileMercadoLibreBuyerData(\"triplim\", [\"sale-secret\"], { onDegradedOutcome: (event) => warn(JSON.stringify(event)) });\n expect(warn).toHaveBeenCalledOnce();\n expect(warn.mock.calls[0]?.[0]).not.toContain(\"secret-doc\");\n expect(degraded).not.toHaveProperty(\"operational_event\");\n expect(degraded).not.toHaveProperty(\"telemetry\");\n\n } finally { warn.mockRestore(); error.mockRestore(); }\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["shipment"]
7
+ }
@@ -0,0 +1,127 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { MercadoLibreApiError, getMercadoLibreApiContext } from "../mercadolibre-api.js";
3
+ import { getClaimReconciliationDeadlineMs, reconcileMercadoLibreClaimData } from "../mercadolibre-claim-reconciliation.js";
4
+ import { getMcpToolDeadlineRemainingMs, runWithMcpToolDeadlineContext } from "../../../config/mcp-tool-deadline-context.js";
5
+ const { getMock } = vi.hoisted(() => ({ getMock: vi.fn() }));
6
+ vi.mock("../mercadolibre-api.js", async () => {
7
+ const actual = await vi.importActual("../mercadolibre-api.js");
8
+ return { ...actual, getMercadoLibreApiContext: vi.fn() };
9
+ });
10
+ describe("reconcileMercadoLibreClaimData", () => {
11
+ beforeEach(() => {
12
+ vi.clearAllMocks();
13
+ vi.mocked(getMercadoLibreApiContext).mockResolvedValue({ api: { get: getMock }, sellerId: "seller-1", accessToken: "token" });
14
+ });
15
+ it("uses the shorter MCP caller budget with a bounded safety margin", async () => {
16
+ const signal = new AbortController().signal;
17
+ await runWithMcpToolDeadlineContext(signal, async () => {
18
+ expect(getMcpToolDeadlineRemainingMs(1e4)).toBe(1e3);
19
+ expect(getClaimReconciliationDeadlineMs(getMcpToolDeadlineRemainingMs(1e4))).toBe(900);
20
+ }, 11e3);
21
+ expect(getClaimReconciliationDeadlineMs(3e5)).toBe(29e4);
22
+ });
23
+ it("derives full message summaries from the projected messages", async () => {
24
+ getMock.mockImplementation(async (path, config) => {
25
+ if (path === "/post-purchase/v1/claims/search") {
26
+ return { data: { paging: { total: config?.params?.type === "returns" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === "returns" ? [{ id: "claim-1", resource_id: "order-1" }] : [] } };
27
+ }
28
+ if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
29
+ if (path === "/post-purchase/v1/claims/claim-1") return { data: { type: "returns", status: "opened", players: [{ role: "respondent" }] } };
30
+ if (path.endsWith("/actions-history")) return { data: [] };
31
+ if (path.endsWith("/expected-resolutions")) return { data: [] };
32
+ if (path.endsWith("/messages")) return { data: [
33
+ { id: "m1", sender_role: "respondent", moderation_status: "approved", text: "untrusted" },
34
+ { id: "m2", sender_role: "complainant", moderation_status: "rejected", text: "untrusted" },
35
+ { id: "m3", sender_role: "respondent", moderation_status: "approved", text: "untrusted" }
36
+ ] };
37
+ if (path.endsWith("/actions")) return { data: [] };
38
+ if (path.includes("/post-purchase/v2/claims/") || path.includes("/charges/return-cost") || path.includes("/returns/")) throw new MercadoLibreApiError("not found", 404);
39
+ throw new Error(`unexpected ${path}`);
40
+ });
41
+ const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"], "full");
42
+ const claim = result.results[0].claim_context.claims[0];
43
+ expect(claim.message_summary).toEqual({ count: 3, by_role: { respondent: 2, complainant: 1 }, by_moderation_status: { approved: 2, rejected: 1 } });
44
+ expect(claim.messages).toHaveLength(3);
45
+ });
46
+ it("keeps standard summaries text-free and marks message failures as unknown", async () => {
47
+ let messagesAvailable = true;
48
+ getMock.mockImplementation(async (path, config) => {
49
+ if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: config?.params?.type === "returns" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === "returns" ? [{ id: "claim-1", resource_id: "order-1" }] : [] } };
50
+ if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
51
+ if (path === "/post-purchase/v1/claims/claim-1") return { data: { status: "opened" } };
52
+ if (path.endsWith("/actions-history") || path.endsWith("/expected-resolutions")) return { data: [] };
53
+ if (path.endsWith("/messages")) {
54
+ if (!messagesAvailable) throw new MercadoLibreApiError("unavailable", 503);
55
+ return { data: [{ id: "m1", sender_role: "respondent", moderation_status: "approved", text: "must not be returned in standard mode" }] };
56
+ }
57
+ if (path.includes("/post-purchase/v2/claims/")) throw new MercadoLibreApiError("not found", 404);
58
+ throw new Error(`unexpected ${path}`);
59
+ });
60
+ const standard = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
61
+ const standardClaim = standard.results[0].claim_context.claims[0];
62
+ expect(standardClaim.message_summary).toEqual({ count: 1, by_role: { respondent: 1 }, by_moderation_status: { approved: 1 } });
63
+ messagesAvailable = false;
64
+ const unavailable = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
65
+ const unavailableClaim = unavailable.results[0].claim_context.claims[0];
66
+ const issues = unavailable.results[0].claim_context.issues;
67
+ expect(issues).toContainEqual(expect.objectContaining({ code: "messages_unavailable" }));
68
+ expect(unavailableClaim.message_summary).toBeUndefined();
69
+ });
70
+ it("does not claim absence when a claims page is rate-limited", async () => {
71
+ getMock.mockImplementation(async (path, config) => {
72
+ if (path === "/post-purchase/v1/claims/search" && config?.params?.type === "returns" && config.params.offset === 0) {
73
+ return { data: { paging: { total: 51, limit: 50, offset: 0 }, data: [] } };
74
+ }
75
+ if (path === "/post-purchase/v1/claims/search" && config?.params?.type === "mediations") {
76
+ return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
77
+ }
78
+ if (path === "/post-purchase/v1/claims/search") throw new MercadoLibreApiError("rate limited", 429);
79
+ if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
80
+ throw new Error(`unexpected ${path}`);
81
+ });
82
+ const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
83
+ expect(result.results[0]).toMatchObject({
84
+ resolution: { kind: "order", status: "partial" },
85
+ claim_context: { status: "claim_status_unknown", completeness: "partial" }
86
+ });
87
+ const claimContext = result.results[0].claim_context;
88
+ expect(claimContext?.issues).toContainEqual(expect.objectContaining({ code: "claims_page_partial" }));
89
+ expect(result.summary).toMatchObject({ without_claims: 0, partial: 1, unavailable: 0 });
90
+ });
91
+ it("treats a failed first-page universe as unknown rather than without claims", async () => {
92
+ getMock.mockImplementation(async (path) => {
93
+ if (path === "/post-purchase/v1/claims/search") throw new MercadoLibreApiError("deadline", 429);
94
+ if (path === "/orders/order-1") return { data: { seller: { id: "seller-1" } } };
95
+ throw new Error(`unexpected ${path}`);
96
+ });
97
+ const result = await reconcileMercadoLibreClaimData("triplim", ["order-1"]);
98
+ expect(result.results[0]).toMatchObject({ resolution: { kind: "order", status: "partial" }, claim_context: { status: "claim_status_unknown" } });
99
+ expect(result.summary.without_claims).toBe(0);
100
+ });
101
+ it("returns unavailable when no pack member can be ownership-validated", async () => {
102
+ getMock.mockImplementation(async (path) => {
103
+ if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
104
+ if (path === "/orders/pack-1") throw new MercadoLibreApiError("not found", 404);
105
+ if (path === "/packs/pack-1") return { data: { orders: [{ id: "member-1" }, { id: "member-2" }] } };
106
+ if (path === "/orders/member-1" || path === "/orders/member-2") throw new MercadoLibreApiError("upstream", 503);
107
+ throw new Error(`unexpected ${path}`);
108
+ });
109
+ const result = await reconcileMercadoLibreClaimData("triplim", ["pack-1"]);
110
+ expect(result.results[0]).toMatchObject({ resolution: { kind: "pack", status: "unavailable" } });
111
+ expect(result.summary).toMatchObject({ unavailable: 1, partial: 0, without_claims: 0 });
112
+ });
113
+ it("withholds foreign orders and marks full projected context untrusted", async () => {
114
+ getMock.mockImplementation(async (path) => {
115
+ if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
116
+ if (path === "/orders/foreign-order") return { data: { seller: { id: "foreign-seller" } } };
117
+ if (path === "/orders/owned-order") return { data: { seller: { id: "seller-1" } } };
118
+ if (path === "/post-purchase/v1/claims/search") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };
119
+ throw new Error(`unexpected ${path}`);
120
+ });
121
+ const result = await reconcileMercadoLibreClaimData("triplim", ["foreign-order", "owned-order"], "full");
122
+ expect(result.results[0]).toMatchObject({ resolution: { status: "unavailable" } });
123
+ expect(result.results[1]).toMatchObject({ resolution: { status: "resolved" }, claim_context: { content_trust: "untrusted_user_generated" } });
124
+ expect(result.safety_notice).toContain("untrusted");
125
+ });
126
+ });
127
+ //# sourceMappingURL=mercadolibre-claim-reconciliation.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { MercadoLibreApiError, getMercadoLibreApiContext } from \"../mercadolibre-api.js\";\nimport { getClaimReconciliationDeadlineMs, reconcileMercadoLibreClaimData } from \"../mercadolibre-claim-reconciliation.js\";\nimport { getMcpToolDeadlineRemainingMs, runWithMcpToolDeadlineContext } from \"../../../config/mcp-tool-deadline-context.js\";\n\nconst { getMock } = vi.hoisted(() => ({ getMock: vi.fn() }));\n\nvi.mock(\"../mercadolibre-api.js\", async () => {\n const actual = await vi.importActual<typeof import(\"../mercadolibre-api.js\")>(\"../mercadolibre-api.js\");\n return { ...actual, getMercadoLibreApiContext: vi.fn() };\n});\n\ndescribe(\"reconcileMercadoLibreClaimData\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({ api: { get: getMock }, sellerId: \"seller-1\", accessToken: \"token\" } as never);\n });\n\n it(\"uses the shorter MCP caller budget with a bounded safety margin\", async () => {\n const signal = new AbortController().signal;\n await runWithMcpToolDeadlineContext(signal, async () => {\n expect(getMcpToolDeadlineRemainingMs(10_000)).toBe(1_000);\n expect(getClaimReconciliationDeadlineMs(getMcpToolDeadlineRemainingMs(10_000)!)).toBe(900);\n }, 11_000);\n\n expect(getClaimReconciliationDeadlineMs(300_000)).toBe(290_000);\n });\n\n it(\"derives full message summaries from the projected messages\", async () => {\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string } }) => {\n if (path === \"/post-purchase/v1/claims/search\") {\n return { data: { paging: { total: config?.params?.type === \"returns\" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === \"returns\" ? [{ id: \"claim-1\", resource_id: \"order-1\" }] : [] } };\n }\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/claim-1\") return { data: { type: \"returns\", status: \"opened\", players: [{ role: \"respondent\" }] } };\n if (path.endsWith(\"/actions-history\")) return { data: [] };\n if (path.endsWith(\"/expected-resolutions\")) return { data: [] };\n if (path.endsWith(\"/messages\")) return { data: [\n { id: \"m1\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"untrusted\" },\n { id: \"m2\", sender_role: \"complainant\", moderation_status: \"rejected\", text: \"untrusted\" },\n { id: \"m3\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"untrusted\" },\n ] };\n if (path.endsWith(\"/actions\")) return { data: [] };\n if (path.includes(\"/post-purchase/v2/claims/\") || path.includes(\"/charges/return-cost\") || path.includes(\"/returns/\")) throw new MercadoLibreApiError(\"not found\", 404);\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"], \"full\");\n const claim = (result.results[0] as { claim_context: { claims: Array<{ message_summary: unknown; messages: unknown[] }> } }).claim_context.claims[0];\n\n expect(claim.message_summary).toEqual({ count: 3, by_role: { respondent: 2, complainant: 1 }, by_moderation_status: { approved: 2, rejected: 1 } });\n expect(claim.messages).toHaveLength(3);\n });\n\n it(\"keeps standard summaries text-free and marks message failures as unknown\", async () => {\n let messagesAvailable = true;\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string } }) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: config?.params?.type === \"returns\" ? 1 : 0, limit: 50, offset: 0 }, data: config?.params?.type === \"returns\" ? [{ id: \"claim-1\", resource_id: \"order-1\" }] : [] } };\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/claim-1\") return { data: { status: \"opened\" } };\n if (path.endsWith(\"/actions-history\") || path.endsWith(\"/expected-resolutions\")) return { data: [] };\n if (path.endsWith(\"/messages\")) {\n if (!messagesAvailable) throw new MercadoLibreApiError(\"unavailable\", 503);\n return { data: [{ id: \"m1\", sender_role: \"respondent\", moderation_status: \"approved\", text: \"must not be returned in standard mode\" }] };\n }\n if (path.includes(\"/post-purchase/v2/claims/\")) throw new MercadoLibreApiError(\"not found\", 404);\n throw new Error(`unexpected ${path}`);\n });\n\n const standard = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n const standardClaim = (standard.results[0] as { claim_context: { claims: Array<{ message_summary: unknown }> } }).claim_context.claims[0];\n expect(standardClaim.message_summary).toEqual({ count: 1, by_role: { respondent: 1 }, by_moderation_status: { approved: 1 } });\n\n messagesAvailable = false;\n const unavailable = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n const unavailableClaim = (unavailable.results[0] as { claim_context: { claims: Array<{ message_summary?: unknown; issues: Array<{ code: string }> }> } }).claim_context.claims[0];\n\n const issues = (unavailable.results[0] as { claim_context: { issues: Array<{ code: string }> } }).claim_context.issues;\n expect(issues).toContainEqual(expect.objectContaining({ code: \"messages_unavailable\" }));\n expect(unavailableClaim.message_summary).toBeUndefined();\n });\n\n it(\"does not claim absence when a claims page is rate-limited\", async () => {\n getMock.mockImplementation(async (path: string, config?: { params?: { type?: string; offset?: number } }) => {\n if (path === \"/post-purchase/v1/claims/search\" && config?.params?.type === \"returns\" && config.params.offset === 0) {\n return { data: { paging: { total: 51, limit: 50, offset: 0 }, data: [] } };\n }\n if (path === \"/post-purchase/v1/claims/search\" && config?.params?.type === \"mediations\") {\n return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n }\n if (path === \"/post-purchase/v1/claims/search\") throw new MercadoLibreApiError(\"rate limited\", 429);\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n\n expect(result.results[0]).toMatchObject({\n resolution: { kind: \"order\", status: \"partial\" },\n claim_context: { status: \"claim_status_unknown\", completeness: \"partial\" },\n });\n const claimContext = (result.results[0] as { claim_context?: { issues?: unknown[] } }).claim_context;\n expect(claimContext?.issues).toContainEqual(expect.objectContaining({ code: \"claims_page_partial\" }));\n expect(result.summary).toMatchObject({ without_claims: 0, partial: 1, unavailable: 0 });\n });\n\n it(\"treats a failed first-page universe as unknown rather than without claims\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") throw new MercadoLibreApiError(\"deadline\", 429);\n if (path === \"/orders/order-1\") return { data: { seller: { id: \"seller-1\" } } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"order-1\"]);\n\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"order\", status: \"partial\" }, claim_context: { status: \"claim_status_unknown\" } });\n expect(result.summary.without_claims).toBe(0);\n });\n\n it(\"returns unavailable when no pack member can be ownership-validated\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n if (path === \"/orders/pack-1\") throw new MercadoLibreApiError(\"not found\", 404);\n if (path === \"/packs/pack-1\") return { data: { orders: [{ id: \"member-1\" }, { id: \"member-2\" }] } };\n if (path === \"/orders/member-1\" || path === \"/orders/member-2\") throw new MercadoLibreApiError(\"upstream\", 503);\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"pack-1\"]);\n\n expect(result.results[0]).toMatchObject({ resolution: { kind: \"pack\", status: \"unavailable\" } });\n expect(result.summary).toMatchObject({ unavailable: 1, partial: 0, without_claims: 0 });\n });\n\n it(\"withholds foreign orders and marks full projected context untrusted\", async () => {\n getMock.mockImplementation(async (path: string) => {\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n if (path === \"/orders/foreign-order\") return { data: { seller: { id: \"foreign-seller\" } } };\n if (path === \"/orders/owned-order\") return { data: { seller: { id: \"seller-1\" } } };\n if (path === \"/post-purchase/v1/claims/search\") return { data: { paging: { total: 0, limit: 50, offset: 0 }, data: [] } };\n throw new Error(`unexpected ${path}`);\n });\n\n const result = await reconcileMercadoLibreClaimData(\"triplim\", [\"foreign-order\", \"owned-order\"], \"full\");\n\n expect(result.results[0]).toMatchObject({ resolution: { status: \"unavailable\" } });\n expect(result.results[1]).toMatchObject({ resolution: { status: \"resolved\" }, claim_context: { content_trust: \"untrusted_user_generated\" } });\n expect(result.safety_notice).toContain(\"untrusted\");\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,103 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { getMercadoLibreApiContext, runMercadoLibreBatch } from "../mercadolibre-api.js";
3
+ import {
4
+ getMercadoLibreUserProduct,
5
+ getMercadoLibreUserProductBundles,
6
+ getMercadoLibreUserProductBundlesBatch,
7
+ getMercadoLibreUserProductsBatch,
8
+ resolveMercadoLibreUserProductsFromItems
9
+ } from "../mercadolibre-kits.js";
10
+ import { getMercadoLibreItemDetailsBatch } from "../mercadolibre-items.js";
11
+ vi.mock("../mercadolibre-api.js", () => ({
12
+ getMercadoLibreApiContext: vi.fn(),
13
+ runMercadoLibreBatch: vi.fn()
14
+ }));
15
+ vi.mock("../mercadolibre-items.js", () => ({
16
+ getMercadoLibreItemDetailsBatch: vi.fn()
17
+ }));
18
+ describe("mercadolibre-kits service", () => {
19
+ const getMock = vi.fn();
20
+ beforeEach(() => {
21
+ vi.clearAllMocks();
22
+ vi.mocked(getMercadoLibreApiContext).mockResolvedValue({
23
+ api: { get: getMock },
24
+ sellerId: "seller-from-profile",
25
+ accessToken: "token"
26
+ });
27
+ });
28
+ it("fetches user product bundle context from the official user-products endpoint", async () => {
29
+ getMock.mockResolvedValueOnce({ data: { id: "MLAU1", tags: ["bundle"], bundle: { type: "kit" } } });
30
+ const result = await getMercadoLibreUserProduct("profile-1", "MLAU1");
31
+ expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1");
32
+ expect(result).toEqual({ id: "MLAU1", tags: ["bundle"], bundle: { type: "kit" } });
33
+ });
34
+ it("fetches bundle memberships from the official bundles endpoint", async () => {
35
+ getMock.mockResolvedValueOnce({ data: { user_product_id: "MLAU2", bundles: ["MLAU9"] } });
36
+ const result = await getMercadoLibreUserProductBundles("profile-1", "MLAU2");
37
+ expect(getMock).toHaveBeenCalledWith("/user-products/MLAU2/bundles");
38
+ expect(result).toEqual({ user_product_id: "MLAU2", bundles: ["MLAU9"] });
39
+ });
40
+ it("delegates user product batch fetching through the shared batch runner", async () => {
41
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
42
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
43
+ failed: []
44
+ }));
45
+ getMock.mockResolvedValueOnce({ data: { id: "MLAU1" } });
46
+ const result = await getMercadoLibreUserProductsBatch("profile-1", ["MLAU1"], { maxRetries: 1 });
47
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["MLAU1"], expect.any(Function), { maxRetries: 1 });
48
+ expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1");
49
+ expect(result).toEqual({ successful: [{ id: "MLAU1", document: { id: "MLAU1" } }], failed: [] });
50
+ });
51
+ it("resolves user product ids from item multiget responses", async () => {
52
+ vi.mocked(getMercadoLibreItemDetailsBatch).mockResolvedValue([
53
+ { id: "MLA1", user_product_id: "MLAU1", title: "Kit" },
54
+ { id: "MLA2", title: "Component" }
55
+ ]);
56
+ const result = await resolveMercadoLibreUserProductsFromItems("profile-1", ["MLA1", "MLA2"]);
57
+ expect(getMercadoLibreItemDetailsBatch).toHaveBeenCalledWith("profile-1", ["MLA1", "MLA2"], [
58
+ "id",
59
+ "user_product_id",
60
+ "title",
61
+ "catalog_product_id",
62
+ "domain_id",
63
+ "family_id"
64
+ ]);
65
+ expect(result).toEqual([
66
+ {
67
+ itemId: "MLA1",
68
+ userProductId: "MLAU1",
69
+ title: "Kit",
70
+ catalogProductId: "",
71
+ domainId: "",
72
+ familyId: ""
73
+ },
74
+ {
75
+ itemId: "MLA2",
76
+ userProductId: "",
77
+ title: "Component",
78
+ catalogProductId: "",
79
+ domainId: "",
80
+ familyId: ""
81
+ }
82
+ ]);
83
+ });
84
+ it("delegates bundle membership batch fetching through the shared batch runner", async () => {
85
+ vi.mocked(runMercadoLibreBatch).mockImplementation(async (ids, fetcher) => ({
86
+ successful: [{ id: ids[0], document: await fetcher(ids[0]) }],
87
+ failed: []
88
+ }));
89
+ getMock.mockResolvedValueOnce({ data: { user_product_id: "MLAU1", bundles: ["MLAU2"] } });
90
+ const result = await getMercadoLibreUserProductBundlesBatch("profile-1", ["MLAU1"], {
91
+ maxConcurrency: 2
92
+ });
93
+ expect(runMercadoLibreBatch).toHaveBeenCalledWith(["MLAU1"], expect.any(Function), {
94
+ maxConcurrency: 2
95
+ });
96
+ expect(getMock).toHaveBeenCalledWith("/user-products/MLAU1/bundles");
97
+ expect(result).toEqual({
98
+ successful: [{ id: "MLAU1", document: { user_product_id: "MLAU1", bundles: ["MLAU2"] } }],
99
+ failed: []
100
+ });
101
+ });
102
+ });
103
+ //# sourceMappingURL=mercadolibre-kits.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/mercadolibre/__tests__/mercadolibre-kits.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { getMercadoLibreApiContext, runMercadoLibreBatch } from \"../mercadolibre-api.js\";\nimport {\n getMercadoLibreUserProduct,\n getMercadoLibreUserProductBundles,\n getMercadoLibreUserProductBundlesBatch,\n getMercadoLibreUserProductsBatch,\n resolveMercadoLibreUserProductsFromItems,\n} from \"../mercadolibre-kits.js\";\nimport { getMercadoLibreItemDetailsBatch } from \"../mercadolibre-items.js\";\n\nvi.mock(\"../mercadolibre-api.js\", () => ({\n getMercadoLibreApiContext: vi.fn(),\n runMercadoLibreBatch: vi.fn(),\n}));\n\nvi.mock(\"../mercadolibre-items.js\", () => ({\n getMercadoLibreItemDetailsBatch: vi.fn(),\n}));\n\ndescribe(\"mercadolibre-kits service\", () => {\n const getMock = vi.fn();\n\n beforeEach(() => {\n vi.clearAllMocks();\n vi.mocked(getMercadoLibreApiContext).mockResolvedValue({\n api: { get: getMock },\n sellerId: \"seller-from-profile\",\n accessToken: \"token\",\n } as never);\n });\n\n it(\"fetches user product bundle context from the official user-products endpoint\", async () => {\n getMock.mockResolvedValueOnce({ data: { id: \"MLAU1\", tags: [\"bundle\"], bundle: { type: \"kit\" } } });\n\n const result = await getMercadoLibreUserProduct(\"profile-1\", \"MLAU1\");\n\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1\");\n expect(result).toEqual({ id: \"MLAU1\", tags: [\"bundle\"], bundle: { type: \"kit\" } });\n });\n\n it(\"fetches bundle memberships from the official bundles endpoint\", async () => {\n getMock.mockResolvedValueOnce({ data: { user_product_id: \"MLAU2\", bundles: [\"MLAU9\"] } });\n\n const result = await getMercadoLibreUserProductBundles(\"profile-1\", \"MLAU2\");\n\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU2/bundles\");\n expect(result).toEqual({ user_product_id: \"MLAU2\", bundles: [\"MLAU9\"] });\n });\n\n it(\"delegates user product batch fetching 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: \"MLAU1\" } });\n\n const result = await getMercadoLibreUserProductsBatch(\"profile-1\", [\"MLAU1\"], { maxRetries: 1 });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"MLAU1\"], expect.any(Function), { maxRetries: 1 });\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1\");\n expect(result).toEqual({ successful: [{ id: \"MLAU1\", document: { id: \"MLAU1\" } }], failed: [] });\n });\n\n it(\"resolves user product ids from item multiget responses\", async () => {\n vi.mocked(getMercadoLibreItemDetailsBatch).mockResolvedValue([\n { id: \"MLA1\", user_product_id: \"MLAU1\", title: \"Kit\" },\n { id: \"MLA2\", title: \"Component\" },\n ] as never);\n\n const result = await resolveMercadoLibreUserProductsFromItems(\"profile-1\", [\"MLA1\", \"MLA2\"]);\n\n expect(getMercadoLibreItemDetailsBatch).toHaveBeenCalledWith(\"profile-1\", [\"MLA1\", \"MLA2\"], [\n \"id\",\n \"user_product_id\",\n \"title\",\n \"catalog_product_id\",\n \"domain_id\",\n \"family_id\",\n ]);\n expect(result).toEqual([\n {\n itemId: \"MLA1\",\n userProductId: \"MLAU1\",\n title: \"Kit\",\n catalogProductId: \"\",\n domainId: \"\",\n familyId: \"\",\n },\n {\n itemId: \"MLA2\",\n userProductId: \"\",\n title: \"Component\",\n catalogProductId: \"\",\n domainId: \"\",\n familyId: \"\",\n },\n ]);\n });\n\n it(\"delegates bundle membership batch fetching 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: { user_product_id: \"MLAU1\", bundles: [\"MLAU2\"] } });\n\n const result = await getMercadoLibreUserProductBundlesBatch(\"profile-1\", [\"MLAU1\"], {\n maxConcurrency: 2,\n });\n\n expect(runMercadoLibreBatch).toHaveBeenCalledWith([\"MLAU1\"], expect.any(Function), {\n maxConcurrency: 2,\n });\n expect(getMock).toHaveBeenCalledWith(\"/user-products/MLAU1/bundles\");\n expect(result).toEqual({\n successful: [{ id: \"MLAU1\", document: { user_product_id: \"MLAU1\", bundles: [\"MLAU2\"] } }],\n failed: [],\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }