@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,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../tests/vtex/vtex-catalog-write-tools.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { z } from \"zod\";\n\nimport { associateSpecificationHandler } from \"../../src/tools/vtex/associate-specification.js\";\nimport { createBrandHandler } from \"../../src/tools/vtex/create-brand.js\";\nimport { createCategoryHandler } from \"../../src/tools/vtex/create-category.js\";\nimport { createProductHandler } from \"../../src/tools/vtex/create-product.js\";\nimport { createSkuHandler } from \"../../src/tools/vtex/create-sku.js\";\nimport {\n\tcreateSpecificationHandler,\n\tcreateSpecificationSchema,\n} from \"../../src/tools/vtex/create-specification.js\";\nimport { createSpecificationValueHandler } from \"../../src/tools/vtex/create-specification-value.js\";\nimport {\n\tassociateProductSpecification,\n\tassociateSkuSpecification,\n\tcreateBrand,\n\tcreateCategory,\n\tcreateProduct,\n\tcreateSku,\n\tcreateSkuEan,\n\tcreateSpecification,\n\tcreateSpecificationValue,\n} from \"../../src/services/vtex/vtex-catalog-write.js\";\nimport {\n\tbuildWriteSuccessResponse,\n\thandleVtexWriteError,\n\tresolveVtexWriteProfile,\n} from \"../../src/tools/vtex/write-helpers.js\";\n\nvi.mock(\"../../src/tools/vtex/write-helpers.js\", () => ({\n\tvtexProfileIdSchemaField: z.string().optional(),\n\tconfirmationSchemaField: z.boolean().optional(),\n\tconfirmationNoteSchemaField: z.string().optional(),\n\tresolveVtexWriteProfile: vi.fn(),\n\tbuildWriteSuccessResponse: vi.fn((params: unknown) => ({\n\t\tkind: \"success\",\n\t\tparams,\n\t})),\n\thandleVtexWriteError: vi.fn((err: unknown, fallback: string) => ({\n\t\tkind: \"error\",\n\t\tfallback,\n\t\terr,\n\t})),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-catalog-write.js\", () => ({\n\tcreateBrand: vi.fn(),\n\tcreateCategory: vi.fn(),\n\tcreateProduct: vi.fn(),\n\tcreateSku: vi.fn(),\n\tcreateSkuEan: vi.fn(),\n\tcreateSpecification: vi.fn(),\n\tcreateSpecificationValue: vi.fn(),\n\tassociateProductSpecification: vi.fn(),\n\tassociateSkuSpecification: vi.fn(),\n}));\n\ndescribe(\"VTEX catalog/specification write tools\", () => {\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\tok: true,\n\t\t\tvalue: { profileId: \"profile-1\" },\n\t\t});\n\t});\n\n\tdescribe(\"createBrandHandler\", () => {\n\t\tit(\"applies default payload values before creating a brand\", async () => {\n\t\t\tconst createdBrand = { Id: 10, Name: \"Nike\", Active: true };\n\t\t\tvi.mocked(createBrand).mockResolvedValue(createdBrand as never);\n\n\t\t\tconst result = await createBrandHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tid: 10,\n\t\t\t\tname: \"Nike\",\n\t\t\t\tlinkId: \"nike\",\n\t\t\t});\n\n\t\t\texpect(createBrand).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tId: 10,\n\t\t\t\tName: \"Nike\",\n\t\t\t\tText: \"Nike\",\n\t\t\t\tKeywords: \"\",\n\t\t\t\tSiteTitle: \"Nike\",\n\t\t\t\tActive: true,\n\t\t\t\tMenuHome: false,\n\t\t\t\tLinkId: \"nike\",\n\t\t\t\tScore: null,\n\t\t\t\tAdWordsRemarketingCode: null,\n\t\t\t\tLomadeeCampaignCode: null,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_brand\",\n\t\t\t\tresourceId: \"10\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Brand created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdBrand,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_brand\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createBrandHandler({ id: 10, name: \"Nike\" });\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createBrand).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createBrand).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createBrandHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tid: 10,\n\t\t\t\tname: \"Nike\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create brand in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create brand in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createCategoryHandler\", () => {\n\t\tit(\"forwards the expected VTEX category payload with defaults\", async () => {\n\t\t\tconst createdCategory = { Id: 20, Name: \"Shoes\" };\n\t\t\tvi.mocked(createCategory).mockResolvedValue(createdCategory as never);\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tfatherCategoryId: null,\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(createCategory).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tId: undefined,\n\t\t\t\tName: \"Shoes\",\n\t\t\t\tKeywords: \"\",\n\t\t\t\tTitle: \"Running Shoes\",\n\t\t\t\tDescription: \"Category description\",\n\t\t\t\tAdWordsRemarketingCode: null,\n\t\t\t\tLomadeeCampaignCode: null,\n\t\t\t\tFatherCategoryId: null,\n\t\t\t\tGlobalCategoryId: 123,\n\t\t\t\tShowInStoreFront: true,\n\t\t\t\tIsActive: true,\n\t\t\t\tActiveStoreFrontLink: true,\n\t\t\t\tShowBrandFilter: true,\n\t\t\t\tScore: null,\n\t\t\t\tStockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_category\",\n\t\t\t\tresourceId: \"20\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Category created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdCategory,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_category\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createCategory).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createCategory).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createCategoryHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Shoes\",\n\t\t\t\ttitle: \"Running Shoes\",\n\t\t\t\tdescription: \"Category description\",\n\t\t\t\tglobalCategoryId: 123,\n\t\t\t\tstockKeepingUnitSelectionMode: \"SPECIFICATION\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create category in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create category in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createProductHandler\", () => {\n\t\tit(\"forwards the expected VTEX product payload and builds a success response\", async () => {\n\t\t\tconst createdProduct = { Id: 55, Name: \"Running Shoe\" };\n\t\t\tvi.mocked(createProduct).mockResolvedValue(createdProduct as never);\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryPath: \"Mens/Shoes/Running\",\n\t\t\t\tbrandName: \"Acme\",\n\t\t\t\tdepartmentId: 7,\n\t\t\t\trefId: \"RUN-001\",\n\t\t\t\ttitle: \"Running Shoe\",\n\t\t\t\tdescription: \"Main description\",\n\t\t\t\tdescriptionShort: \"Short description\",\n\t\t\t\tlinkId: \"running-shoe\",\n\t\t\t\treleaseDate: \"2026-06-01T00:00:00Z\",\n\t\t\t\tkeyWords: \"running,shoe\",\n\t\t\t\tisVisible: true,\n\t\t\t\tisActive: false,\n\t\t\t\ttaxCode: \"TX-1\",\n\t\t\t\tmetaTagDescription: \"Meta description\",\n\t\t\t\tsupplierId: 91,\n\t\t\t\tshowWithoutStock: true,\n\t\t\t\tscore: 12,\n\t\t\t});\n\n\t\t\texpect(createProduct).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tName: \"Running Shoe\",\n\t\t\t\tCategoryPath: \"Mens/Shoes/Running\",\n\t\t\t\tBrandName: \"Acme\",\n\t\t\t\tDepartmentId: 7,\n\t\t\t\tRefId: \"RUN-001\",\n\t\t\t\tTitle: \"Running Shoe\",\n\t\t\t\tDescription: \"Main description\",\n\t\t\t\tDescriptionShort: \"Short description\",\n\t\t\t\tLinkId: \"running-shoe\",\n\t\t\t\tReleaseDate: \"2026-06-01T00:00:00Z\",\n\t\t\t\tKeyWords: \"running,shoe\",\n\t\t\t\tIsVisible: true,\n\t\t\t\tIsActive: false,\n\t\t\t\tTaxCode: \"TX-1\",\n\t\t\t\tMetaTagDescription: \"Meta description\",\n\t\t\t\tSupplierId: 91,\n\t\t\t\tShowWithoutStock: true,\n\t\t\t\tScore: 12,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_product\",\n\t\t\t\tresourceId: \"55\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Product created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdProduct,\n\t\t\t\tdetails: {\n\t\t\t\t\tproduct_id: \"55\",\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_product\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryId: 10,\n\t\t\t\tbrandId: 20,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createProduct).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createProduct).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createProductHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tname: \"Running Shoe\",\n\t\t\t\tcategoryId: 10,\n\t\t\t\tbrandId: 20,\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create product in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create product in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSkuHandler\", () => {\n\t\tconst skuPayload = {\n\t\t\tprofileId: \"custom\",\n\t\t\tproductId: 99,\n\t\t\tname: \"Running Shoe / Black / 42\",\n\t\t\trefId: \"RUN-001-42\",\n\t\t\tpackagedHeight: 10,\n\t\t\tpackagedLength: 20,\n\t\t\tpackagedWidth: 30,\n\t\t\tpackagedWeightKg: 1.5,\n\t\t\theight: 9,\n\t\t\tlength: 19,\n\t\t\twidth: 29,\n\t\t\tweightKg: 1.25,\n\t\t\tmeasurementUnit: \"un\",\n\t\t\tunitMultiplier: 1,\n\t\t\tmanufacturerCode: \"ACME-42\",\n\t\t\tcommercialConditionId: 12,\n\t\t};\n\n\t\tit(\"forwards the expected VTEX SKU payload with default flags\", async () => {\n\t\t\tconst createdSku = { Id: 77, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tconst result = await createSkuHandler(skuPayload);\n\n\t\t\texpect(createSku).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tProductId: 99,\n\t\t\t\tName: \"Running Shoe / Black / 42\",\n\t\t\t\tRefId: \"RUN-001-42\",\n\t\t\t\tPackagedHeight: 10,\n\t\t\t\tPackagedLength: 20,\n\t\t\t\tPackagedWidth: 30,\n\t\t\t\tPackagedWeightKg: 1.5,\n\t\t\t\tActivateIfPossible: true,\n\t\t\t\tIsActive: false,\n\t\t\t\tHeight: 9,\n\t\t\t\tLength: 19,\n\t\t\t\tWidth: 29,\n\t\t\t\tWeightKg: 1.25,\n\t\t\t\tMeasurementUnit: \"un\",\n\t\t\t\tUnitMultiplier: 1,\n\t\t\t\tManufacturerCode: \"ACME-42\",\n\t\t\t\tCommercialConditionId: 12,\n\t\t\t});\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_sku\",\n\t\t\t\tresourceId: \"77\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"SKU created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdSku,\n\t\t\t\tdetails: {\n\t\t\t\t\tproduct_id: 99,\n\t\t\t\t\tsku_id: \"77\",\n\t\t\t\t},\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_sku\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"creates the sku then attaches the EAN when provided\", async () => {\n\t\t\tconst createdSku = { Id: 78, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tawait createSkuHandler({\n\t\t\t\t...skuPayload,\n\t\t\t\tean: \" 7791234567890 \",\n\t\t\t\tisActive: true,\n\t\t\t\tactivateIfPossible: false,\n\t\t\t});\n\n\t\t\texpect(createSku).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tProductId: 99,\n\t\t\t\tName: \"Running Shoe / Black / 42\",\n\t\t\t\tRefId: \"RUN-001-42\",\n\t\t\t\tPackagedHeight: 10,\n\t\t\t\tPackagedLength: 20,\n\t\t\t\tPackagedWidth: 30,\n\t\t\t\tPackagedWeightKg: 1.5,\n\t\t\t\tActivateIfPossible: false,\n\t\t\t\tIsActive: true,\n\t\t\t\tHeight: 9,\n\t\t\t\tLength: 19,\n\t\t\t\tWidth: 29,\n\t\t\t\tWeightKg: 1.25,\n\t\t\t\tMeasurementUnit: \"un\",\n\t\t\t\tUnitMultiplier: 1,\n\t\t\t\tManufacturerCode: \"ACME-42\",\n\t\t\t\tCommercialConditionId: 12,\n\t\t\t});\n\t\t\texpect(createSkuEan).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"78\",\n\t\t\t\t\"7791234567890\",\n\t\t\t);\n\t\t\texpect(\n\t\t\t\tvi.mocked(createSku).mock.invocationCallOrder[0],\n\t\t\t).toBeLessThan(vi.mocked(createSkuEan).mock.invocationCallOrder[0]);\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tafter: expect.objectContaining({ Eans: [\"7791234567890\"] }),\n\t\t\t\t}),\n\t\t\t);\n\t\t});\n\n\t\tit(\"skips EAN attachment when EAN is missing or blank\", async () => {\n\t\t\tconst createdSku = { Id: 79, Name: skuPayload.name };\n\t\t\tvi.mocked(createSku).mockResolvedValue(createdSku as never);\n\n\t\t\tawait createSkuHandler({\n\t\t\t\t...skuPayload,\n\t\t\t\tean: \" \",\n\t\t\t});\n\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSkuHandler({\n\t\t\t\tproductId: 99,\n\t\t\t\tname: \"Running Shoe / Black / 42\",\n\t\t\t\trefId: \"RUN-001-42\",\n\t\t\t\tpackagedHeight: 10,\n\t\t\t\tpackagedLength: 20,\n\t\t\t\tpackagedWidth: 30,\n\t\t\t\tpackagedWeightKg: 1.5,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSku).not.toHaveBeenCalled();\n\t\t\texpect(createSkuEan).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSku).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSkuHandler(skuPayload);\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create SKU in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create SKU in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSpecificationHandler\", () => {\n\t\tit(\"schema converts fieldTypeId from string to number\", () => {\n\t\t\tconst parsed = createSpecificationSchema.parse({\n\t\t\t\tfieldTypeId: \"4\",\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(parsed.fieldTypeId).toBe(4);\n\t\t});\n\n\t\tit(\"fills default fields before creating a specification\", async () => {\n\t\t\tconst createdSpecification = { Id: 30, Name: \"Color\" };\n\t\t\tvi.mocked(createSpecification).mockResolvedValue(\n\t\t\t\tcreatedSpecification as never,\n\t\t\t);\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(createSpecification).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tFieldTypeId: 4,\n\t\t\t\tFieldGroupId: 12,\n\t\t\t\tName: \"Color\",\n\t\t\t\tCategoryId: undefined,\n\t\t\t\tDescription: null,\n\t\t\t\tPosition: 0,\n\t\t\t\tIsFilter: false,\n\t\t\t\tIsRequired: false,\n\t\t\t\tIsOnProductDetails: true,\n\t\t\t\tIsStockKeepingUnit: false,\n\t\t\t\tIsWizard: false,\n\t\t\t\tIsActive: true,\n\t\t\t\tIsTopMenuLinkActive: false,\n\t\t\t\tIsSideMenuLinkActive: false,\n\t\t\t\tDefaultValue: \"\",\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_specification\",\n\t\t\t\tresourceId: \"30\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdSpecification,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({ operation: \"create_specification\" }),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSpecification).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldTypeId: 4,\n\t\t\t\tfieldGroupId: 12,\n\t\t\t\tname: \"Color\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create specification in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create specification in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"createSpecificationValueHandler\", () => {\n\t\tit(\"fills default fields before creating a specification value\", async () => {\n\t\t\tconst createdValue = { FieldValueId: 40, Name: \"Red\" };\n\t\t\tvi.mocked(createSpecificationValue).mockResolvedValue(\n\t\t\t\tcreatedValue as never,\n\t\t\t);\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(createSpecificationValue).toHaveBeenCalledWith(\"profile-1\", {\n\t\t\t\tFieldId: 30,\n\t\t\t\tName: \"Red\",\n\t\t\t\tIsActive: true,\n\t\t\t\tPosition: 0,\n\t\t\t\tText: null,\n\t\t\t});\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"create_specification_value\",\n\t\t\t\tresourceId: \"40\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification value created successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: createdValue,\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({\n\t\t\t\t\toperation: \"create_specification_value\",\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(createSpecificationValue).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(createSpecificationValue).mockRejectedValue(new Error(\"boom\"));\n\n\t\t\tconst result = await createSpecificationValueHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tname: \"Red\",\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to create specification value in VTEX\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to create specification value in VTEX\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"associateSpecificationHandler\", () => {\n\t\tit(\"routes product associations to the product service and shapes optional payload fields\", async () => {\n\t\t\tconst association = { success: true, id: \"prod-1\" };\n\t\t\tvi.mocked(associateProductSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t\tfieldValueId: 40,\n\t\t\t});\n\n\t\t\texpect(associateProductSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"prod-1\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 30,\n\t\t\t\t\tFieldValueId: 40,\n\t\t\t\t},\n\t\t\t);\n\t\t\texpect(associateSkuSpecification).not.toHaveBeenCalled();\n\t\t\texpect(buildWriteSuccessResponse).toHaveBeenCalledWith({\n\t\t\t\tprofileId: \"profile-1\",\n\t\t\t\toperation: \"associate_specification\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\triskLevel: \"low\",\n\t\t\t\tmessage: \"Specification associated successfully.\",\n\t\t\t\tbefore: null,\n\t\t\t\tafter: association,\n\t\t\t\tdetails: { entity_type: \"product\" },\n\t\t\t});\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"success\",\n\t\t\t\tparams: expect.objectContaining({\n\t\t\t\t\toperation: \"associate_specification\",\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\n\t\tit(\"routes sku associations to the sku service and keeps free-text payloads\", async () => {\n\t\t\tconst association = { success: true, id: \"sku-1\" };\n\t\t\tvi.mocked(associateSkuSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tawait associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"sku\",\n\t\t\t\tresourceId: \"sku-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t\ttext: \"Blue\",\n\t\t\t});\n\n\t\t\texpect(associateSkuSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"sku-1\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 30,\n\t\t\t\t\tText: \"Blue\",\n\t\t\t\t},\n\t\t\t);\n\t\t\texpect(associateProductSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"keeps both FieldValueId and Text when both are provided\", async () => {\n\t\t\tconst association = { success: true, id: \"sku-2\" };\n\t\t\tvi.mocked(associateSkuSpecification).mockResolvedValue(\n\t\t\t\tassociation as never,\n\t\t\t);\n\n\t\t\tawait associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"sku\",\n\t\t\t\tresourceId: \"sku-2\",\n\t\t\t\tfieldId: 31,\n\t\t\t\tfieldValueId: 41,\n\t\t\t\ttext: \"Navy\",\n\t\t\t});\n\n\t\t\texpect(associateSkuSpecification).toHaveBeenCalledWith(\n\t\t\t\t\"profile-1\",\n\t\t\t\t\"sku-2\",\n\t\t\t\t{\n\t\t\t\t\tFieldId: 31,\n\t\t\t\t\tFieldValueId: 41,\n\t\t\t\t\tText: \"Navy\",\n\t\t\t\t},\n\t\t\t);\n\t\t});\n\n\t\tit(\"returns profile selection payload when profile resolution fails\", async () => {\n\t\t\tvi.mocked(resolveVtexWriteProfile).mockResolvedValue({\n\t\t\t\tok: false,\n\t\t\t\tresponse: { selection: true },\n\t\t\t} as never);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t});\n\n\t\t\texpect(result).toEqual({ selection: true });\n\t\t\texpect(associateProductSpecification).not.toHaveBeenCalled();\n\t\t\texpect(associateSkuSpecification).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"maps service errors through handleVtexWriteError\", async () => {\n\t\t\tvi.mocked(associateProductSpecification).mockRejectedValue(\n\t\t\t\tnew Error(\"boom\"),\n\t\t\t);\n\n\t\t\tconst result = await associateSpecificationHandler({\n\t\t\t\tprofileId: \"custom\",\n\t\t\t\tentityType: \"product\",\n\t\t\t\tresourceId: \"prod-1\",\n\t\t\t\tfieldId: 30,\n\t\t\t});\n\n\t\t\texpect(handleVtexWriteError).toHaveBeenCalledWith(\n\t\t\t\texpect.any(Error),\n\t\t\t\t\"Failed to associate specification to product prod-1\",\n\t\t\t);\n\t\t\texpect(result).toEqual({\n\t\t\t\tkind: \"error\",\n\t\t\t\tfallback: \"Failed to associate specification to product prod-1\",\n\t\t\t\terr: expect.any(Error),\n\t\t\t});\n\t\t});\n\t});\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,51 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ getProductOffers,
4
+ getSkuOffers
5
+ } from "../../src/services/vtex/vtex-catalog.js";
6
+ import { getVtexApiClients } from "../../src/services/vtex/vtex-api.js";
7
+ vi.mock("../../src/services/vtex/vtex-api.js", () => ({
8
+ getVtexApiClients: vi.fn()
9
+ }));
10
+ describe("vtex-catalog service", () => {
11
+ const catalogGet = vi.fn();
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ vi.mocked(getVtexApiClients).mockResolvedValue({
15
+ config: {
16
+ accountName: "test-account",
17
+ apiKey: "key",
18
+ apiToken: "token",
19
+ baseUrl: "https://example.vtex.com",
20
+ pricingBaseUrl: "https://pricing.example.vtex.com"
21
+ },
22
+ vtexApi: {
23
+ get: catalogGet
24
+ },
25
+ vtexPricingApi: {
26
+ get: vi.fn()
27
+ }
28
+ });
29
+ });
30
+ it("fetches product offers through the general VTEX client", async () => {
31
+ const payload = [{ seller: "1", price: 1e3 }];
32
+ catalogGet.mockResolvedValue({ data: payload });
33
+ const result = await getProductOffers("profile-1", "product-1");
34
+ expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
35
+ expect(catalogGet).toHaveBeenCalledWith(
36
+ "/api/catalog_system/pub/products/offers/product-1"
37
+ );
38
+ expect(result).toEqual(payload);
39
+ });
40
+ it("fetches SKU offers using both product and sku identifiers", async () => {
41
+ const payload = [{ seller: "1", availableQuantity: 4 }];
42
+ catalogGet.mockResolvedValue({ data: payload });
43
+ const result = await getSkuOffers("profile-1", "product-1", "sku-9");
44
+ expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
45
+ expect(catalogGet).toHaveBeenCalledWith(
46
+ "/api/catalog_system/pub/products/offers/product-1/sku/sku-9"
47
+ );
48
+ expect(result).toEqual(payload);
49
+ });
50
+ });
51
+ //# sourceMappingURL=vtex-catalog.service.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../tests/vtex/vtex-catalog.service.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n\tgetProductOffers,\n\tgetSkuOffers,\n} from \"../../src/services/vtex/vtex-catalog.js\";\nimport { getVtexApiClients } from \"../../src/services/vtex/vtex-api.js\";\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tgetVtexApiClients: vi.fn(),\n}));\n\ndescribe(\"vtex-catalog service\", () => {\n\tconst catalogGet = vi.fn();\n\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\n\t\tvi.mocked(getVtexApiClients).mockResolvedValue({\n\t\t\tconfig: {\n\t\t\t\taccountName: \"test-account\",\n\t\t\t\tapiKey: \"key\",\n\t\t\t\tapiToken: \"token\",\n\t\t\t\tbaseUrl: \"https://example.vtex.com\",\n\t\t\t\tpricingBaseUrl: \"https://pricing.example.vtex.com\",\n\t\t\t},\n\t\t\tvtexApi: {\n\t\t\t\tget: catalogGet,\n\t\t\t} as never,\n\t\t\tvtexPricingApi: {\n\t\t\t\tget: vi.fn(),\n\t\t\t} as never,\n\t\t});\n\t});\n\n\tit(\"fetches product offers through the general VTEX client\", async () => {\n\t\tconst payload = [{ seller: \"1\", price: 1000 }];\n\t\tcatalogGet.mockResolvedValue({ data: payload });\n\n\t\tconst result = await getProductOffers(\"profile-1\", \"product-1\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(catalogGet).toHaveBeenCalledWith(\n\t\t\t\"/api/catalog_system/pub/products/offers/product-1\",\n\t\t);\n\t\texpect(result).toEqual(payload);\n\t});\n\n\tit(\"fetches SKU offers using both product and sku identifiers\", async () => {\n\t\tconst payload = [{ seller: \"1\", availableQuantity: 4 }];\n\t\tcatalogGet.mockResolvedValue({ data: payload });\n\n\t\tconst result = await getSkuOffers(\"profile-1\", \"product-1\", \"sku-9\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(catalogGet).toHaveBeenCalledWith(\n\t\t\t\"/api/catalog_system/pub/products/offers/product-1/sku/sku-9\",\n\t\t);\n\t\texpect(result).toEqual(payload);\n\t});\n});\n"],
5
+ "mappings": "AAAA,SAAS,YAAY,UAAU,QAAQ,IAAI,UAAU;AAErD;AAAA,EACC;AAAA,EACA;AAAA,OACM;AACP,SAAS,yBAAyB;AAElC,GAAG,KAAK,uCAAuC,OAAO;AAAA,EACrD,mBAAmB,GAAG,GAAG;AAC1B,EAAE;AAEF,SAAS,wBAAwB,MAAM;AACtC,QAAM,aAAa,GAAG,GAAG;AAEzB,aAAW,MAAM;AAChB,OAAG,cAAc;AAEjB,OAAG,OAAO,iBAAiB,EAAE,kBAAkB;AAAA,MAC9C,QAAQ;AAAA,QACP,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SAAS;AAAA,QACT,gBAAgB;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,QACR,KAAK;AAAA,MACN;AAAA,MACA,gBAAgB;AAAA,QACf,KAAK,GAAG,GAAG;AAAA,MACZ;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AAED,KAAG,0DAA0D,YAAY;AACxE,UAAM,UAAU,CAAC,EAAE,QAAQ,KAAK,OAAO,IAAK,CAAC;AAC7C,eAAW,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAE9C,UAAM,SAAS,MAAM,iBAAiB,aAAa,WAAW;AAE9D,WAAO,iBAAiB,EAAE,qBAAqB,WAAW;AAC1D,WAAO,UAAU,EAAE;AAAA,MAClB;AAAA,IACD;AACA,WAAO,MAAM,EAAE,QAAQ,OAAO;AAAA,EAC/B,CAAC;AAED,KAAG,6DAA6D,YAAY;AAC3E,UAAM,UAAU,CAAC,EAAE,QAAQ,KAAK,mBAAmB,EAAE,CAAC;AACtD,eAAW,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAE9C,UAAM,SAAS,MAAM,aAAa,aAAa,aAAa,OAAO;AAEnE,WAAO,iBAAiB,EAAE,qBAAqB,WAAW;AAC1D,WAAO,UAAU,EAAE;AAAA,MAClB;AAAA,IACD;AACA,WAAO,MAAM,EAAE,QAAQ,OAAO;AAAA,EAC/B,CAAC;AACF,CAAC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,201 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { formatVtexError } from "../../src/services/vtex/vtex-api.js";
3
+ import {
4
+ getInventoryBySkuBatch,
5
+ getInventoryByWarehouse
6
+ } from "../../src/services/vtex/vtex-logistics.js";
7
+ import { inventoryCheckHandler } from "../../src/tools/vtex/inventory-check.js";
8
+ import { resolveVtexProfileOrSelection } from "../../src/tools/vtex/profile-resolution.js";
9
+ import { warehouseInventoryHandler } from "../../src/tools/vtex/warehouse-inventory.js";
10
+ vi.mock("mcp-use/server", () => ({
11
+ object: vi.fn((payload) => ({ kind: "object", payload })),
12
+ error: vi.fn((message) => ({ kind: "error", message }))
13
+ }));
14
+ vi.mock("../../src/tools/vtex/profile-resolution.js", () => ({
15
+ resolveVtexProfileOrSelection: vi.fn()
16
+ }));
17
+ vi.mock("../../src/services/vtex/vtex-logistics.js", () => ({
18
+ getInventoryByWarehouse: vi.fn(),
19
+ getInventoryBySkuBatch: vi.fn()
20
+ }));
21
+ vi.mock("../../src/services/vtex/vtex-api.js", () => ({
22
+ formatVtexError: vi.fn(
23
+ (err, fallback) => `formatted:${fallback}:${err instanceof Error ? err.message : String(err)}`
24
+ )
25
+ }));
26
+ describe("heavy VTEX inventory tools", () => {
27
+ beforeEach(() => {
28
+ vi.clearAllMocks();
29
+ vi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({
30
+ ok: true,
31
+ value: { profileId: "profile-1" }
32
+ });
33
+ });
34
+ it("formats warehouse inventory output", async () => {
35
+ vi.mocked(getInventoryByWarehouse).mockResolvedValue([
36
+ {
37
+ skuId: "sku-1",
38
+ warehouseId: "wh-1",
39
+ totalQuantity: 10,
40
+ reservedQuantity: 3,
41
+ availableQuantity: 7,
42
+ isUnlimited: false,
43
+ keepSellingAfterExpiration: true
44
+ }
45
+ ]);
46
+ const result = await warehouseInventoryHandler({
47
+ profileId: "custom",
48
+ skuId: "sku-1",
49
+ warehouseId: "wh-1"
50
+ });
51
+ expect(getInventoryByWarehouse).toHaveBeenCalledWith(
52
+ "profile-1",
53
+ "sku-1",
54
+ "wh-1"
55
+ );
56
+ expect(result).toEqual({
57
+ kind: "object",
58
+ payload: {
59
+ profile_id: "profile-1",
60
+ sku_id: "sku-1",
61
+ warehouse_id: "wh-1",
62
+ inventory: [
63
+ {
64
+ sku_id: "sku-1",
65
+ warehouse_id: "wh-1",
66
+ total_quantity: 10,
67
+ reserved_quantity: 3,
68
+ available_quantity: 7,
69
+ is_unlimited: false,
70
+ keep_selling_after_expiration: true
71
+ }
72
+ ]
73
+ }
74
+ });
75
+ });
76
+ it("formats inventory batch output with deduped sku ids and dynamic warehouse schema", async () => {
77
+ vi.mocked(getInventoryBySkuBatch).mockResolvedValue({
78
+ successful: [
79
+ {
80
+ skuId: "sku-1",
81
+ document: {
82
+ skuId: "sku-1",
83
+ balance: [
84
+ {
85
+ warehouseName: "Main",
86
+ totalQuantity: 10,
87
+ reservedQuantity: 3,
88
+ hasUnlimitedQuantity: false,
89
+ timeToRefill: "2d",
90
+ dateOfSupplyUtc: "2026-06-01T15:30:00.000Z"
91
+ }
92
+ ]
93
+ }
94
+ },
95
+ {
96
+ skuId: "sku-2",
97
+ document: {
98
+ skuId: "sku-2",
99
+ balance: [
100
+ {
101
+ warehouseId: "WH-2",
102
+ totalQuantity: 2,
103
+ reservedQuantity: 0,
104
+ availableQuantity: 2,
105
+ isUnlimited: false
106
+ }
107
+ ]
108
+ }
109
+ }
110
+ ],
111
+ failed: [
112
+ {
113
+ skuId: "sku-3",
114
+ message: "missing",
115
+ statusCode: 404,
116
+ attempts: 1,
117
+ retryable: false
118
+ }
119
+ ]
120
+ });
121
+ const result = await inventoryCheckHandler({
122
+ profileId: "custom",
123
+ skuIds: ["sku-1", "sku-1", "sku-2", "sku-3"]
124
+ });
125
+ expect(getInventoryBySkuBatch).toHaveBeenCalledWith(
126
+ "profile-1",
127
+ ["sku-1", "sku-2", "sku-3"],
128
+ {
129
+ maxConcurrency: 10,
130
+ maxRetries: 2
131
+ }
132
+ );
133
+ expect(result).toEqual({
134
+ kind: "object",
135
+ payload: {
136
+ metadata: {
137
+ profile_id: "profile-1",
138
+ requested_ids: 4,
139
+ unique_ids: 3,
140
+ max_parallel_requests: 10,
141
+ successful_items: 2,
142
+ failed_items: 1,
143
+ has_failures: true
144
+ },
145
+ inventory_schema: {
146
+ sku: ["sku_id", "global_available_quantity", "health_status"],
147
+ warehouse_balance: [
148
+ "warehouseName",
149
+ "totalQuantity",
150
+ "reservedQuantity",
151
+ "hasUnlimitedQuantity",
152
+ "timeToRefill",
153
+ "dateOfSupplyUtc"
154
+ ]
155
+ },
156
+ inventory: [
157
+ {
158
+ sku: ["sku-1", 7, "LOW_STOCK"],
159
+ warehouses: [["Main", 10, 3, false, "2d", "2026-06-01 15:30"]]
160
+ },
161
+ {
162
+ sku: ["sku-2", 2, "CRITICAL_LOW_STOCK"],
163
+ warehouses: [["WH-2", 2, 0, false, "", ""]]
164
+ }
165
+ ],
166
+ failures: [
167
+ {
168
+ sku_id: "sku-3",
169
+ message: "missing",
170
+ status_code: 404,
171
+ attempts: 1,
172
+ retryable: false
173
+ }
174
+ ]
175
+ }
176
+ });
177
+ });
178
+ it("returns profile selection payload unchanged when resolution fails", async () => {
179
+ vi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({
180
+ ok: false,
181
+ response: { selection: true }
182
+ });
183
+ const result = await inventoryCheckHandler({ skuIds: ["sku-1"] });
184
+ expect(result).toEqual({ selection: true });
185
+ expect(getInventoryBySkuBatch).not.toHaveBeenCalled();
186
+ });
187
+ it("formats heavy tool failures through formatVtexError", async () => {
188
+ vi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error("boom"));
189
+ const result = await warehouseInventoryHandler({
190
+ profileId: "custom",
191
+ skuId: "sku-1",
192
+ warehouseId: "wh-1"
193
+ });
194
+ expect(formatVtexError).toHaveBeenCalled();
195
+ expect(result).toEqual({
196
+ kind: "error",
197
+ message: "formatted:Failed to fetch inventory for SKU sku-1 in warehouse wh-1:boom"
198
+ });
199
+ });
200
+ });
201
+ //# sourceMappingURL=vtex-inventory-tools.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../tests/vtex/vtex-inventory-tools.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { formatVtexError } from \"../../src/services/vtex/vtex-api.js\";\nimport {\n\tgetInventoryBySkuBatch,\n\tgetInventoryByWarehouse,\n} from \"../../src/services/vtex/vtex-logistics.js\";\nimport { inventoryCheckHandler } from \"../../src/tools/vtex/inventory-check.js\";\nimport { resolveVtexProfileOrSelection } from \"../../src/tools/vtex/profile-resolution.js\";\nimport { warehouseInventoryHandler } from \"../../src/tools/vtex/warehouse-inventory.js\";\n\nvi.mock(\"mcp-use/server\", () => ({\n\tobject: vi.fn((payload: unknown) => ({ kind: \"object\", payload })),\n\terror: vi.fn((message: string) => ({ kind: \"error\", message })),\n}));\n\nvi.mock(\"../../src/tools/vtex/profile-resolution.js\", () => ({\n\tresolveVtexProfileOrSelection: vi.fn(),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-logistics.js\", () => ({\n\tgetInventoryByWarehouse: vi.fn(),\n\tgetInventoryBySkuBatch: vi.fn(),\n}));\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tformatVtexError: vi.fn(\n\t\t(err: unknown, fallback: string) =>\n\t\t\t`formatted:${fallback}:${err instanceof Error ? err.message : String(err)}`,\n\t),\n}));\n\ndescribe(\"heavy VTEX inventory tools\", () => {\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\t\tvi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({\n\t\t\tok: true,\n\t\t\tvalue: { profileId: \"profile-1\" },\n\t\t});\n\t});\n\n\tit(\"formats warehouse inventory output\", async () => {\n\t\tvi.mocked(getInventoryByWarehouse).mockResolvedValue([\n\t\t\t{\n\t\t\t\tskuId: \"sku-1\",\n\t\t\t\twarehouseId: \"wh-1\",\n\t\t\t\ttotalQuantity: 10,\n\t\t\t\treservedQuantity: 3,\n\t\t\t\tavailableQuantity: 7,\n\t\t\t\tisUnlimited: false,\n\t\t\t\tkeepSellingAfterExpiration: true,\n\t\t\t},\n\t\t]);\n\n\t\tconst result = await warehouseInventoryHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuId: \"sku-1\",\n\t\t\twarehouseId: \"wh-1\",\n\t\t});\n\n\t\texpect(getInventoryByWarehouse).toHaveBeenCalledWith(\n\t\t\t\"profile-1\",\n\t\t\t\"sku-1\",\n\t\t\t\"wh-1\",\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tkind: \"object\",\n\t\t\tpayload: {\n\t\t\t\tprofile_id: \"profile-1\",\n\t\t\t\tsku_id: \"sku-1\",\n\t\t\t\twarehouse_id: \"wh-1\",\n\t\t\t\tinventory: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku_id: \"sku-1\",\n\t\t\t\t\t\twarehouse_id: \"wh-1\",\n\t\t\t\t\t\ttotal_quantity: 10,\n\t\t\t\t\t\treserved_quantity: 3,\n\t\t\t\t\t\tavailable_quantity: 7,\n\t\t\t\t\t\tis_unlimited: false,\n\t\t\t\t\t\tkeep_selling_after_expiration: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"formats inventory batch output with deduped sku ids and dynamic warehouse schema\", async () => {\n\t\tvi.mocked(getInventoryBySkuBatch).mockResolvedValue({\n\t\t\tsuccessful: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-1\",\n\t\t\t\t\tdocument: {\n\t\t\t\t\t\tskuId: \"sku-1\",\n\t\t\t\t\t\tbalance: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twarehouseName: \"Main\",\n\t\t\t\t\t\t\t\ttotalQuantity: 10,\n\t\t\t\t\t\t\t\treservedQuantity: 3,\n\t\t\t\t\t\t\t\thasUnlimitedQuantity: false,\n\t\t\t\t\t\t\t\ttimeToRefill: \"2d\",\n\t\t\t\t\t\t\t\tdateOfSupplyUtc: \"2026-06-01T15:30:00.000Z\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\tdocument: {\n\t\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\t\tbalance: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\twarehouseId: \"WH-2\",\n\t\t\t\t\t\t\t\ttotalQuantity: 2,\n\t\t\t\t\t\t\t\treservedQuantity: 0,\n\t\t\t\t\t\t\t\tavailableQuantity: 2,\n\t\t\t\t\t\t\t\tisUnlimited: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tfailed: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-3\",\n\t\t\t\t\tmessage: \"missing\",\n\t\t\t\t\tstatusCode: 404,\n\t\t\t\t\tattempts: 1,\n\t\t\t\t\tretryable: false,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst result = await inventoryCheckHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuIds: [\"sku-1\", \"sku-1\", \"sku-2\", \"sku-3\"],\n\t\t});\n\n\t\texpect(getInventoryBySkuBatch).toHaveBeenCalledWith(\n\t\t\t\"profile-1\",\n\t\t\t[\"sku-1\", \"sku-2\", \"sku-3\"],\n\t\t\t{\n\t\t\t\tmaxConcurrency: 10,\n\t\t\t\tmaxRetries: 2,\n\t\t\t},\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tkind: \"object\",\n\t\t\tpayload: {\n\t\t\t\tmetadata: {\n\t\t\t\t\tprofile_id: \"profile-1\",\n\t\t\t\t\trequested_ids: 4,\n\t\t\t\t\tunique_ids: 3,\n\t\t\t\t\tmax_parallel_requests: 10,\n\t\t\t\t\tsuccessful_items: 2,\n\t\t\t\t\tfailed_items: 1,\n\t\t\t\t\thas_failures: true,\n\t\t\t\t},\n\t\t\t\tinventory_schema: {\n\t\t\t\t\tsku: [\"sku_id\", \"global_available_quantity\", \"health_status\"],\n\t\t\t\t\twarehouse_balance: [\n\t\t\t\t\t\t\"warehouseName\",\n\t\t\t\t\t\t\"totalQuantity\",\n\t\t\t\t\t\t\"reservedQuantity\",\n\t\t\t\t\t\t\"hasUnlimitedQuantity\",\n\t\t\t\t\t\t\"timeToRefill\",\n\t\t\t\t\t\t\"dateOfSupplyUtc\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tinventory: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku: [\"sku-1\", 7, \"LOW_STOCK\"],\n\t\t\t\t\t\twarehouses: [[\"Main\", 10, 3, false, \"2d\", \"2026-06-01 15:30\"]],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsku: [\"sku-2\", 2, \"CRITICAL_LOW_STOCK\"],\n\t\t\t\t\t\twarehouses: [[\"WH-2\", 2, 0, false, \"\", \"\"]],\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tfailures: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsku_id: \"sku-3\",\n\t\t\t\t\t\tmessage: \"missing\",\n\t\t\t\t\t\tstatus_code: 404,\n\t\t\t\t\t\tattempts: 1,\n\t\t\t\t\t\tretryable: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\t});\n\n\tit(\"returns profile selection payload unchanged when resolution fails\", async () => {\n\t\tvi.mocked(resolveVtexProfileOrSelection).mockResolvedValue({\n\t\t\tok: false,\n\t\t\tresponse: { selection: true },\n\t\t} as never);\n\n\t\tconst result = await inventoryCheckHandler({ skuIds: [\"sku-1\"] });\n\n\t\texpect(result).toEqual({ selection: true });\n\t\texpect(getInventoryBySkuBatch).not.toHaveBeenCalled();\n\t});\n\n\tit(\"formats heavy tool failures through formatVtexError\", async () => {\n\t\tvi.mocked(getInventoryByWarehouse).mockRejectedValue(new Error(\"boom\"));\n\n\t\tconst result = await warehouseInventoryHandler({\n\t\t\tprofileId: \"custom\",\n\t\t\tskuId: \"sku-1\",\n\t\t\twarehouseId: \"wh-1\",\n\t\t});\n\n\t\texpect(formatVtexError).toHaveBeenCalled();\n\t\texpect(result).toEqual({\n\t\t\tkind: \"error\",\n\t\t\tmessage:\n\t\t\t\t\"formatted:Failed to fetch inventory for SKU sku-1 in warehouse wh-1:boom\",\n\t\t});\n\t});\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,134 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ getInventoryBySku,
4
+ getInventoryBySkuBatch,
5
+ getInventoryByWarehouse
6
+ } from "../../src/services/vtex/vtex-logistics.js";
7
+ import { getVtexApiClients } from "../../src/services/vtex/vtex-api.js";
8
+ vi.mock("../../src/services/vtex/vtex-api.js", () => ({
9
+ getVtexApiClients: vi.fn()
10
+ }));
11
+ function makeAxiosLikeError(message, status, retryAfter) {
12
+ return {
13
+ isAxiosError: true,
14
+ message,
15
+ response: status ? {
16
+ status,
17
+ headers: retryAfter === void 0 ? {} : { "retry-after": retryAfter },
18
+ data: { message }
19
+ } : void 0,
20
+ toJSON: () => ({})
21
+ };
22
+ }
23
+ describe("vtex-logistics service", () => {
24
+ const logisticsGet = vi.fn();
25
+ beforeEach(() => {
26
+ vi.clearAllMocks();
27
+ vi.mocked(getVtexApiClients).mockResolvedValue({
28
+ config: {
29
+ accountName: "test-account",
30
+ apiKey: "key",
31
+ apiToken: "token",
32
+ baseUrl: "https://example.vtex.com",
33
+ pricingBaseUrl: "https://pricing.example.vtex.com"
34
+ },
35
+ vtexApi: {
36
+ get: logisticsGet,
37
+ patch: vi.fn()
38
+ },
39
+ vtexPricingApi: {
40
+ get: vi.fn()
41
+ }
42
+ });
43
+ });
44
+ it("fetches inventory by sku", async () => {
45
+ logisticsGet.mockResolvedValue({
46
+ data: {
47
+ skuId: "sku-1",
48
+ balance: [{ warehouseId: "wh-1", availableQuantity: 4 }]
49
+ }
50
+ });
51
+ const result = await getInventoryBySku("profile-1", "sku-1");
52
+ expect(getVtexApiClients).toHaveBeenCalledWith("profile-1");
53
+ expect(logisticsGet).toHaveBeenCalledWith(
54
+ "/api/logistics/pvt/inventory/skus/sku-1"
55
+ );
56
+ expect(result).toEqual({
57
+ skuId: "sku-1",
58
+ balance: [{ warehouseId: "wh-1", availableQuantity: 4 }]
59
+ });
60
+ });
61
+ it("fetches inventory by warehouse for a sku", async () => {
62
+ logisticsGet.mockResolvedValue({
63
+ data: [{ skuId: "sku-1", warehouseId: "wh-1", availableQuantity: 3 }]
64
+ });
65
+ const result = await getInventoryByWarehouse("profile-1", "sku-1", "wh-1");
66
+ expect(logisticsGet).toHaveBeenCalledWith(
67
+ "/api/logistics/pvt/inventory/items/sku-1/warehouses/wh-1"
68
+ );
69
+ expect(result).toEqual([
70
+ { skuId: "sku-1", warehouseId: "wh-1", availableQuantity: 3 }
71
+ ]);
72
+ });
73
+ it("returns successful and failed sku inventory documents in batch mode", async () => {
74
+ logisticsGet.mockImplementation((url) => {
75
+ if (url.endsWith("sku-1")) {
76
+ return Promise.resolve({ data: { skuId: "sku-1", balance: [] } });
77
+ }
78
+ return Promise.reject(makeAxiosLikeError("missing", 404));
79
+ });
80
+ const result = await getInventoryBySkuBatch(
81
+ "profile-1",
82
+ ["sku-1", "sku-2"],
83
+ {
84
+ maxConcurrency: 2,
85
+ maxRetries: 0
86
+ }
87
+ );
88
+ expect(result).toEqual({
89
+ successful: [
90
+ { skuId: "sku-1", document: { skuId: "sku-1", balance: [] } }
91
+ ],
92
+ failed: [
93
+ {
94
+ skuId: "sku-2",
95
+ message: "Unexpected error while fetching inventory details",
96
+ statusCode: 404,
97
+ attempts: 1,
98
+ retryable: false
99
+ }
100
+ ]
101
+ });
102
+ });
103
+ it("retries retryable inventory fetches and then succeeds", async () => {
104
+ let attempts = 0;
105
+ logisticsGet.mockImplementation((url) => {
106
+ if (!url.endsWith("sku-3")) {
107
+ return Promise.resolve({ data: { skuId: "other", balance: [] } });
108
+ }
109
+ attempts += 1;
110
+ if (attempts === 1) {
111
+ return Promise.reject(makeAxiosLikeError("rate limited", 429, 0));
112
+ }
113
+ return Promise.resolve({
114
+ data: { skuId: "sku-3", balance: [{ warehouseId: "wh-1" }] }
115
+ });
116
+ });
117
+ const result = await getInventoryBySkuBatch("profile-1", ["sku-3"], {
118
+ maxConcurrency: 1,
119
+ maxRetries: 1,
120
+ baseRetryDelayMs: 0
121
+ });
122
+ expect(attempts).toBe(2);
123
+ expect(result).toEqual({
124
+ successful: [
125
+ {
126
+ skuId: "sku-3",
127
+ document: { skuId: "sku-3", balance: [{ warehouseId: "wh-1" }] }
128
+ }
129
+ ],
130
+ failed: []
131
+ });
132
+ });
133
+ });
134
+ //# sourceMappingURL=vtex-logistics.service.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../tests/vtex/vtex-logistics.service.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport {\n\tgetInventoryBySku,\n\tgetInventoryBySkuBatch,\n\tgetInventoryByWarehouse,\n} from \"../../src/services/vtex/vtex-logistics.js\";\nimport { getVtexApiClients } from \"../../src/services/vtex/vtex-api.js\";\n\nvi.mock(\"../../src/services/vtex/vtex-api.js\", () => ({\n\tgetVtexApiClients: vi.fn(),\n}));\n\nfunction makeAxiosLikeError(\n\tmessage: string,\n\tstatus?: number,\n\tretryAfter?: string | number,\n) {\n\treturn {\n\t\tisAxiosError: true,\n\t\tmessage,\n\t\tresponse: status\n\t\t\t? {\n\t\t\t\t\tstatus,\n\t\t\t\t\theaders:\n\t\t\t\t\t\tretryAfter === undefined ? {} : { \"retry-after\": retryAfter },\n\t\t\t\t\tdata: { message },\n\t\t\t\t}\n\t\t\t: undefined,\n\t\ttoJSON: () => ({}),\n\t};\n}\n\ndescribe(\"vtex-logistics service\", () => {\n\tconst logisticsGet = vi.fn();\n\n\tbeforeEach(() => {\n\t\tvi.clearAllMocks();\n\n\t\tvi.mocked(getVtexApiClients).mockResolvedValue({\n\t\t\tconfig: {\n\t\t\t\taccountName: \"test-account\",\n\t\t\t\tapiKey: \"key\",\n\t\t\t\tapiToken: \"token\",\n\t\t\t\tbaseUrl: \"https://example.vtex.com\",\n\t\t\t\tpricingBaseUrl: \"https://pricing.example.vtex.com\",\n\t\t\t},\n\t\t\tvtexApi: {\n\t\t\t\tget: logisticsGet,\n\t\t\t\tpatch: vi.fn(),\n\t\t\t} as never,\n\t\t\tvtexPricingApi: {\n\t\t\t\tget: vi.fn(),\n\t\t\t} as never,\n\t\t});\n\t});\n\n\tit(\"fetches inventory by sku\", async () => {\n\t\tlogisticsGet.mockResolvedValue({\n\t\t\tdata: {\n\t\t\t\tskuId: \"sku-1\",\n\t\t\t\tbalance: [{ warehouseId: \"wh-1\", availableQuantity: 4 }],\n\t\t\t},\n\t\t});\n\n\t\tconst result = await getInventoryBySku(\"profile-1\", \"sku-1\");\n\n\t\texpect(getVtexApiClients).toHaveBeenCalledWith(\"profile-1\");\n\t\texpect(logisticsGet).toHaveBeenCalledWith(\n\t\t\t\"/api/logistics/pvt/inventory/skus/sku-1\",\n\t\t);\n\t\texpect(result).toEqual({\n\t\t\tskuId: \"sku-1\",\n\t\t\tbalance: [{ warehouseId: \"wh-1\", availableQuantity: 4 }],\n\t\t});\n\t});\n\n\tit(\"fetches inventory by warehouse for a sku\", async () => {\n\t\tlogisticsGet.mockResolvedValue({\n\t\t\tdata: [{ skuId: \"sku-1\", warehouseId: \"wh-1\", availableQuantity: 3 }],\n\t\t});\n\n\t\tconst result = await getInventoryByWarehouse(\"profile-1\", \"sku-1\", \"wh-1\");\n\n\t\texpect(logisticsGet).toHaveBeenCalledWith(\n\t\t\t\"/api/logistics/pvt/inventory/items/sku-1/warehouses/wh-1\",\n\t\t);\n\t\texpect(result).toEqual([\n\t\t\t{ skuId: \"sku-1\", warehouseId: \"wh-1\", availableQuantity: 3 },\n\t\t]);\n\t});\n\n\tit(\"returns successful and failed sku inventory documents in batch mode\", async () => {\n\t\tlogisticsGet.mockImplementation((url: string) => {\n\t\t\tif (url.endsWith(\"sku-1\")) {\n\t\t\t\treturn Promise.resolve({ data: { skuId: \"sku-1\", balance: [] } });\n\t\t\t}\n\n\t\t\treturn Promise.reject(makeAxiosLikeError(\"missing\", 404));\n\t\t});\n\n\t\tconst result = await getInventoryBySkuBatch(\n\t\t\t\"profile-1\",\n\t\t\t[\"sku-1\", \"sku-2\"],\n\t\t\t{\n\t\t\t\tmaxConcurrency: 2,\n\t\t\t\tmaxRetries: 0,\n\t\t\t},\n\t\t);\n\n\t\texpect(result).toEqual({\n\t\t\tsuccessful: [\n\t\t\t\t{ skuId: \"sku-1\", document: { skuId: \"sku-1\", balance: [] } },\n\t\t\t],\n\t\t\tfailed: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-2\",\n\t\t\t\t\tmessage: \"Unexpected error while fetching inventory details\",\n\t\t\t\t\tstatusCode: 404,\n\t\t\t\t\tattempts: 1,\n\t\t\t\t\tretryable: false,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t});\n\n\tit(\"retries retryable inventory fetches and then succeeds\", async () => {\n\t\tlet attempts = 0;\n\t\tlogisticsGet.mockImplementation((url: string) => {\n\t\t\tif (!url.endsWith(\"sku-3\")) {\n\t\t\t\treturn Promise.resolve({ data: { skuId: \"other\", balance: [] } });\n\t\t\t}\n\n\t\t\tattempts += 1;\n\t\t\tif (attempts === 1) {\n\t\t\t\treturn Promise.reject(makeAxiosLikeError(\"rate limited\", 429, 0));\n\t\t\t}\n\n\t\t\treturn Promise.resolve({\n\t\t\t\tdata: { skuId: \"sku-3\", balance: [{ warehouseId: \"wh-1\" }] },\n\t\t\t});\n\t\t});\n\n\t\tconst result = await getInventoryBySkuBatch(\"profile-1\", [\"sku-3\"], {\n\t\t\tmaxConcurrency: 1,\n\t\t\tmaxRetries: 1,\n\t\t\tbaseRetryDelayMs: 0,\n\t\t});\n\n\t\texpect(attempts).toBe(2);\n\t\texpect(result).toEqual({\n\t\t\tsuccessful: [\n\t\t\t\t{\n\t\t\t\t\tskuId: \"sku-3\",\n\t\t\t\t\tdocument: { skuId: \"sku-3\", balance: [{ warehouseId: \"wh-1\" }] },\n\t\t\t\t},\n\t\t\t],\n\t\t\tfailed: [],\n\t\t});\n\t});\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }