@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
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/search-console/search-console-utils.ts"],
4
- "sourcesContent": ["import { z } from \"zod\";\n\nimport type {\n SearchConsoleDimensionFilter,\n SearchConsoleDimensionFilterGroup,\n SearchConsoleSearchAnalyticsRequest,\n SearchConsoleSearchAnalyticsRow,\n SearchConsoleSiteEntry,\n} from \"../services/search-console/search-console-client.js\";\n\nexport const searchConsoleDateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const searchConsoleSearchTypes = [\"web\", \"image\", \"video\", \"news\", \"discover\"] as const;\nexport const searchConsoleDimensions = [\n \"query\",\n \"page\",\n \"country\",\n \"device\",\n \"date\",\n \"searchAppearance\",\n] as const;\nexport const searchConsoleFilterOperators = [\n \"contains\",\n \"equals\",\n \"notContains\",\n \"notEquals\",\n \"includingRegex\",\n \"excludingRegex\",\n] as const;\nexport const searchConsoleAggregationTypes = [\"auto\", \"byPage\", \"byProperty\"] as const;\n\nexport const searchConsoleDimensionFilterSchema = z.object({\n dimension: z\n .enum(searchConsoleDimensions)\n .describe(\"Dimension to filter on in Search Console (query, page, country, device, date, or searchAppearance)\"),\n operator: z\n .enum(searchConsoleFilterOperators)\n .describe(\"Filter operator supported by Search Console.\"),\n expression: z.string().min(1).describe(\"Filter value or regex expression.\"),\n});\n\nexport const siteUrlSchemaField = z\n .string()\n .optional()\n .describe(\n \"Search Console site URL or domain property identifier (for example https://www.example.com/ or sc-domain:example.com). If omitted, the tool expects the site to be configured elsewhere.\"\n );\n\nexport const profileIdSchemaField = z\n .string()\n .optional()\n .describe(\"Optional business profile identifier for future multi-profile resolution. Defaults to the active profile when supported.\");\n\nexport const startDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"Start date in YYYY-MM-DD format.\");\n\nexport const endDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"End date in YYYY-MM-DD format.\");\n\nexport const currentStartDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"Current comparison period start date in YYYY-MM-DD format.\");\n\nexport const currentEndDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"Current comparison period end date in YYYY-MM-DD format.\");\n\nexport const previousStartDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"Previous comparison period start date in YYYY-MM-DD format.\");\n\nexport const previousEndDateSchemaField = z\n .string()\n .regex(searchConsoleDateRegex)\n .describe(\"Previous comparison period end date in YYYY-MM-DD format.\");\n\nexport const rowLimitSchemaField = z\n .number()\n .int()\n .min(1)\n .max(25000)\n .optional()\n .describe(\"Maximum number of rows to return. Search Console supports up to 25,000 rows per request.\");\n\nexport const startRowSchemaField = z\n .number()\n .int()\n .min(0)\n .optional()\n .describe(\"Zero-based row offset for paginated Search Console requests.\");\n\nexport const searchTypeSchemaField = z\n .enum(searchConsoleSearchTypes)\n .optional()\n .describe(\"Search type to query. Defaults to web.\");\n\nexport const brandTermsSchemaField = z\n .array(z.string().min(1))\n .max(50)\n .optional()\n .describe(\"Brand tokens used to separate branded from non-branded queries.\");\n\nexport function resolveSearchConsoleSiteUrl(siteUrl?: string, profileId?: string): string {\n const explicitSiteUrl = siteUrl?.trim();\n if (explicitSiteUrl) {\n return explicitSiteUrl;\n }\n\n if (profileId?.trim()) {\n throw new Error(\n `Missing Search Console site URL. profileId \"${profileId}\" was provided, but business-data based site resolution is not implemented yet. Pass siteUrl explicitly or configure Search Console site resolution first.`\n );\n }\n\n throw new Error(\n \"Missing Search Console site URL. Pass siteUrl explicitly or first call gsc_list_accessible_sites to discover available properties.\"\n );\n}\n\nexport function inferSearchConsolePropertyType(\n siteUrl: string\n): \"domain\" | \"url_prefix\" | \"unknown\" {\n if (siteUrl.startsWith(\"sc-domain:\")) {\n return \"domain\";\n }\n\n if (/^https?:\\/\\//.test(siteUrl)) {\n return \"url_prefix\";\n }\n\n return \"unknown\";\n}\n\nexport function normalizePermissionLevel(permissionLevel?: string): string | undefined {\n return permissionLevel?.trim().toLowerCase() || undefined;\n}\n\nexport function normalizeSearchConsoleSiteEntry(siteEntry: SearchConsoleSiteEntry) {\n return {\n site_url: siteEntry.siteUrl,\n property_type: inferSearchConsolePropertyType(siteEntry.siteUrl),\n permission_level: normalizePermissionLevel(siteEntry.permissionLevel),\n };\n}\n\nexport function toPercent(numerator: number, denominator: number): number {\n if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {\n return 0;\n }\n\n return (numerator / denominator) * 100;\n}\n\nexport function round(value: number, decimals = 2): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\nexport function normalizeSearchConsoleRow(\n row: SearchConsoleSearchAnalyticsRow,\n dimensions: readonly string[] = []\n) {\n const clicks = row.clicks ?? 0;\n const impressions = row.impressions ?? 0;\n const ctr = typeof row.ctr === \"number\" ? row.ctr * 100 : toPercent(clicks, impressions);\n const keys = row.keys ?? [];\n\n return {\n keys,\n dimensions: dimensions.reduce<Record<string, string>>((accumulator, dimension, index) => {\n accumulator[dimension] = keys[index] ?? \"\";\n return accumulator;\n }, {}),\n clicks: round(clicks, 2),\n impressions: round(impressions, 2),\n ctr_percent: round(ctr, 2),\n position: round(row.position ?? 0, 2),\n };\n}\n\nexport function buildSearchConsoleQueryBody(input: {\n startDate: string;\n endDate: string;\n dimensions?: string[];\n searchType?: string;\n dimensionFilters?: SearchConsoleDimensionFilter[];\n aggregationType?: string;\n rowLimit?: number;\n startRow?: number;\n}): SearchConsoleSearchAnalyticsRequest {\n const dimensionFilterGroups: SearchConsoleDimensionFilterGroup[] | undefined =\n input.dimensionFilters && input.dimensionFilters.length > 0\n ? [\n {\n groupType: \"and\",\n filters: input.dimensionFilters,\n },\n ]\n : undefined;\n\n return {\n startDate: input.startDate,\n endDate: input.endDate,\n dimensions: input.dimensions,\n type: input.searchType ?? \"web\",\n dimensionFilterGroups,\n aggregationType: input.aggregationType,\n rowLimit: input.rowLimit,\n startRow: input.startRow,\n };\n}\n\nexport function buildPaginationMetadata(input: {\n startRow?: number;\n rowLimit?: number;\n returnedRows: number;\n}) {\n const startRow = input.startRow ?? 0;\n const rowLimit = input.rowLimit;\n const isPartial = Boolean(rowLimit) && input.returnedRows === rowLimit;\n const nextStartRow = isPartial ? startRow + input.returnedRows : undefined;\n\n return {\n is_partial: isPartial,\n start_row: startRow,\n row_limit: rowLimit,\n returned_rows: input.returnedRows,\n next_start_row: nextStartRow,\n continuation_instructions: nextStartRow\n ? \"This Search Console response may be truncated at row_limit. If you need additional rows, call the same tool again with startRow set to next_start_row.\"\n : undefined,\n };\n}\n\nexport function parseBrandTerms(brandTerms?: string[]): string[] {\n return (brandTerms ?? []).map((term) => term.trim().toLowerCase()).filter(Boolean);\n}\n\nexport function isBrandedQuery(query: string, brandTerms?: string[]): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n const normalizedBrandTerms = parseBrandTerms(brandTerms);\n\n if (!normalizedQuery || normalizedBrandTerms.length === 0) {\n return false;\n }\n\n return normalizedBrandTerms.some((brandTerm) => normalizedQuery.includes(brandTerm));\n}\n\nexport function classifyBrandLabel(query: string, brandTerms?: string[]): \"brand\" | \"non_brand\" {\n return isBrandedQuery(query, brandTerms) ? \"brand\" : \"non_brand\";\n}\n\nexport function computeChangePercent(currentValue: number, previousValue: number): number | null {\n if (!Number.isFinite(currentValue) || !Number.isFinite(previousValue)) {\n return null;\n }\n\n if (previousValue === 0) {\n if (currentValue === 0) {\n return 0;\n }\n\n return null;\n }\n\n return round(((currentValue - previousValue) / previousValue) * 100, 2);\n}\n\nexport function sumSearchConsoleRows(\n rows: Array<ReturnType<typeof normalizeSearchConsoleRow>>\n): {\n clicks: number;\n impressions: number;\n ctrPercent: number;\n averagePosition: number;\n} {\n const totals = rows.reduce(\n (accumulator, row) => {\n accumulator.clicks += row.clicks;\n accumulator.impressions += row.impressions;\n accumulator.weightedPosition += row.position * row.impressions;\n return accumulator;\n },\n {\n clicks: 0,\n impressions: 0,\n weightedPosition: 0,\n }\n );\n\n return {\n clicks: round(totals.clicks, 2),\n impressions: round(totals.impressions, 2),\n ctrPercent: round(toPercent(totals.clicks, totals.impressions), 2),\n averagePosition: totals.impressions > 0 ? round(totals.weightedPosition / totals.impressions, 2) : 0,\n };\n}\n\nexport function buildComparisonMap(\n rows: Array<ReturnType<typeof normalizeSearchConsoleRow>>,\n keyBuilder: (row: ReturnType<typeof normalizeSearchConsoleRow>) => string\n) {\n return new Map(rows.map((row) => [keyBuilder(row), row]));\n}\n\nexport function tokenizeQuery(query: string): string[] {\n return query\n .toLowerCase()\n .split(/[^a-z0-9\u00E1\u00E9\u00ED\u00F3\u00FA\u00FC\u00F1]+/i)\n .map((token) => token.trim())\n .filter(Boolean);\n}\n\nexport function looksLikeCommercialQuery(query: string): boolean {\n const tokens = tokenizeQuery(query);\n const commercialTerms = new Set([\n \"comprar\",\n \"precio\",\n \"precios\",\n \"cuanto\",\n \"oferta\",\n \"ofertas\",\n \"envio\",\n \"shop\",\n \"tienda\",\n \"modelo\",\n \"medida\",\n \"ml\",\n \"cm\",\n \"kg\",\n ]);\n\n return tokens.some((token) => commercialTerms.has(token));\n}\n\nexport function looksLikeProductQuery(query: string, productTerms?: string[]): boolean {\n const normalizedProductTerms = parseBrandTerms(productTerms);\n const normalizedQuery = query.toLowerCase();\n\n if (normalizedProductTerms.some((term) => normalizedQuery.includes(term))) {\n return true;\n }\n\n return looksLikeCommercialQuery(query) || tokenizeQuery(query).length >= 3;\n}\n\nexport function classifyQuickWinType(position: number, ctrPercent: number): \"ctr\" | \"position\" {\n if (position <= 8 && ctrPercent <= 3) {\n return \"ctr\";\n }\n\n return \"position\";\n}\n\nexport function scoreHighImpressionLowClickOpportunity(input: {\n impressions: number;\n ctrPercent: number;\n position: number;\n}): number {\n const impressionScore = Math.min(input.impressions / 100, 60);\n const ctrPenalty = Math.max(0, 15 - input.ctrPercent) * 2;\n const positionBonus = input.position > 0 && input.position <= 20 ? Math.max(0, 20 - input.position) : 0;\n\n return round(impressionScore + ctrPenalty + positionBonus, 2);\n}\n\nexport function scoreQuickWinOpportunity(input: {\n impressions: number;\n ctrPercent: number;\n position: number;\n}): number {\n const impressionWeight = Math.min(input.impressions / 150, 50);\n const ctrWeight = Math.max(0, 10 - input.ctrPercent) * 3;\n const positionWeight = input.position > 0 && input.position <= 20 ? Math.max(0, 18 - input.position) * 1.8 : 0;\n\n return round(impressionWeight + ctrWeight + positionWeight, 2);\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,165 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
- const getMock = vi.fn();
3
- const postMock = vi.fn();
4
- const putMock = vi.fn();
5
- const deleteMock = vi.fn();
6
- vi.mock("../vtex-api.js", () => ({
7
- getVtexApiClients: vi.fn(async () => ({
8
- vtexApi: {
9
- get: getMock,
10
- post: postMock,
11
- put: putMock,
12
- delete: deleteMock
13
- }
14
- }))
15
- }));
16
- const catalogWrite = await import("../vtex-catalog-write.js");
17
- describe("VTEX catalog write batch planning and execution", () => {
18
- beforeEach(() => {
19
- vi.clearAllMocks();
20
- });
21
- it("builds batch preflight summaries and destructive warnings from mixed operations", async () => {
22
- const operations = [
23
- {
24
- type: "update_product_basic_fields",
25
- productId: "product-1",
26
- updates: { name: "New Product Name" }
27
- },
28
- {
29
- type: "update_sku_basic_fields",
30
- skuId: "sku-1",
31
- updates: { measurementUnit: "un", unitMultiplier: 1 }
32
- },
33
- {
34
- type: "replace_sku_eans",
35
- skuId: "sku-2",
36
- eans: ["111", "222"]
37
- }
38
- ];
39
- await expect(catalogWrite.planCatalogBatch("profile-1", operations)).resolves.toEqual({
40
- preflight: {
41
- entities: 3,
42
- entityTypes: ["product", "sku"],
43
- destructive: true,
44
- hasDeleteOrReplaceAll: true,
45
- dependencyFailureCount: 0,
46
- multiEntityCriticalReassignment: false
47
- },
48
- warnings: ["destructive_operation_detected"],
49
- impactedEntityTypes: ["product", "sku"],
50
- before: [
51
- {
52
- operation_index: 0,
53
- operation_type: "update_product_basic_fields",
54
- resource_id: "product-1"
55
- },
56
- {
57
- operation_index: 1,
58
- operation_type: "update_sku_basic_fields",
59
- resource_id: "sku-1"
60
- },
61
- {
62
- operation_index: 2,
63
- operation_type: "replace_sku_eans",
64
- resource_id: "sku-2"
65
- }
66
- ],
67
- after: [
68
- {
69
- operation_index: 0,
70
- operation_type: "update_product_basic_fields",
71
- resource_id: "product-1",
72
- updates: { name: "New Product Name" }
73
- },
74
- {
75
- operation_index: 1,
76
- operation_type: "update_sku_basic_fields",
77
- resource_id: "sku-1",
78
- updates: { measurementUnit: "un", unitMultiplier: 1 }
79
- },
80
- {
81
- operation_index: 2,
82
- operation_type: "replace_sku_eans",
83
- resource_id: "sku-2",
84
- planned_eans: ["111", "222"]
85
- }
86
- ]
87
- });
88
- });
89
- it("aggregates batch successes and failures without aborting later operations", async () => {
90
- const operations = [
91
- {
92
- type: "update_product_basic_fields",
93
- productId: "product-1",
94
- updates: { name: "Updated Product" }
95
- },
96
- {
97
- type: "update_sku_basic_fields",
98
- skuId: "sku-1",
99
- updates: { name: "Updated SKU" }
100
- },
101
- {
102
- type: "replace_sku_eans",
103
- skuId: "sku-2",
104
- eans: ["111", "222", "111"]
105
- }
106
- ];
107
- getMock.mockResolvedValueOnce({
108
- data: {
109
- Name: "Original Product",
110
- CategoryId: 10,
111
- BrandId: 20
112
- }
113
- });
114
- putMock.mockResolvedValueOnce({
115
- data: {
116
- Id: "product-1",
117
- Name: "Updated Product"
118
- }
119
- });
120
- getMock.mockRejectedValueOnce(new Error("sku fetch failed"));
121
- deleteMock.mockResolvedValueOnce({});
122
- postMock.mockResolvedValue({});
123
- getMock.mockResolvedValueOnce({ data: ["111", "222"] });
124
- await expect(catalogWrite.executeCatalogBatch("profile-1", operations)).resolves.toEqual({
125
- successful: [
126
- {
127
- operation_index: 0,
128
- operation_type: "update_product_basic_fields",
129
- resource_id: "product-1",
130
- result: {
131
- Id: "product-1",
132
- Name: "Updated Product"
133
- }
134
- },
135
- {
136
- operation_index: 2,
137
- operation_type: "replace_sku_eans",
138
- resource_id: "sku-2",
139
- result: {
140
- eans: ["111", "222"]
141
- }
142
- }
143
- ],
144
- failed: [
145
- {
146
- operation_index: 1,
147
- operation_type: "update_sku_basic_fields",
148
- resource_id: "sku-1",
149
- message: "sku fetch failed"
150
- }
151
- ]
152
- });
153
- expect(deleteMock).toHaveBeenCalledWith("/api/catalog/pvt/stockkeepingunit/sku-2/ean");
154
- expect(postMock).toHaveBeenNthCalledWith(
155
- 1,
156
- "/api/catalog/pvt/stockkeepingunit/sku-2/ean/111"
157
- );
158
- expect(postMock).toHaveBeenNthCalledWith(
159
- 2,
160
- "/api/catalog/pvt/stockkeepingunit/sku-2/ean/222"
161
- );
162
- expect(postMock).toHaveBeenCalledTimes(2);
163
- });
164
- });
165
- //# sourceMappingURL=vtex-catalog-write-batch.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/services/vtex/__tests__/vtex-catalog-write-batch.test.ts"],
4
- "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst getMock = vi.fn();\nconst postMock = vi.fn();\nconst putMock = vi.fn();\nconst deleteMock = vi.fn();\n\nvi.mock(\"../vtex-api.js\", () => ({\n getVtexApiClients: vi.fn(async () => ({\n vtexApi: {\n get: getMock,\n post: postMock,\n put: putMock,\n delete: deleteMock,\n },\n })),\n}));\n\nconst catalogWrite = await import(\"../vtex-catalog-write.js\");\n\ndescribe(\"VTEX catalog write batch planning and execution\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n it(\"builds batch preflight summaries and destructive warnings from mixed operations\", async () => {\n const operations = [\n {\n type: \"update_product_basic_fields\" as const,\n productId: \"product-1\",\n updates: { name: \"New Product Name\" },\n },\n {\n type: \"update_sku_basic_fields\" as const,\n skuId: \"sku-1\",\n updates: { measurementUnit: \"un\", unitMultiplier: 1 },\n },\n {\n type: \"replace_sku_eans\" as const,\n skuId: \"sku-2\",\n eans: [\"111\", \"222\"],\n },\n ];\n\n await expect(catalogWrite.planCatalogBatch(\"profile-1\", operations)).resolves.toEqual({\n preflight: {\n entities: 3,\n entityTypes: [\"product\", \"sku\"],\n destructive: true,\n hasDeleteOrReplaceAll: true,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n warnings: [\"destructive_operation_detected\"],\n impactedEntityTypes: [\"product\", \"sku\"],\n before: [\n {\n operation_index: 0,\n operation_type: \"update_product_basic_fields\",\n resource_id: \"product-1\",\n },\n {\n operation_index: 1,\n operation_type: \"update_sku_basic_fields\",\n resource_id: \"sku-1\",\n },\n {\n operation_index: 2,\n operation_type: \"replace_sku_eans\",\n resource_id: \"sku-2\",\n },\n ],\n after: [\n {\n operation_index: 0,\n operation_type: \"update_product_basic_fields\",\n resource_id: \"product-1\",\n updates: { name: \"New Product Name\" },\n },\n {\n operation_index: 1,\n operation_type: \"update_sku_basic_fields\",\n resource_id: \"sku-1\",\n updates: { measurementUnit: \"un\", unitMultiplier: 1 },\n },\n {\n operation_index: 2,\n operation_type: \"replace_sku_eans\",\n resource_id: \"sku-2\",\n planned_eans: [\"111\", \"222\"],\n },\n ],\n });\n });\n\n it(\"aggregates batch successes and failures without aborting later operations\", async () => {\n const operations = [\n {\n type: \"update_product_basic_fields\" as const,\n productId: \"product-1\",\n updates: { name: \"Updated Product\" },\n },\n {\n type: \"update_sku_basic_fields\" as const,\n skuId: \"sku-1\",\n updates: { name: \"Updated SKU\" },\n },\n {\n type: \"replace_sku_eans\" as const,\n skuId: \"sku-2\",\n eans: [\"111\", \"222\", \"111\"],\n },\n ];\n\n getMock.mockResolvedValueOnce({\n data: {\n Name: \"Original Product\",\n CategoryId: 10,\n BrandId: 20,\n },\n });\n putMock.mockResolvedValueOnce({\n data: {\n Id: \"product-1\",\n Name: \"Updated Product\",\n },\n });\n getMock.mockRejectedValueOnce(new Error(\"sku fetch failed\"));\n deleteMock.mockResolvedValueOnce({});\n postMock.mockResolvedValue({});\n getMock.mockResolvedValueOnce({ data: [\"111\", \"222\"] });\n\n await expect(catalogWrite.executeCatalogBatch(\"profile-1\", operations)).resolves.toEqual({\n successful: [\n {\n operation_index: 0,\n operation_type: \"update_product_basic_fields\",\n resource_id: \"product-1\",\n result: {\n Id: \"product-1\",\n Name: \"Updated Product\",\n },\n },\n {\n operation_index: 2,\n operation_type: \"replace_sku_eans\",\n resource_id: \"sku-2\",\n result: {\n eans: [\"111\", \"222\"],\n },\n },\n ],\n failed: [\n {\n operation_index: 1,\n operation_type: \"update_sku_basic_fields\",\n resource_id: \"sku-1\",\n message: \"sku fetch failed\",\n },\n ],\n });\n\n expect(deleteMock).toHaveBeenCalledWith(\"/api/catalog/pvt/stockkeepingunit/sku-2/ean\");\n expect(postMock).toHaveBeenNthCalledWith(\n 1,\n \"/api/catalog/pvt/stockkeepingunit/sku-2/ean/111\"\n );\n expect(postMock).toHaveBeenNthCalledWith(\n 2,\n \"/api/catalog/pvt/stockkeepingunit/sku-2/ean/222\"\n );\n expect(postMock).toHaveBeenCalledTimes(2);\n });\n});\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,233 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
- const resolveVtexProfileOrSelectionMock = vi.fn();
3
- const planCatalogBatchMock = vi.fn();
4
- const executeCatalogBatchMock = vi.fn();
5
- vi.mock("../profile-resolution.js", () => ({
6
- resolveVtexProfileOrSelection: resolveVtexProfileOrSelectionMock
7
- }));
8
- vi.mock("../../../services/vtex/vtex-catalog-write.js", () => ({
9
- planCatalogBatch: planCatalogBatchMock,
10
- executeCatalogBatch: executeCatalogBatchMock
11
- }));
12
- const moduleUnderTest = await import("../catalog-admin-batch.js");
13
- function getStructured(result) {
14
- if (result && typeof result === "object" && "structuredContent" in result) {
15
- return result.structuredContent;
16
- }
17
- return result;
18
- }
19
- describe("catalog-admin-batch", () => {
20
- beforeEach(() => {
21
- vi.clearAllMocks();
22
- resolveVtexProfileOrSelectionMock.mockResolvedValue({
23
- ok: true,
24
- value: { profileId: "profile-1" }
25
- });
26
- });
27
- it("auto-applies medium-risk batch after safe preflight", async () => {
28
- planCatalogBatchMock.mockResolvedValue({
29
- preflight: {
30
- entities: 2,
31
- entityTypes: ["product", "sku"],
32
- destructive: false,
33
- hasDeleteOrReplaceAll: false,
34
- dependencyFailureCount: 0,
35
- multiEntityCriticalReassignment: false
36
- },
37
- warnings: [],
38
- impactedEntityTypes: ["product", "sku"],
39
- before: [{ operation_index: 0, snapshot: { id: "10" } }],
40
- after: [{ operation_index: 0, snapshot: { id: "10", updated: true } }]
41
- });
42
- executeCatalogBatchMock.mockResolvedValue({
43
- successful: [
44
- {
45
- operation_index: 0,
46
- operation_type: "update_product_basic_fields",
47
- resource_id: "10",
48
- result: { ok: true }
49
- }
50
- ],
51
- failed: []
52
- });
53
- const result = await moduleUnderTest.catalogAdminBatchHandler({
54
- profileId: "profile-1",
55
- mode: "apply",
56
- requestedRiskLevel: "medium",
57
- operations: [
58
- {
59
- type: "update_product_basic_fields",
60
- productId: "10",
61
- updates: { name: "Updated" }
62
- }
63
- ]
64
- });
65
- expect(planCatalogBatchMock).toHaveBeenCalledWith("profile-1", [
66
- {
67
- type: "update_product_basic_fields",
68
- productId: "10",
69
- updates: { name: "Updated" }
70
- }
71
- ]);
72
- expect(executeCatalogBatchMock).toHaveBeenCalledTimes(1);
73
- const structured = getStructured(result);
74
- expect(structured).toMatchObject({
75
- success: true,
76
- operation: "catalog_admin_batch",
77
- requested_risk_level: "medium",
78
- risk_level: "medium",
79
- details: {
80
- mode: "apply",
81
- execution: {
82
- successful_count: 1,
83
- failed_count: 0
84
- }
85
- }
86
- });
87
- });
88
- it("escalates medium-risk requests to high and returns preview token", async () => {
89
- planCatalogBatchMock.mockResolvedValue({
90
- preflight: {
91
- entities: 12,
92
- entityTypes: ["product"],
93
- destructive: false,
94
- hasDeleteOrReplaceAll: false,
95
- dependencyFailureCount: 0,
96
- multiEntityCriticalReassignment: false
97
- },
98
- warnings: [],
99
- impactedEntityTypes: ["product"],
100
- before: [],
101
- after: []
102
- });
103
- const result = await moduleUnderTest.catalogAdminBatchHandler({
104
- profileId: "profile-1",
105
- mode: "preview",
106
- requestedRiskLevel: "medium",
107
- operations: [
108
- {
109
- type: "update_product_basic_fields",
110
- productId: "10",
111
- updates: { name: "Updated" }
112
- }
113
- ]
114
- });
115
- expect(executeCatalogBatchMock).not.toHaveBeenCalled();
116
- const structured = getStructured(result);
117
- expect(structured).toMatchObject({
118
- success: true,
119
- operation: "catalog_admin_batch",
120
- requested_risk_level: "medium",
121
- risk_level: "high",
122
- escalated: true
123
- });
124
- expect(structured.confirmation_requirements).toMatchObject({ required: true });
125
- expect(structured.details?.preview_id).toEqual(
126
- expect.any(String)
127
- );
128
- });
129
- it("blocks high-risk apply without preview id and explicit confirmation", async () => {
130
- planCatalogBatchMock.mockResolvedValue({
131
- preflight: {
132
- entities: 1,
133
- entityTypes: ["sku"],
134
- destructive: true,
135
- hasDeleteOrReplaceAll: true,
136
- dependencyFailureCount: 0,
137
- multiEntityCriticalReassignment: false
138
- },
139
- warnings: ["destructive_operation_detected"],
140
- impactedEntityTypes: ["sku"],
141
- before: [],
142
- after: []
143
- });
144
- const missingPreviewIdResult = await moduleUnderTest.catalogAdminBatchHandler({
145
- profileId: "profile-1",
146
- mode: "apply",
147
- requestedRiskLevel: "high",
148
- operations: [
149
- {
150
- type: "replace_sku_eans",
151
- skuId: "22",
152
- eans: ["7790011223344"]
153
- }
154
- ],
155
- confirmed: true
156
- });
157
- expect(getStructured(missingPreviewIdResult)).toMatchObject({
158
- success: false,
159
- error_code: "INVALID_OPERATION"
160
- });
161
- const expectedPreviewId = getStructured(missingPreviewIdResult).details?.expected_preview_id;
162
- const missingConfirmationResult = await moduleUnderTest.catalogAdminBatchHandler({
163
- profileId: "profile-1",
164
- mode: "apply",
165
- requestedRiskLevel: "high",
166
- previewId: expectedPreviewId,
167
- operations: [
168
- {
169
- type: "replace_sku_eans",
170
- skuId: "22",
171
- eans: ["7790011223344"]
172
- }
173
- ]
174
- });
175
- expect(getStructured(missingConfirmationResult)).toMatchObject({
176
- success: false,
177
- error_code: "EXPLICIT_CONFIRMATION_REQUIRED"
178
- });
179
- expect(executeCatalogBatchMock).not.toHaveBeenCalled();
180
- });
181
- it("adds partial-failure warnings when apply has failed operations", async () => {
182
- planCatalogBatchMock.mockResolvedValue({
183
- preflight: {
184
- entities: 1,
185
- entityTypes: ["sku"],
186
- destructive: false,
187
- hasDeleteOrReplaceAll: false,
188
- dependencyFailureCount: 0,
189
- multiEntityCriticalReassignment: false
190
- },
191
- warnings: [],
192
- impactedEntityTypes: ["sku"],
193
- before: [],
194
- after: []
195
- });
196
- executeCatalogBatchMock.mockResolvedValue({
197
- successful: [],
198
- failed: [
199
- {
200
- operation_index: 0,
201
- operation_type: "update_sku_basic_fields",
202
- resource_id: "22",
203
- message: "VTEX timeout"
204
- }
205
- ]
206
- });
207
- const result = await moduleUnderTest.catalogAdminBatchHandler({
208
- profileId: "profile-1",
209
- mode: "apply",
210
- requestedRiskLevel: "medium",
211
- operations: [
212
- {
213
- type: "update_sku_basic_fields",
214
- skuId: "22",
215
- updates: { name: "SKU v2" }
216
- }
217
- ]
218
- });
219
- const structured = getStructured(result);
220
- expect(structured).toMatchObject({
221
- success: true,
222
- warnings: expect.arrayContaining(["partial_failures_detected"]),
223
- details: {
224
- mode: "apply",
225
- execution: {
226
- successful_count: 0,
227
- failed_count: 1
228
- }
229
- }
230
- });
231
- });
232
- });
233
- //# sourceMappingURL=catalog-admin-batch.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../../src/tools/vtex/__tests__/catalog-admin-batch.test.ts"],
4
- "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst resolveVtexProfileOrSelectionMock = vi.fn();\n\nconst planCatalogBatchMock = vi.fn();\nconst executeCatalogBatchMock = vi.fn();\n\nvi.mock(\"../profile-resolution.js\", () => ({\n resolveVtexProfileOrSelection: resolveVtexProfileOrSelectionMock,\n}));\n\nvi.mock(\"../../../services/vtex/vtex-catalog-write.js\", () => ({\n planCatalogBatch: planCatalogBatchMock,\n executeCatalogBatch: executeCatalogBatchMock,\n}));\n\nconst moduleUnderTest = await import(\"../catalog-admin-batch.js\");\n\nfunction getStructured(result: unknown): Record<string, unknown> {\n if (result && typeof result === \"object\" && \"structuredContent\" in result) {\n return (result as { structuredContent: Record<string, unknown> }).structuredContent;\n }\n\n return result as Record<string, unknown>;\n}\n\ndescribe(\"catalog-admin-batch\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n resolveVtexProfileOrSelectionMock.mockResolvedValue({\n ok: true,\n value: { profileId: \"profile-1\" },\n });\n });\n\n it(\"auto-applies medium-risk batch after safe preflight\", async () => {\n planCatalogBatchMock.mockResolvedValue({\n preflight: {\n entities: 2,\n entityTypes: [\"product\", \"sku\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n warnings: [],\n impactedEntityTypes: [\"product\", \"sku\"],\n before: [{ operation_index: 0, snapshot: { id: \"10\" } }],\n after: [{ operation_index: 0, snapshot: { id: \"10\", updated: true } }],\n });\n\n executeCatalogBatchMock.mockResolvedValue({\n successful: [\n {\n operation_index: 0,\n operation_type: \"update_product_basic_fields\",\n resource_id: \"10\",\n result: { ok: true },\n },\n ],\n failed: [],\n });\n\n const result = await moduleUnderTest.catalogAdminBatchHandler({\n profileId: \"profile-1\",\n mode: \"apply\",\n requestedRiskLevel: \"medium\",\n operations: [\n {\n type: \"update_product_basic_fields\",\n productId: \"10\",\n updates: { name: \"Updated\" },\n },\n ],\n });\n\n expect(planCatalogBatchMock).toHaveBeenCalledWith(\"profile-1\", [\n {\n type: \"update_product_basic_fields\",\n productId: \"10\",\n updates: { name: \"Updated\" },\n },\n ]);\n expect(executeCatalogBatchMock).toHaveBeenCalledTimes(1);\n const structured = getStructured(result);\n\n expect(structured).toMatchObject({\n success: true,\n operation: \"catalog_admin_batch\",\n requested_risk_level: \"medium\",\n risk_level: \"medium\",\n details: {\n mode: \"apply\",\n execution: {\n successful_count: 1,\n failed_count: 0,\n },\n },\n });\n });\n\n it(\"escalates medium-risk requests to high and returns preview token\", async () => {\n planCatalogBatchMock.mockResolvedValue({\n preflight: {\n entities: 12,\n entityTypes: [\"product\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n warnings: [],\n impactedEntityTypes: [\"product\"],\n before: [],\n after: [],\n });\n\n const result = await moduleUnderTest.catalogAdminBatchHandler({\n profileId: \"profile-1\",\n mode: \"preview\",\n requestedRiskLevel: \"medium\",\n operations: [\n {\n type: \"update_product_basic_fields\",\n productId: \"10\",\n updates: { name: \"Updated\" },\n },\n ],\n });\n\n expect(executeCatalogBatchMock).not.toHaveBeenCalled();\n const structured = getStructured(result);\n\n expect(structured).toMatchObject({\n success: true,\n operation: \"catalog_admin_batch\",\n requested_risk_level: \"medium\",\n risk_level: \"high\",\n escalated: true,\n });\n expect(structured.confirmation_requirements).toMatchObject({ required: true });\n expect((structured.details as { preview_id?: string } | undefined)?.preview_id).toEqual(\n expect.any(String)\n );\n });\n\n it(\"blocks high-risk apply without preview id and explicit confirmation\", async () => {\n planCatalogBatchMock.mockResolvedValue({\n preflight: {\n entities: 1,\n entityTypes: [\"sku\"],\n destructive: true,\n hasDeleteOrReplaceAll: true,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n warnings: [\"destructive_operation_detected\"],\n impactedEntityTypes: [\"sku\"],\n before: [],\n after: [],\n });\n\n const missingPreviewIdResult = await moduleUnderTest.catalogAdminBatchHandler({\n profileId: \"profile-1\",\n mode: \"apply\",\n requestedRiskLevel: \"high\",\n operations: [\n {\n type: \"replace_sku_eans\",\n skuId: \"22\",\n eans: [\"7790011223344\"],\n },\n ],\n confirmed: true,\n });\n\n expect(getStructured(missingPreviewIdResult)).toMatchObject({\n success: false,\n error_code: \"INVALID_OPERATION\",\n });\n\n const expectedPreviewId = (\n getStructured(missingPreviewIdResult).details as { expected_preview_id?: string } | undefined\n )?.expected_preview_id;\n\n const missingConfirmationResult = await moduleUnderTest.catalogAdminBatchHandler({\n profileId: \"profile-1\",\n mode: \"apply\",\n requestedRiskLevel: \"high\",\n previewId: expectedPreviewId,\n operations: [\n {\n type: \"replace_sku_eans\",\n skuId: \"22\",\n eans: [\"7790011223344\"],\n },\n ],\n });\n\n expect(getStructured(missingConfirmationResult)).toMatchObject({\n success: false,\n error_code: \"EXPLICIT_CONFIRMATION_REQUIRED\",\n });\n expect(executeCatalogBatchMock).not.toHaveBeenCalled();\n });\n\n it(\"adds partial-failure warnings when apply has failed operations\", async () => {\n planCatalogBatchMock.mockResolvedValue({\n preflight: {\n entities: 1,\n entityTypes: [\"sku\"],\n destructive: false,\n hasDeleteOrReplaceAll: false,\n dependencyFailureCount: 0,\n multiEntityCriticalReassignment: false,\n },\n warnings: [],\n impactedEntityTypes: [\"sku\"],\n before: [],\n after: [],\n });\n\n executeCatalogBatchMock.mockResolvedValue({\n successful: [],\n failed: [\n {\n operation_index: 0,\n operation_type: \"update_sku_basic_fields\",\n resource_id: \"22\",\n message: \"VTEX timeout\",\n },\n ],\n });\n\n const result = await moduleUnderTest.catalogAdminBatchHandler({\n profileId: \"profile-1\",\n mode: \"apply\",\n requestedRiskLevel: \"medium\",\n operations: [\n {\n type: \"update_sku_basic_fields\",\n skuId: \"22\",\n updates: { name: \"SKU v2\" },\n },\n ],\n });\n\n const structured = getStructured(result);\n\n expect(structured).toMatchObject({\n success: true,\n warnings: expect.arrayContaining([\"partial_failures_detected\"]),\n details: {\n mode: \"apply\",\n execution: {\n successful_count: 0,\n failed_count: 1,\n },\n },\n });\n });\n});\n"],
5
- "mappings": "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",
6
- "names": []
7
- }