@yoryoboy/bi-mcp 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +87 -87
  2. package/bin/bi-mcp.js +9 -9
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp-use.json +2 -2
  7. package/dist/public/icon.svg +6 -6
  8. package/dist/scripts/_helpers.js.map +1 -1
  9. package/dist/scripts/admin-profile-delete.js.map +1 -1
  10. package/dist/scripts/admin-profile-list.js.map +1 -1
  11. package/dist/scripts/admin-profile-upsert.js.map +1 -1
  12. package/dist/scripts/admin-vtex-list.js.map +1 -1
  13. package/dist/scripts/admin-vtex-upsert.js.map +1 -1
  14. package/dist/scripts/admin-vtex-validate.js.map +1 -1
  15. package/dist/scripts/run-migrations.js.map +1 -1
  16. package/dist/scripts/test-db-connection.js.map +1 -1
  17. package/dist/src/analytics/ga4-channel-groups.js.map +1 -1
  18. package/dist/src/analytics/ga4-report-utils.js.map +1 -1
  19. package/dist/src/config/benchmarks.js.map +1 -1
  20. package/dist/src/config/google-store.js.map +1 -1
  21. package/dist/src/config/google.js.map +1 -1
  22. package/dist/src/config/mercadolibre-profile-store.js.map +1 -1
  23. package/dist/src/config/mercadolibre.js.map +1 -1
  24. package/dist/src/config/meta.js.map +1 -1
  25. package/dist/src/config/profile-store.js.map +1 -1
  26. package/dist/src/config/vtex-crypto.js.map +1 -1
  27. package/dist/src/config/vtex-profile-store.js.map +1 -1
  28. package/dist/src/config/vtex.js.map +1 -1
  29. package/dist/src/db/client.js.map +1 -1
  30. package/dist/src/google-ads/report-utils.js +78 -0
  31. package/dist/src/google-ads/report-utils.js.map +7 -0
  32. package/dist/src/meta/meta-utils.js.map +1 -1
  33. package/dist/src/prompts/reporte-ventas.js.map +1 -1
  34. package/dist/src/search-console/search-console-utils.js +275 -0
  35. package/dist/src/search-console/search-console-utils.js.map +7 -0
  36. package/dist/src/services/analytics/ga4-client.js.map +1 -1
  37. package/dist/src/services/analytics/oauth.js.map +1 -1
  38. package/dist/src/services/google-ads/google-ads-client.js.map +1 -1
  39. package/dist/src/services/mercadolibre/mercadolibre-api.js.map +1 -1
  40. package/dist/src/services/mercadolibre/mercadolibre-items.js.map +1 -1
  41. package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +1 -1
  42. package/dist/src/services/mercadolibre/mercadolibre-questions.js.map +1 -1
  43. package/dist/src/services/meta/meta-ads.js.map +1 -1
  44. package/dist/src/services/meta/meta-api.js.map +1 -1
  45. package/dist/src/services/search-console/search-console-client.js.map +1 -1
  46. package/dist/src/services/search-console/search-console-utils.js.map +1 -1
  47. package/dist/src/services/vtex/vtex-api.js.map +1 -1
  48. package/dist/src/services/vtex/vtex-catalog-write.js.map +1 -1
  49. package/dist/src/services/vtex/vtex-catalog.js.map +1 -1
  50. package/dist/src/services/vtex/vtex-logistics.js.map +1 -1
  51. package/dist/src/services/vtex/vtex-orders-write.js.map +1 -1
  52. package/dist/src/services/vtex/vtex-orders.js.map +1 -1
  53. package/dist/src/services/vtex/vtex-pricing-write.js.map +1 -1
  54. package/dist/src/services/vtex/vtex-pricing.js.map +1 -1
  55. package/dist/src/services/vtex/vtex-write.js.map +1 -1
  56. package/dist/src/tools/analytics/attribution-gaps.js.map +1 -1
  57. package/dist/src/tools/analytics/channel-mix.js.map +1 -1
  58. package/dist/src/tools/analytics/ecommerce-tracking-health.js.map +1 -1
  59. package/dist/src/tools/analytics/engagement-overview.js.map +1 -1
  60. package/dist/src/tools/analytics/index.js.map +1 -1
  61. package/dist/src/tools/analytics/list-accessible-properties.js.map +1 -1
  62. package/dist/src/tools/analytics/property-info.js.map +1 -1
  63. package/dist/src/tools/analytics/revenue-by-channel.js.map +1 -1
  64. package/dist/src/tools/analytics/revenue-overview.js.map +1 -1
  65. package/dist/src/tools/analytics/revenue-trend.js.map +1 -1
  66. package/dist/src/tools/analytics/source-medium-breakdown.js.map +1 -1
  67. package/dist/src/tools/analytics/top-landing-pages.js.map +1 -1
  68. package/dist/src/tools/config/check-database-connection.js.map +1 -1
  69. package/dist/src/tools/config/index.js.map +1 -1
  70. package/dist/src/tools/config/list-profiles.js.map +1 -1
  71. package/dist/src/tools/google-ads/account-overview.js.map +1 -1
  72. package/dist/src/tools/google-ads/account-risks.js.map +1 -1
  73. package/dist/src/tools/google-ads/break-even-analysis.js.map +1 -1
  74. package/dist/src/tools/google-ads/campaign-performance.js.map +1 -1
  75. package/dist/src/tools/google-ads/channel-mix.js.map +1 -1
  76. package/dist/src/tools/google-ads/compare-accounts.js.map +1 -1
  77. package/dist/src/tools/google-ads/customer-clients.js.map +1 -1
  78. package/dist/src/tools/google-ads/customer-info.js.map +1 -1
  79. package/dist/src/tools/google-ads/index.js.map +1 -1
  80. package/dist/src/tools/google-ads/scaling-health.js.map +1 -1
  81. package/dist/src/tools/google-ads/search-terms-summary.js.map +1 -1
  82. package/dist/src/tools/google-ads/time-series.js.map +1 -1
  83. package/dist/src/tools/index.js.map +1 -1
  84. package/dist/src/tools/mercadolibre/answer-question.js.map +1 -1
  85. package/dist/src/tools/mercadolibre/create-item.js.map +1 -1
  86. package/dist/src/tools/mercadolibre/estimate-listing-fee.js.map +1 -1
  87. package/dist/src/tools/mercadolibre/get-account-context.js.map +1 -1
  88. package/dist/src/tools/mercadolibre/get-category-requirements.js.map +1 -1
  89. package/dist/src/tools/mercadolibre/get-item-details.js.map +1 -1
  90. package/dist/src/tools/mercadolibre/get-item-visits.js.map +1 -1
  91. package/dist/src/tools/mercadolibre/get-listing-quality.js.map +1 -1
  92. package/dist/src/tools/mercadolibre/get-order-details.js.map +1 -1
  93. package/dist/src/tools/mercadolibre/get-orders-summary.js +366 -28
  94. package/dist/src/tools/mercadolibre/get-orders-summary.js.map +2 -2
  95. package/dist/src/tools/mercadolibre/get-sales-by-item.js.map +1 -1
  96. package/dist/src/tools/mercadolibre/get-sales-trend.js.map +1 -1
  97. package/dist/src/tools/mercadolibre/get-shipping-summary.js.map +1 -1
  98. package/dist/src/tools/mercadolibre/get-store-performance.js.map +1 -1
  99. package/dist/src/tools/mercadolibre/helpers.js.map +1 -1
  100. package/dist/src/tools/mercadolibre/index.js.map +1 -1
  101. package/dist/src/tools/mercadolibre/pause-or-reactivate-item.js.map +1 -1
  102. package/dist/src/tools/mercadolibre/predict-category.js.map +1 -1
  103. package/dist/src/tools/mercadolibre/profile-resolution.js.map +1 -1
  104. package/dist/src/tools/mercadolibre/search-items.js.map +1 -1
  105. package/dist/src/tools/mercadolibre/search-questions.js.map +1 -1
  106. package/dist/src/tools/mercadolibre/update-item-basic-fields.js.map +1 -1
  107. package/dist/src/tools/mercadolibre/update-item-description.js.map +1 -1
  108. package/dist/src/tools/mercadolibre/update-item-pictures.js.map +1 -1
  109. package/dist/src/tools/mercadolibre/validate-connection.js.map +1 -1
  110. package/dist/src/tools/mercadolibre/write-helpers.js.map +1 -1
  111. package/dist/src/tools/meta/account-overview.js.map +1 -1
  112. package/dist/src/tools/meta/ad-account-info.js.map +1 -1
  113. package/dist/src/tools/meta/ads-performance.js.map +1 -1
  114. package/dist/src/tools/meta/campaign-performance.js.map +1 -1
  115. package/dist/src/tools/meta/index.js.map +1 -1
  116. package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +1 -1
  117. package/dist/src/tools/meta/list-accessible-businesses.js.map +1 -1
  118. package/dist/src/tools/meta/placement-mix.js.map +1 -1
  119. package/dist/src/tools/meta/time-series.js.map +1 -1
  120. package/dist/src/tools/search-console/country-breakdown.js.map +1 -1
  121. package/dist/src/tools/search-console/device-breakdown.js.map +1 -1
  122. package/dist/src/tools/search-console/high-impression-low-click-queries.js.map +1 -1
  123. package/dist/src/tools/search-console/index.js.map +1 -1
  124. package/dist/src/tools/search-console/list-accessible-sites.js.map +1 -1
  125. package/dist/src/tools/search-console/low-ctr-opportunities.js.map +1 -1
  126. package/dist/src/tools/search-console/page-performance.js.map +1 -1
  127. package/dist/src/tools/search-console/product-demand-low-capture-queries.js.map +1 -1
  128. package/dist/src/tools/search-console/query-page-matrix.js.map +1 -1
  129. package/dist/src/tools/search-console/query-performance.js.map +1 -1
  130. package/dist/src/tools/search-console/quick-win-opportunities.js.map +1 -1
  131. package/dist/src/tools/search-console/rising-non-brand-queries.js.map +1 -1
  132. package/dist/src/tools/search-console/search-performance.js.map +1 -1
  133. package/dist/src/tools/search-console/site-context.js.map +1 -1
  134. package/dist/src/tools/search-console/visibility-declines.js.map +1 -1
  135. package/dist/src/tools/vtex/activate-sku.js.map +1 -1
  136. package/dist/src/tools/vtex/add-order-tracking.js.map +1 -1
  137. package/dist/src/tools/vtex/associate-specification.js.map +1 -1
  138. package/dist/src/tools/vtex/attach-catalog-image.js.map +1 -1
  139. package/dist/src/tools/vtex/cancel-order.js.map +1 -1
  140. package/dist/src/tools/vtex/computed-price.js.map +1 -1
  141. package/dist/src/tools/vtex/create-brand.js.map +1 -1
  142. package/dist/src/tools/vtex/create-category.js.map +1 -1
  143. package/dist/src/tools/vtex/create-product-with-sku.js.map +1 -1
  144. package/dist/src/tools/vtex/create-product.js.map +1 -1
  145. package/dist/src/tools/vtex/create-sku.js.map +1 -1
  146. package/dist/src/tools/vtex/create-specification-value.js.map +1 -1
  147. package/dist/src/tools/vtex/create-specification.js.map +1 -1
  148. package/dist/src/tools/vtex/deactivate-sku.js.map +1 -1
  149. package/dist/src/tools/vtex/delete-fixed-price.js.map +1 -1
  150. package/dist/src/tools/vtex/index.js.map +1 -1
  151. package/dist/src/tools/vtex/inventory-check.js.map +1 -1
  152. package/dist/src/tools/vtex/invoice-order.js.map +1 -1
  153. package/dist/src/tools/vtex/order-details.js.map +1 -1
  154. package/dist/src/tools/vtex/orders-summary.js.map +1 -1
  155. package/dist/src/tools/vtex/product-offers.js.map +1 -1
  156. package/dist/src/tools/vtex/profile-resolution.js.map +1 -1
  157. package/dist/src/tools/vtex/sku-offers.js.map +1 -1
  158. package/dist/src/tools/vtex/sku-price.js.map +1 -1
  159. package/dist/src/tools/vtex/toggle-unlimited-quantity.js.map +1 -1
  160. package/dist/src/tools/vtex/update-inventory.js.map +1 -1
  161. package/dist/src/tools/vtex/update-lead-time.js.map +1 -1
  162. package/dist/src/tools/vtex/update-product-basic-fields.js.map +1 -1
  163. package/dist/src/tools/vtex/update-sku-basic-fields.js.map +1 -1
  164. package/dist/src/tools/vtex/update-sku-price.js.map +1 -1
  165. package/dist/src/tools/vtex/upsert-fixed-price.js.map +1 -1
  166. package/dist/src/tools/vtex/warehouse-inventory.js.map +1 -1
  167. package/dist/src/tools/vtex/write-helpers.js.map +1 -1
  168. package/dist/src/utils/case-conversion.js.map +1 -1
  169. package/dist/src/utils/currency.js.map +1 -1
  170. package/dist/src/utils/format-order-details.js.map +1 -1
  171. package/dist/src/utils/google-ads.js.map +1 -1
  172. package/dist/src/utils/money.js.map +1 -1
  173. package/dist/src/utils/order-status.js.map +1 -1
  174. package/dist/src/utils/pagination.js.map +1 -1
  175. package/dist/src/utils/strip-payload.js.map +1 -1
  176. package/dist/src/utils/type-guards.js.map +1 -1
  177. package/package.json +1 -1
  178. package/public/icon.svg +6 -6
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/meta/meta-ads.ts"],
4
- "sourcesContent": ["import { metaFetch, type MetaListResponse } from \"./meta-api.js\";\r\nimport { normalizeMetaAdAccountId, toActId } from \"../../meta/meta-utils.js\";\r\n\r\nexport interface MetaBusiness {\r\n id?: string;\r\n name?: string;\r\n verification_status?: string;\r\n}\r\n\r\nexport interface MetaBusinessRef {\r\n id?: string;\r\n name?: string;\r\n}\r\n\r\nexport interface MetaAdAccount {\r\n id?: string;\r\n account_id?: string;\r\n name?: string;\r\n currency?: string;\r\n account_status?: number;\r\n timezone_name?: string;\r\n timezone_offset_hours_utc?: number;\r\n business?: MetaBusinessRef;\r\n}\r\n\r\nexport interface MetaActionMetric {\r\n action_type?: string;\r\n value?: string;\r\n}\r\n\r\nexport interface MetaRoasMetric {\r\n action_type?: string;\r\n value?: string;\r\n}\r\n\r\nexport interface MetaAdInsight {\r\n date_start?: string;\r\n date_stop?: string;\r\n impressions?: string;\r\n reach?: string;\r\n clicks?: string;\r\n spend?: string;\r\n ctr?: string;\r\n cpc?: string;\r\n cpm?: string;\r\n actions?: MetaActionMetric[];\r\n action_values?: MetaActionMetric[];\r\n purchase_roas?: MetaRoasMetric[];\r\n}\r\n\r\nexport interface MetaCampaign {\r\n id?: string;\r\n name?: string;\r\n status?: string;\r\n effective_status?: string;\r\n objective?: string;\r\n}\r\n\r\nexport interface MetaAd {\r\n id?: string;\r\n name?: string;\r\n status?: string;\r\n effective_status?: string;\r\n creative?: {\r\n id?: string;\r\n };\r\n}\r\n\r\nexport interface MetaPlacementRow extends MetaAdInsight {\r\n publisher_platform?: string;\r\n platform_position?: string;\r\n impression_device?: string;\r\n}\r\n\r\nfunction decodePagingCursor(url: string | undefined): string | undefined {\r\n if (!url) {\r\n return undefined;\r\n }\r\n\r\n try {\r\n return new URL(url).searchParams.get(\"after\") || undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nexport async function listAccessibleMetaBusinesses(after?: string) {\r\n const response = await metaFetch<MetaListResponse<MetaBusiness>>(\"/me/businesses\", {\r\n fields: \"id,name,verification_status\",\r\n limit: 100,\r\n after,\r\n });\r\n\r\n return {\r\n businesses: response.data ?? [],\r\n paging: {\r\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\r\n before: response.paging?.cursors?.before,\r\n has_more: Boolean(response.paging?.next),\r\n },\r\n };\r\n}\r\n\r\nexport async function listAccessibleMetaAdAccounts(after?: string) {\r\n const response = await metaFetch<MetaListResponse<MetaAdAccount>>(\"/me/adaccounts\", {\r\n fields:\r\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name}\",\r\n limit: 100,\r\n after,\r\n });\r\n\r\n const accounts = (response.data ?? []).map((account) => ({\r\n ...account,\r\n account_id: account.account_id || normalizeMetaAdAccountId(account.id || \"\"),\r\n }));\r\n\r\n return {\r\n adAccounts: accounts,\r\n paging: {\r\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\r\n before: response.paging?.cursors?.before,\r\n has_more: Boolean(response.paging?.next),\r\n },\r\n };\r\n}\r\n\r\nexport async function getMetaAdAccountInfo(adAccountId: string): Promise<MetaAdAccount> {\r\n return metaFetch<MetaAdAccount>(`/${toActId(adAccountId)}`, {\r\n fields:\r\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name},amount_spent,balance,spend_cap\",\r\n });\r\n}\r\n\r\nexport async function getMetaInsights(\r\n objectId: string,\r\n params: Record<string, string | number | undefined>\r\n): Promise<MetaAdInsight[]> {\r\n const response = await metaFetch<MetaListResponse<MetaAdInsight>>(`/${objectId}/insights`, {\r\n fields:\r\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas,date_start,date_stop\",\r\n ...params,\r\n });\r\n\r\n return response.data ?? [];\r\n}\r\n\r\nexport async function getMetaCampaigns(adAccountId: string, limit = 50): Promise<MetaCampaign[]> {\r\n const response = await metaFetch<MetaListResponse<MetaCampaign>>(`/${toActId(adAccountId)}/campaigns`, {\r\n fields: \"id,name,status,effective_status,objective\",\r\n limit,\r\n });\r\n\r\n return response.data ?? [];\r\n}\r\n\r\nexport async function getMetaAds(adAccountId: string, limit = 50): Promise<MetaAd[]> {\r\n const response = await metaFetch<MetaListResponse<MetaAd>>(`/${toActId(adAccountId)}/ads`, {\r\n fields: \"id,name,status,effective_status,creative{id}\",\r\n limit,\r\n });\r\n\r\n return response.data ?? [];\r\n}\r\n\r\nexport async function getMetaPlacementInsights(\r\n adAccountId: string,\r\n params: Record<string, string | number | undefined>\r\n): Promise<MetaPlacementRow[]> {\r\n const response = await metaFetch<MetaListResponse<MetaPlacementRow>>(`/${toActId(adAccountId)}/insights`, {\r\n fields:\r\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas\",\r\n ...params,\r\n });\r\n\r\n return response.data ?? [];\r\n}\r\n"],
4
+ "sourcesContent": ["import { metaFetch, type MetaListResponse } from \"./meta-api.js\";\nimport { normalizeMetaAdAccountId, toActId } from \"../../meta/meta-utils.js\";\n\nexport interface MetaBusiness {\n id?: string;\n name?: string;\n verification_status?: string;\n}\n\nexport interface MetaBusinessRef {\n id?: string;\n name?: string;\n}\n\nexport interface MetaAdAccount {\n id?: string;\n account_id?: string;\n name?: string;\n currency?: string;\n account_status?: number;\n timezone_name?: string;\n timezone_offset_hours_utc?: number;\n business?: MetaBusinessRef;\n}\n\nexport interface MetaActionMetric {\n action_type?: string;\n value?: string;\n}\n\nexport interface MetaRoasMetric {\n action_type?: string;\n value?: string;\n}\n\nexport interface MetaAdInsight {\n date_start?: string;\n date_stop?: string;\n impressions?: string;\n reach?: string;\n clicks?: string;\n spend?: string;\n ctr?: string;\n cpc?: string;\n cpm?: string;\n actions?: MetaActionMetric[];\n action_values?: MetaActionMetric[];\n purchase_roas?: MetaRoasMetric[];\n}\n\nexport interface MetaCampaign {\n id?: string;\n name?: string;\n status?: string;\n effective_status?: string;\n objective?: string;\n}\n\nexport interface MetaAd {\n id?: string;\n name?: string;\n status?: string;\n effective_status?: string;\n creative?: {\n id?: string;\n };\n}\n\nexport interface MetaPlacementRow extends MetaAdInsight {\n publisher_platform?: string;\n platform_position?: string;\n impression_device?: string;\n}\n\nfunction decodePagingCursor(url: string | undefined): string | undefined {\n if (!url) {\n return undefined;\n }\n\n try {\n return new URL(url).searchParams.get(\"after\") || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport async function listAccessibleMetaBusinesses(after?: string) {\n const response = await metaFetch<MetaListResponse<MetaBusiness>>(\"/me/businesses\", {\n fields: \"id,name,verification_status\",\n limit: 100,\n after,\n });\n\n return {\n businesses: response.data ?? [],\n paging: {\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\n before: response.paging?.cursors?.before,\n has_more: Boolean(response.paging?.next),\n },\n };\n}\n\nexport async function listAccessibleMetaAdAccounts(after?: string) {\n const response = await metaFetch<MetaListResponse<MetaAdAccount>>(\"/me/adaccounts\", {\n fields:\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name}\",\n limit: 100,\n after,\n });\n\n const accounts = (response.data ?? []).map((account) => ({\n ...account,\n account_id: account.account_id || normalizeMetaAdAccountId(account.id || \"\"),\n }));\n\n return {\n adAccounts: accounts,\n paging: {\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\n before: response.paging?.cursors?.before,\n has_more: Boolean(response.paging?.next),\n },\n };\n}\n\nexport async function getMetaAdAccountInfo(adAccountId: string): Promise<MetaAdAccount> {\n return metaFetch<MetaAdAccount>(`/${toActId(adAccountId)}`, {\n fields:\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name},amount_spent,balance,spend_cap\",\n });\n}\n\nexport async function getMetaInsights(\n objectId: string,\n params: Record<string, string | number | undefined>\n): Promise<MetaAdInsight[]> {\n const response = await metaFetch<MetaListResponse<MetaAdInsight>>(`/${objectId}/insights`, {\n fields:\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas,date_start,date_stop\",\n ...params,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaCampaigns(adAccountId: string, limit = 50): Promise<MetaCampaign[]> {\n const response = await metaFetch<MetaListResponse<MetaCampaign>>(`/${toActId(adAccountId)}/campaigns`, {\n fields: \"id,name,status,effective_status,objective\",\n limit,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaAds(adAccountId: string, limit = 50): Promise<MetaAd[]> {\n const response = await metaFetch<MetaListResponse<MetaAd>>(`/${toActId(adAccountId)}/ads`, {\n fields: \"id,name,status,effective_status,creative{id}\",\n limit,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaPlacementInsights(\n adAccountId: string,\n params: Record<string, string | number | undefined>\n): Promise<MetaPlacementRow[]> {\n const response = await metaFetch<MetaListResponse<MetaPlacementRow>>(`/${toActId(adAccountId)}/insights`, {\n fields:\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas\",\n ...params,\n });\n\n return response.data ?? [];\n}\n"],
5
5
  "mappings": "AAAA,SAAS,iBAAwC;AACjD,SAAS,0BAA0B,eAAe;AAyElD,SAAS,mBAAmB,KAA6C;AACvE,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,OAAO,KAAK;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,6BAA6B,OAAgB;AACjE,QAAM,WAAW,MAAM,UAA0C,kBAAkB;AAAA,IACjF,QAAQ;AAAA,IACR,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,YAAY,SAAS,QAAQ,CAAC;AAAA,IAC9B,QAAQ;AAAA,MACN,OAAO,SAAS,QAAQ,SAAS,SAAS,mBAAmB,SAAS,QAAQ,IAAI;AAAA,MAClF,QAAQ,SAAS,QAAQ,SAAS;AAAA,MAClC,UAAU,QAAQ,SAAS,QAAQ,IAAI;AAAA,IACzC;AAAA,EACF;AACF;AAEA,eAAsB,6BAA6B,OAAgB;AACjE,QAAM,WAAW,MAAM,UAA2C,kBAAkB;AAAA,IAClF,QACE;AAAA,IACF,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AAED,QAAM,YAAY,SAAS,QAAQ,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,IACvD,GAAG;AAAA,IACH,YAAY,QAAQ,cAAc,yBAAyB,QAAQ,MAAM,EAAE;AAAA,EAC7E,EAAE;AAEF,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,QAAQ;AAAA,MACN,OAAO,SAAS,QAAQ,SAAS,SAAS,mBAAmB,SAAS,QAAQ,IAAI;AAAA,MAClF,QAAQ,SAAS,QAAQ,SAAS;AAAA,MAClC,UAAU,QAAQ,SAAS,QAAQ,IAAI;AAAA,IACzC;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,aAA6C;AACtF,SAAO,UAAyB,IAAI,QAAQ,WAAW,CAAC,IAAI;AAAA,IAC1D,QACE;AAAA,EACJ,CAAC;AACH;AAEA,eAAsB,gBACpB,UACA,QAC0B;AAC1B,QAAM,WAAW,MAAM,UAA2C,IAAI,QAAQ,aAAa;AAAA,IACzF,QACE;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,iBAAiB,aAAqB,QAAQ,IAA6B;AAC/F,QAAM,WAAW,MAAM,UAA0C,IAAI,QAAQ,WAAW,CAAC,cAAc;AAAA,IACrG,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,WAAW,aAAqB,QAAQ,IAAuB;AACnF,QAAM,WAAW,MAAM,UAAoC,IAAI,QAAQ,WAAW,CAAC,QAAQ;AAAA,IACzF,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,yBACpB,aACA,QAC6B;AAC7B,QAAM,WAAW,MAAM,UAA8C,IAAI,QAAQ,WAAW,CAAC,aAAa;AAAA,IACxG,QACE;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/meta/meta-api.ts"],
4
- "sourcesContent": ["import { createMetaAppSecretProof, getMetaConfig } from \"../../config/meta.js\";\r\n\r\ninterface MetaErrorPayload {\r\n error?: {\r\n message?: string;\r\n type?: string;\r\n code?: number;\r\n error_subcode?: number;\r\n error_user_title?: string;\r\n error_user_msg?: string;\r\n fbtrace_id?: string;\r\n };\r\n}\r\n\r\nexport interface MetaPagingCursor {\r\n before?: string;\r\n after?: string;\r\n}\r\n\r\nexport interface MetaPaging {\r\n cursors?: MetaPagingCursor;\r\n next?: string;\r\n previous?: string;\r\n}\r\n\r\nexport interface MetaListResponse<T> {\r\n data?: T[];\r\n paging?: MetaPaging;\r\n}\r\n\r\nfunction buildUrl(path: string, query: Record<string, string | number | undefined>): string {\r\n const config = getMetaConfig();\r\n const accessToken = config.accessToken;\r\n const appSecretProof = createMetaAppSecretProof(accessToken, config.appSecret);\r\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\r\n const searchParams = new URLSearchParams();\r\n\r\n searchParams.set(\"access_token\", accessToken);\r\n searchParams.set(\"appsecret_proof\", appSecretProof);\r\n\r\n for (const [key, value] of Object.entries(query)) {\r\n if (value === undefined || value === null || value === \"\") {\r\n continue;\r\n }\r\n\r\n searchParams.set(key, String(value));\r\n }\r\n\r\n return `${config.baseUrl}${normalizedPath}?${searchParams.toString()}`;\r\n}\r\n\r\nexport async function metaFetch<T>(\r\n path: string,\r\n query: Record<string, string | number | undefined> = {}\r\n): Promise<T> {\r\n const response = await fetch(buildUrl(path, query), {\r\n method: \"GET\",\r\n headers: {\r\n Accept: \"application/json\",\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n const payload = (await response.json().catch(() => ({}))) as MetaErrorPayload;\r\n const message =\r\n payload.error?.error_user_msg ||\r\n payload.error?.error_user_title ||\r\n payload.error?.message ||\r\n `Meta API request failed with status ${response.status}`;\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return (await response.json()) as T;\r\n}\r\n"],
4
+ "sourcesContent": ["import { createMetaAppSecretProof, getMetaConfig } from \"../../config/meta.js\";\n\ninterface MetaErrorPayload {\n error?: {\n message?: string;\n type?: string;\n code?: number;\n error_subcode?: number;\n error_user_title?: string;\n error_user_msg?: string;\n fbtrace_id?: string;\n };\n}\n\nexport interface MetaPagingCursor {\n before?: string;\n after?: string;\n}\n\nexport interface MetaPaging {\n cursors?: MetaPagingCursor;\n next?: string;\n previous?: string;\n}\n\nexport interface MetaListResponse<T> {\n data?: T[];\n paging?: MetaPaging;\n}\n\nfunction buildUrl(path: string, query: Record<string, string | number | undefined>): string {\n const config = getMetaConfig();\n const accessToken = config.accessToken;\n const appSecretProof = createMetaAppSecretProof(accessToken, config.appSecret);\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n const searchParams = new URLSearchParams();\n\n searchParams.set(\"access_token\", accessToken);\n searchParams.set(\"appsecret_proof\", appSecretProof);\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null || value === \"\") {\n continue;\n }\n\n searchParams.set(key, String(value));\n }\n\n return `${config.baseUrl}${normalizedPath}?${searchParams.toString()}`;\n}\n\nexport async function metaFetch<T>(\n path: string,\n query: Record<string, string | number | undefined> = {}\n): Promise<T> {\n const response = await fetch(buildUrl(path, query), {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as MetaErrorPayload;\n const message =\n payload.error?.error_user_msg ||\n payload.error?.error_user_title ||\n payload.error?.message ||\n `Meta API request failed with status ${response.status}`;\n\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n"],
5
5
  "mappings": "AAAA,SAAS,0BAA0B,qBAAqB;AA8BxD,SAAS,SAAS,MAAc,OAA4D;AAC1F,QAAM,SAAS,cAAc;AAC7B,QAAM,cAAc,OAAO;AAC3B,QAAM,iBAAiB,yBAAyB,aAAa,OAAO,SAAS;AAC7E,QAAM,iBAAiB,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAC7D,QAAM,eAAe,IAAI,gBAAgB;AAEzC,eAAa,IAAI,gBAAgB,WAAW;AAC5C,eAAa,IAAI,mBAAmB,cAAc;AAElD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD;AAAA,IACF;AAEA,iBAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EACrC;AAEA,SAAO,GAAG,OAAO,OAAO,GAAG,cAAc,IAAI,aAAa,SAAS,CAAC;AACtE;AAEA,eAAsB,UACpB,MACA,QAAqD,CAAC,GAC1C;AACZ,QAAM,WAAW,MAAM,MAAM,SAAS,MAAM,KAAK,GAAG;AAAA,IAClD,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAW,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACvD,UAAM,UACJ,QAAQ,OAAO,kBACf,QAAQ,OAAO,oBACf,QAAQ,OAAO,WACf,uCAAuC,SAAS,MAAM;AAExD,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/search-console/search-console-client.ts"],
4
- "sourcesContent": ["import { refreshGoogleAccessToken } from \"../analytics/oauth.js\";\r\n\r\nconst SEARCH_CONSOLE_BASE_URL = \"https://www.googleapis.com/webmasters/v3\";\r\n\r\nexport interface SearchConsoleSiteEntry {\r\n siteUrl: string;\r\n permissionLevel?: string;\r\n}\r\n\r\nexport interface SearchConsoleSitesListResponse {\r\n siteEntry?: SearchConsoleSiteEntry[];\r\n}\r\n\r\nexport interface SearchConsoleDimensionFilter {\r\n dimension: string;\r\n operator: string;\r\n expression: string;\r\n}\r\n\r\nexport interface SearchConsoleDimensionFilterGroup {\r\n groupType?: string;\r\n filters: SearchConsoleDimensionFilter[];\r\n}\r\n\r\nexport interface SearchConsoleSearchAnalyticsRequest {\r\n startDate: string;\r\n endDate: string;\r\n dimensions?: string[];\r\n type?: string;\r\n dimensionFilterGroups?: SearchConsoleDimensionFilterGroup[];\r\n aggregationType?: string;\r\n rowLimit?: number;\r\n startRow?: number;\r\n}\r\n\r\nexport interface SearchConsoleSearchAnalyticsRow {\r\n keys?: string[];\r\n clicks?: number;\r\n impressions?: number;\r\n ctr?: number;\r\n position?: number;\r\n}\r\n\r\nexport interface SearchConsoleSearchAnalyticsResponse {\r\n rows?: SearchConsoleSearchAnalyticsRow[];\r\n responseAggregationType?: string;\r\n}\r\n\r\ninterface GoogleApiErrorPayload {\r\n error?: {\r\n code?: number;\r\n message?: string;\r\n status?: string;\r\n };\r\n}\r\n\r\nasync function googleApiFetch<T>(url: string, init?: RequestInit): Promise<T> {\r\n const accessToken = await refreshGoogleAccessToken();\r\n\r\n const response = await fetch(url, {\r\n ...init,\r\n headers: {\r\n Authorization: `Bearer ${accessToken.accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n ...(init?.headers ?? {}),\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n const payload = (await response.json().catch(() => ({}))) as GoogleApiErrorPayload;\r\n const message =\r\n payload.error?.message ??\r\n payload.error?.status ??\r\n `Google Search Console API request failed with status ${response.status}`;\r\n\r\n const normalizedMessage = message.toLowerCase();\r\n if (\r\n response.status === 403 &&\r\n normalizedMessage.includes(\"insufficient authentication scopes\")\r\n ) {\r\n throw new Error(\r\n \"Request had insufficient authentication scopes. Reconnect the Google OAuth credentials with Search Console scope https://www.googleapis.com/auth/webmasters.readonly or https://www.googleapis.com/auth/webmasters.\"\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return (await response.json()) as T;\r\n}\r\n\r\nexport async function listSearchConsoleSites(): Promise<SearchConsoleSiteEntry[]> {\r\n const payload = await googleApiFetch<SearchConsoleSitesListResponse>(\r\n `${SEARCH_CONSOLE_BASE_URL}/sites`\r\n );\r\n\r\n return payload.siteEntry ?? [];\r\n}\r\n\r\nexport async function querySearchConsolePerformance(\r\n siteUrl: string,\r\n body: SearchConsoleSearchAnalyticsRequest\r\n): Promise<SearchConsoleSearchAnalyticsResponse> {\r\n return googleApiFetch<SearchConsoleSearchAnalyticsResponse>(\r\n `${SEARCH_CONSOLE_BASE_URL}/sites/${encodeURIComponent(siteUrl)}/searchAnalytics/query`,\r\n {\r\n method: \"POST\",\r\n body: JSON.stringify(body),\r\n }\r\n );\r\n}\r\n"],
4
+ "sourcesContent": ["import { refreshGoogleAccessToken } from \"../analytics/oauth.js\";\n\nconst SEARCH_CONSOLE_BASE_URL = \"https://www.googleapis.com/webmasters/v3\";\n\nexport interface SearchConsoleSiteEntry {\n siteUrl: string;\n permissionLevel?: string;\n}\n\nexport interface SearchConsoleSitesListResponse {\n siteEntry?: SearchConsoleSiteEntry[];\n}\n\nexport interface SearchConsoleDimensionFilter {\n dimension: string;\n operator: string;\n expression: string;\n}\n\nexport interface SearchConsoleDimensionFilterGroup {\n groupType?: string;\n filters: SearchConsoleDimensionFilter[];\n}\n\nexport interface SearchConsoleSearchAnalyticsRequest {\n startDate: string;\n endDate: string;\n dimensions?: string[];\n type?: string;\n dimensionFilterGroups?: SearchConsoleDimensionFilterGroup[];\n aggregationType?: string;\n rowLimit?: number;\n startRow?: number;\n}\n\nexport interface SearchConsoleSearchAnalyticsRow {\n keys?: string[];\n clicks?: number;\n impressions?: number;\n ctr?: number;\n position?: number;\n}\n\nexport interface SearchConsoleSearchAnalyticsResponse {\n rows?: SearchConsoleSearchAnalyticsRow[];\n responseAggregationType?: string;\n}\n\ninterface GoogleApiErrorPayload {\n error?: {\n code?: number;\n message?: string;\n status?: string;\n };\n}\n\nasync function googleApiFetch<T>(url: string, init?: RequestInit): Promise<T> {\n const accessToken = await refreshGoogleAccessToken();\n\n const response = await fetch(url, {\n ...init,\n headers: {\n Authorization: `Bearer ${accessToken.accessToken}`,\n \"Content-Type\": \"application/json\",\n ...(init?.headers ?? {}),\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as GoogleApiErrorPayload;\n const message =\n payload.error?.message ??\n payload.error?.status ??\n `Google Search Console API request failed with status ${response.status}`;\n\n const normalizedMessage = message.toLowerCase();\n if (\n response.status === 403 &&\n normalizedMessage.includes(\"insufficient authentication scopes\")\n ) {\n throw new Error(\n \"Request had insufficient authentication scopes. Reconnect the Google OAuth credentials with Search Console scope https://www.googleapis.com/auth/webmasters.readonly or https://www.googleapis.com/auth/webmasters.\"\n );\n }\n\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n\nexport async function listSearchConsoleSites(): Promise<SearchConsoleSiteEntry[]> {\n const payload = await googleApiFetch<SearchConsoleSitesListResponse>(\n `${SEARCH_CONSOLE_BASE_URL}/sites`\n );\n\n return payload.siteEntry ?? [];\n}\n\nexport async function querySearchConsolePerformance(\n siteUrl: string,\n body: SearchConsoleSearchAnalyticsRequest\n): Promise<SearchConsoleSearchAnalyticsResponse> {\n return googleApiFetch<SearchConsoleSearchAnalyticsResponse>(\n `${SEARCH_CONSOLE_BASE_URL}/sites/${encodeURIComponent(siteUrl)}/searchAnalytics/query`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n }\n );\n}\n"],
5
5
  "mappings": "AAAA,SAAS,gCAAgC;AAEzC,MAAM,0BAA0B;AAsDhC,eAAe,eAAkB,KAAa,MAAgC;AAC5E,QAAM,cAAc,MAAM,yBAAyB;AAEnD,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,GAAG;AAAA,IACH,SAAS;AAAA,MACP,eAAe,UAAU,YAAY,WAAW;AAAA,MAChD,gBAAgB;AAAA,MAChB,GAAI,MAAM,WAAW,CAAC;AAAA,IACxB;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAW,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACvD,UAAM,UACJ,QAAQ,OAAO,WACf,QAAQ,OAAO,UACf,wDAAwD,SAAS,MAAM;AAEzE,UAAM,oBAAoB,QAAQ,YAAY;AAC9C,QACE,SAAS,WAAW,OACpB,kBAAkB,SAAS,oCAAoC,GAC/D;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,eAAsB,yBAA4D;AAChF,QAAM,UAAU,MAAM;AAAA,IACpB,GAAG,uBAAuB;AAAA,EAC5B;AAEA,SAAO,QAAQ,aAAa,CAAC;AAC/B;AAEA,eAAsB,8BACpB,SACA,MAC+C;AAC/C,SAAO;AAAA,IACL,GAAG,uBAAuB,UAAU,mBAAmB,OAAO,CAAC;AAAA,IAC/D;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/search-console/search-console-utils.ts"],
4
- "sourcesContent": ["import { z } from 'zod';\r\nimport { getProfileGoogleServiceMapping } from '../../config/google-store.js';\r\nimport type { SearchConsoleDimensionFilter, SearchConsoleDimensionFilterGroup, SearchConsoleSearchAnalyticsRequest, SearchConsoleSearchAnalyticsRow, SearchConsoleSiteEntry } from './search-console-client.js';\r\n\r\nexport const searchConsoleDateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\r\nexport const searchConsoleSearchTypes = ['web', 'image', 'video', 'news', 'discover'] as const;\r\nexport const searchConsoleDimensions = ['query', 'page', 'country', 'device', 'date', 'searchAppearance'] as const;\r\nexport const searchConsoleFilterOperators = ['contains', 'equals', 'notContains', 'notEquals', 'includingRegex', 'excludingRegex'] as const;\r\nexport const searchConsoleAggregationTypes = ['auto', 'byPage', 'byProperty'] as const;\r\nexport const searchConsoleDimensionFilterSchema = z.object({ dimension: z.enum(searchConsoleDimensions).describe('Dimension to filter on in Search Console (query, page, country, device, date, or searchAppearance)'), operator: z.enum(searchConsoleFilterOperators).describe('Filter operator supported by Search Console.'), expression: z.string().min(1).describe('Filter value or regex expression.') });\r\nexport const siteUrlSchemaField = z.string().optional().describe('Search Console site URL or domain property identifier (for example https://www.example.com/ or sc-domain:example.com). If omitted, the tool tries profileId mapping first.');\r\nexport const profileIdSchemaField = z.string().optional().describe('Optional business profile identifier used to resolve Google service mappings.');\r\nexport const startDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Start date in YYYY-MM-DD format.');\r\nexport const endDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('End date in YYYY-MM-DD format.');\r\nexport const currentStartDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Current comparison period start date in YYYY-MM-DD format.');\r\nexport const currentEndDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Current comparison period end date in YYYY-MM-DD format.');\r\nexport const previousStartDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Previous comparison period start date in YYYY-MM-DD format.');\r\nexport const previousEndDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Previous comparison period end date in YYYY-MM-DD format.');\r\nexport const rowLimitSchemaField = z.number().int().min(1).max(25000).optional().describe('Maximum number of rows to return. Search Console supports up to 25,000 rows per request.');\r\nexport const startRowSchemaField = z.number().int().min(0).optional().describe('Zero-based row offset for paginated Search Console requests.');\r\nexport const searchTypeSchemaField = z.enum(searchConsoleSearchTypes).optional().describe('Search type to query. Defaults to web.');\r\nexport const brandTermsSchemaField = z.array(z.string().min(1)).max(50).optional().describe('Brand tokens used to separate branded from non-branded queries.');\r\n\r\nexport async function resolveSearchConsoleSiteUrl(siteUrl?: string, profileId?: string): Promise<string> {\r\n const explicitSiteUrl = siteUrl?.trim();\r\n if (explicitSiteUrl) return explicitSiteUrl;\r\n const explicitProfileId = profileId?.trim();\r\n if (explicitProfileId) {\r\n const mapping = await getProfileGoogleServiceMapping(explicitProfileId);\r\n if (mapping?.searchConsoleSiteUrl) return mapping.searchConsoleSiteUrl;\r\n throw new Error(`Missing Search Console site URL. profileId \"${explicitProfileId}\" has no Search Console mapping configured.`);\r\n }\r\n throw new Error('Missing Search Console site URL. Pass siteUrl explicitly, provide profileId with a configured mapping, or call gsc_list_accessible_sites first.');\r\n}\r\n\r\nexport function inferSearchConsolePropertyType(siteUrl: string): 'domain' | 'url_prefix' | 'unknown' { if (siteUrl.startsWith('sc-domain:')) return 'domain'; if (/^https?:\\/\\//.test(siteUrl)) return 'url_prefix'; return 'unknown'; }\r\nexport function normalizePermissionLevel(permissionLevel?: string): string | undefined { return permissionLevel?.trim().toLowerCase() || undefined; }\r\nexport function normalizeSearchConsoleSiteEntry(siteEntry: SearchConsoleSiteEntry) { return { site_url: siteEntry.siteUrl, property_type: inferSearchConsolePropertyType(siteEntry.siteUrl), permission_level: normalizePermissionLevel(siteEntry.permissionLevel) }; }\r\nexport function toPercent(numerator: number, denominator: number): number { if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0; return (numerator / denominator) * 100; }\r\nexport function round(value: number, decimals = 2): number { if (!Number.isFinite(value)) return 0; const factor = 10 ** decimals; return Math.round(value * factor) / factor; }\r\nexport function normalizeSearchConsoleRow(row: SearchConsoleSearchAnalyticsRow, dimensions: readonly string[] = []) { const clicks = row.clicks ?? 0; const impressions = row.impressions ?? 0; const ctr = typeof row.ctr === 'number' ? row.ctr * 100 : toPercent(clicks, impressions); const keys = row.keys ?? []; return { keys, dimensions: dimensions.reduce<Record<string, string>>((accumulator, dimension, index) => { accumulator[dimension] = keys[index] ?? ''; return accumulator; }, {}), clicks: round(clicks, 2), impressions: round(impressions, 2), ctr_percent: round(ctr, 2), position: round(row.position ?? 0, 2) }; }\r\nexport function buildSearchConsoleQueryBody(input: { startDate: string; endDate: string; dimensions?: string[]; searchType?: string; dimensionFilters?: SearchConsoleDimensionFilter[]; aggregationType?: string; rowLimit?: number; startRow?: number; }): SearchConsoleSearchAnalyticsRequest { const dimensionFilterGroups: SearchConsoleDimensionFilterGroup[] | undefined = input.dimensionFilters && input.dimensionFilters.length > 0 ? [{ groupType: 'and', filters: input.dimensionFilters }] : undefined; return { startDate: input.startDate, endDate: input.endDate, dimensions: input.dimensions, type: input.searchType ?? 'web', dimensionFilterGroups, aggregationType: input.aggregationType, rowLimit: input.rowLimit, startRow: input.startRow }; }\r\nexport function buildPaginationMetadata(input: { startRow?: number; rowLimit?: number; returnedRows: number; }) { const startRow = input.startRow ?? 0; const rowLimit = input.rowLimit; const isPartial = Boolean(rowLimit) && input.returnedRows === rowLimit; const nextStartRow = isPartial ? startRow + input.returnedRows : undefined; return { is_partial: isPartial, start_row: startRow, row_limit: rowLimit, returned_rows: input.returnedRows, next_start_row: nextStartRow, continuation_instructions: nextStartRow ? '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.' : undefined }; }\r\nexport function parseBrandTerms(brandTerms?: string[]): string[] { return (brandTerms ?? []).map((term) => term.trim().toLowerCase()).filter(Boolean); }\r\nexport function isBrandedQuery(query: string, brandTerms?: string[]): boolean { const normalizedQuery = query.trim().toLowerCase(); const normalizedBrandTerms = parseBrandTerms(brandTerms); if (!normalizedQuery || normalizedBrandTerms.length === 0) return false; return normalizedBrandTerms.some((brandTerm) => normalizedQuery.includes(brandTerm)); }\r\nexport function classifyBrandLabel(query: string, brandTerms?: string[]) { if ((brandTerms ?? []).length === 0) return 'unknown'; return isBrandedQuery(query, brandTerms) ? 'brand' : 'non_brand'; }\r\nexport function sumSearchConsoleRows(rows: Array<{ clicks: number; impressions: number; ctr_percent: number; position: number }>) { const clicks = rows.reduce((total, row) => total + row.clicks, 0); const impressions = rows.reduce((total, row) => total + row.impressions, 0); const weightedCtr = impressions > 0 ? rows.reduce((total, row) => total + row.impressions * row.ctr_percent, 0) / impressions : 0; const weightedPosition = impressions > 0 ? rows.reduce((total, row) => total + row.impressions * row.position, 0) / impressions : 0; return { clicks: round(clicks), impressions: round(impressions), ctrPercent: round(weightedCtr), averagePosition: round(weightedPosition) }; }\r\nexport function scoreQuickWinOpportunity(input: { impressions: number; ctrPercent: number; position: number }) { return round(input.impressions * Math.max(0, 8 - input.ctrPercent) * Math.max(0.5, 20 - input.position) / 100); }\r\nexport function scoreHighImpressionLowClickOpportunity(input: { impressions: number; ctrPercent: number; position: number }) { return round(input.impressions * Math.max(0, 5 - input.ctrPercent) * Math.max(0.5, 15 - input.position) / 100); }\r\nexport function classifyQuickWinType(position: number, ctrPercent: number) { if (position > 0 && position <= 10 && ctrPercent < 4) return 'ctr'; if (position > 10 && position <= 20) return 'position'; return 'mixed'; }\r\nexport function looksLikeProductQuery(query: string, productTerms?: string[]) { if ((productTerms ?? []).some((term) => query.toLowerCase().includes(term.trim().toLowerCase()))) return true; return /\\b(comprar|precio|modelo|sku|talle|color|review|opiniones)\\b/i.test(query); }\r\nexport function buildComparisonMap<T>(rows: T[], getKey: (row: T) => string) { return new Map(rows.map((row) => [getKey(row), row])); }\r\nexport function computeChangePercent(current: number, previous: number) { if (previous === 0) return current > 0 ? 100 : 0; return round(((current - previous) / previous) * 100); }\r\n"],
4
+ "sourcesContent": ["import { z } from 'zod';\nimport { getProfileGoogleServiceMapping } from '../../config/google-store.js';\nimport type { SearchConsoleDimensionFilter, SearchConsoleDimensionFilterGroup, SearchConsoleSearchAnalyticsRequest, SearchConsoleSearchAnalyticsRow, SearchConsoleSiteEntry } from './search-console-client.js';\n\nexport const searchConsoleDateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\nexport const searchConsoleSearchTypes = ['web', 'image', 'video', 'news', 'discover'] as const;\nexport const searchConsoleDimensions = ['query', 'page', 'country', 'device', 'date', 'searchAppearance'] as const;\nexport const searchConsoleFilterOperators = ['contains', 'equals', 'notContains', 'notEquals', 'includingRegex', 'excludingRegex'] as const;\nexport const searchConsoleAggregationTypes = ['auto', 'byPage', 'byProperty'] as const;\nexport const searchConsoleDimensionFilterSchema = z.object({ dimension: z.enum(searchConsoleDimensions).describe('Dimension to filter on in Search Console (query, page, country, device, date, or searchAppearance)'), operator: z.enum(searchConsoleFilterOperators).describe('Filter operator supported by Search Console.'), expression: z.string().min(1).describe('Filter value or regex expression.') });\nexport const siteUrlSchemaField = z.string().optional().describe('Search Console site URL or domain property identifier (for example https://www.example.com/ or sc-domain:example.com). If omitted, the tool tries profileId mapping first.');\nexport const profileIdSchemaField = z.string().optional().describe('Optional business profile identifier used to resolve Google service mappings.');\nexport const startDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Start date in YYYY-MM-DD format.');\nexport const endDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('End date in YYYY-MM-DD format.');\nexport const currentStartDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Current comparison period start date in YYYY-MM-DD format.');\nexport const currentEndDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Current comparison period end date in YYYY-MM-DD format.');\nexport const previousStartDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Previous comparison period start date in YYYY-MM-DD format.');\nexport const previousEndDateSchemaField = z.string().regex(searchConsoleDateRegex).describe('Previous comparison period end date in YYYY-MM-DD format.');\nexport const rowLimitSchemaField = z.number().int().min(1).max(25000).optional().describe('Maximum number of rows to return. Search Console supports up to 25,000 rows per request.');\nexport const startRowSchemaField = z.number().int().min(0).optional().describe('Zero-based row offset for paginated Search Console requests.');\nexport const searchTypeSchemaField = z.enum(searchConsoleSearchTypes).optional().describe('Search type to query. Defaults to web.');\nexport const brandTermsSchemaField = z.array(z.string().min(1)).max(50).optional().describe('Brand tokens used to separate branded from non-branded queries.');\n\nexport async function resolveSearchConsoleSiteUrl(siteUrl?: string, profileId?: string): Promise<string> {\n const explicitSiteUrl = siteUrl?.trim();\n if (explicitSiteUrl) return explicitSiteUrl;\n const explicitProfileId = profileId?.trim();\n if (explicitProfileId) {\n const mapping = await getProfileGoogleServiceMapping(explicitProfileId);\n if (mapping?.searchConsoleSiteUrl) return mapping.searchConsoleSiteUrl;\n throw new Error(`Missing Search Console site URL. profileId \"${explicitProfileId}\" has no Search Console mapping configured.`);\n }\n throw new Error('Missing Search Console site URL. Pass siteUrl explicitly, provide profileId with a configured mapping, or call gsc_list_accessible_sites first.');\n}\n\nexport function inferSearchConsolePropertyType(siteUrl: string): 'domain' | 'url_prefix' | 'unknown' { if (siteUrl.startsWith('sc-domain:')) return 'domain'; if (/^https?:\\/\\//.test(siteUrl)) return 'url_prefix'; return 'unknown'; }\nexport function normalizePermissionLevel(permissionLevel?: string): string | undefined { return permissionLevel?.trim().toLowerCase() || undefined; }\nexport function normalizeSearchConsoleSiteEntry(siteEntry: SearchConsoleSiteEntry) { return { site_url: siteEntry.siteUrl, property_type: inferSearchConsolePropertyType(siteEntry.siteUrl), permission_level: normalizePermissionLevel(siteEntry.permissionLevel) }; }\nexport function toPercent(numerator: number, denominator: number): number { if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0; return (numerator / denominator) * 100; }\nexport function round(value: number, decimals = 2): number { if (!Number.isFinite(value)) return 0; const factor = 10 ** decimals; return Math.round(value * factor) / factor; }\nexport function normalizeSearchConsoleRow(row: SearchConsoleSearchAnalyticsRow, dimensions: readonly string[] = []) { const clicks = row.clicks ?? 0; const impressions = row.impressions ?? 0; const ctr = typeof row.ctr === 'number' ? row.ctr * 100 : toPercent(clicks, impressions); const keys = row.keys ?? []; return { keys, dimensions: dimensions.reduce<Record<string, string>>((accumulator, dimension, index) => { accumulator[dimension] = keys[index] ?? ''; return accumulator; }, {}), clicks: round(clicks, 2), impressions: round(impressions, 2), ctr_percent: round(ctr, 2), position: round(row.position ?? 0, 2) }; }\nexport function buildSearchConsoleQueryBody(input: { startDate: string; endDate: string; dimensions?: string[]; searchType?: string; dimensionFilters?: SearchConsoleDimensionFilter[]; aggregationType?: string; rowLimit?: number; startRow?: number; }): SearchConsoleSearchAnalyticsRequest { const dimensionFilterGroups: SearchConsoleDimensionFilterGroup[] | undefined = input.dimensionFilters && input.dimensionFilters.length > 0 ? [{ groupType: 'and', filters: input.dimensionFilters }] : undefined; return { startDate: input.startDate, endDate: input.endDate, dimensions: input.dimensions, type: input.searchType ?? 'web', dimensionFilterGroups, aggregationType: input.aggregationType, rowLimit: input.rowLimit, startRow: input.startRow }; }\nexport function buildPaginationMetadata(input: { startRow?: number; rowLimit?: number; returnedRows: number; }) { const startRow = input.startRow ?? 0; const rowLimit = input.rowLimit; const isPartial = Boolean(rowLimit) && input.returnedRows === rowLimit; const nextStartRow = isPartial ? startRow + input.returnedRows : undefined; return { is_partial: isPartial, start_row: startRow, row_limit: rowLimit, returned_rows: input.returnedRows, next_start_row: nextStartRow, continuation_instructions: nextStartRow ? '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.' : undefined }; }\nexport function parseBrandTerms(brandTerms?: string[]): string[] { return (brandTerms ?? []).map((term) => term.trim().toLowerCase()).filter(Boolean); }\nexport function isBrandedQuery(query: string, brandTerms?: string[]): boolean { const normalizedQuery = query.trim().toLowerCase(); const normalizedBrandTerms = parseBrandTerms(brandTerms); if (!normalizedQuery || normalizedBrandTerms.length === 0) return false; return normalizedBrandTerms.some((brandTerm) => normalizedQuery.includes(brandTerm)); }\nexport function classifyBrandLabel(query: string, brandTerms?: string[]) { if ((brandTerms ?? []).length === 0) return 'unknown'; return isBrandedQuery(query, brandTerms) ? 'brand' : 'non_brand'; }\nexport function sumSearchConsoleRows(rows: Array<{ clicks: number; impressions: number; ctr_percent: number; position: number }>) { const clicks = rows.reduce((total, row) => total + row.clicks, 0); const impressions = rows.reduce((total, row) => total + row.impressions, 0); const weightedCtr = impressions > 0 ? rows.reduce((total, row) => total + row.impressions * row.ctr_percent, 0) / impressions : 0; const weightedPosition = impressions > 0 ? rows.reduce((total, row) => total + row.impressions * row.position, 0) / impressions : 0; return { clicks: round(clicks), impressions: round(impressions), ctrPercent: round(weightedCtr), averagePosition: round(weightedPosition) }; }\nexport function scoreQuickWinOpportunity(input: { impressions: number; ctrPercent: number; position: number }) { return round(input.impressions * Math.max(0, 8 - input.ctrPercent) * Math.max(0.5, 20 - input.position) / 100); }\nexport function scoreHighImpressionLowClickOpportunity(input: { impressions: number; ctrPercent: number; position: number }) { return round(input.impressions * Math.max(0, 5 - input.ctrPercent) * Math.max(0.5, 15 - input.position) / 100); }\nexport function classifyQuickWinType(position: number, ctrPercent: number) { if (position > 0 && position <= 10 && ctrPercent < 4) return 'ctr'; if (position > 10 && position <= 20) return 'position'; return 'mixed'; }\nexport function looksLikeProductQuery(query: string, productTerms?: string[]) { if ((productTerms ?? []).some((term) => query.toLowerCase().includes(term.trim().toLowerCase()))) return true; return /\\b(comprar|precio|modelo|sku|talle|color|review|opiniones)\\b/i.test(query); }\nexport function buildComparisonMap<T>(rows: T[], getKey: (row: T) => string) { return new Map(rows.map((row) => [getKey(row), row])); }\nexport function computeChangePercent(current: number, previous: number) { if (previous === 0) return current > 0 ? 100 : 0; return round(((current - previous) / previous) * 100); }\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-api.ts"],
4
- "sourcesContent": ["import axios from \"axios\";\r\nimport type { AxiosError, AxiosInstance } from \"axios\";\r\n\r\nimport { getVtexConfigForProfile, type VtexConfig } from \"../../config/vtex.js\";\r\n\r\nexport function createVtexClient(config: VtexConfig, baseURL: string): AxiosInstance {\r\n const client = axios.create({\r\n baseURL,\r\n headers: {\r\n \"X-VTEX-API-AppKey\": config.apiKey,\r\n \"X-VTEX-API-AppToken\": config.apiToken,\r\n Accept: \"application/json\",\r\n \"Content-Type\": \"application/json\",\r\n },\r\n timeout: 30000,\r\n });\r\n\r\n client.interceptors.response.use(\r\n (response) => response,\r\n (error: AxiosError) => {\r\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\r\n const url = error.config?.url ?? \"UNKNOWN_URL\";\r\n const status = error.response?.status ?? \"NO_STATUS\";\r\n\r\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\r\n\r\n if (error.response?.data) {\r\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\r\n }\r\n\r\n return Promise.reject(error);\r\n }\r\n );\r\n\r\n return client;\r\n}\r\n\r\nexport async function getVtexApiClients(profileId: string) {\r\n const config = await getVtexConfigForProfile(profileId);\r\n\r\n return {\r\n config,\r\n vtexApi: createVtexClient(config, config.baseUrl),\r\n vtexPricingApi: createVtexClient(config, config.pricingBaseUrl),\r\n };\r\n}\r\n\r\nexport async function validateVtexConfig(config: VtexConfig): Promise<void> {\r\n const client = createVtexClient(config, config.baseUrl);\r\n await client.get(\"/api/oms/pvt/orders\", {\r\n params: {\r\n page: 1,\r\n per_page: 1,\r\n },\r\n });\r\n}\r\n\r\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\r\n if (axios.isAxiosError(error)) {\r\n const status = error.response?.status;\r\n const responseData = error.response?.data;\r\n const responseMessage =\r\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\r\n ? String((responseData as { message?: unknown }).message)\r\n : typeof responseData === \"string\"\r\n ? responseData\r\n : undefined;\r\n\r\n if (status) {\r\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\r\n }\r\n\r\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\r\n }\r\n\r\n if (error instanceof Error) {\r\n return error.message;\r\n }\r\n\r\n return fallback;\r\n}\r\n"],
4
+ "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosError, AxiosInstance } from \"axios\";\n\nimport { getVtexConfigForProfile, type VtexConfig } from \"../../config/vtex.js\";\n\nexport function createVtexClient(config: VtexConfig, baseURL: string): AxiosInstance {\n const client = axios.create({\n baseURL,\n headers: {\n \"X-VTEX-API-AppKey\": config.apiKey,\n \"X-VTEX-API-AppToken\": config.apiToken,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n });\n\n client.interceptors.response.use(\n (response) => response,\n (error: AxiosError) => {\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\n const url = error.config?.url ?? \"UNKNOWN_URL\";\n const status = error.response?.status ?? \"NO_STATUS\";\n\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\n\n if (error.response?.data) {\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\n }\n\n return Promise.reject(error);\n }\n );\n\n return client;\n}\n\nexport async function getVtexApiClients(profileId: string) {\n const config = await getVtexConfigForProfile(profileId);\n\n return {\n config,\n vtexApi: createVtexClient(config, config.baseUrl),\n vtexPricingApi: createVtexClient(config, config.pricingBaseUrl),\n };\n}\n\nexport async function validateVtexConfig(config: VtexConfig): Promise<void> {\n const client = createVtexClient(config, config.baseUrl);\n await client.get(\"/api/oms/pvt/orders\", {\n params: {\n page: 1,\n per_page: 1,\n },\n });\n}\n\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const responseData = error.response?.data;\n const responseMessage =\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\n ? String((responseData as { message?: unknown }).message)\n : typeof responseData === \"string\"\n ? responseData\n : undefined;\n\n if (status) {\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\n }\n\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return fallback;\n}\n"],
5
5
  "mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS,+BAAgD;AAElD,SAAS,iBAAiB,QAAoB,SAAgC;AACnF,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO;AAAA,MAC5B,uBAAuB,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,SAAO,aAAa,SAAS;AAAA,IAC3B,CAAC,aAAa;AAAA,IACd,CAAC,UAAsB;AACrB,YAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK;AACtD,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,SAAS,MAAM,UAAU,UAAU;AAEzC,cAAQ,MAAM,oBAAoB,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAE9D,UAAI,MAAM,UAAU,MAAM;AACxB,gBAAQ,MAAM,yBAAyB,MAAM,SAAS,IAAI;AAAA,MAC5D;AAEA,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,kBAAkB,WAAmB;AACzD,QAAM,SAAS,MAAM,wBAAwB,SAAS;AAEtD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AAAA,IAChD,gBAAgB,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAChE;AACF;AAEA,eAAsB,mBAAmB,QAAmC;AAC1E,QAAM,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AACtD,QAAM,OAAO,IAAI,uBAAuB;AAAA,IACtC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AACH;AAEO,SAAS,gBAAgB,OAAgB,WAAW,6BAAqC;AAC9F,MAAI,MAAM,aAAa,KAAK,GAAG;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,eAAe,MAAM,UAAU;AACrC,UAAM,kBACJ,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,aAAa,eACtE,OAAQ,aAAuC,OAAO,IACtD,OAAO,iBAAiB,WACtB,eACA;AAER,QAAI,QAAQ;AACV,aAAO,4BAA4B,MAAM,MAAM,mBAAmB,MAAM,OAAO;AAAA,IACjF;AAEA,WAAO,4BAA4B,mBAAmB,MAAM,OAAO;AAAA,EACrE;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-catalog-write.ts"],
4
- "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport interface VtexProductBasicFieldsInput {\r\n name?: string;\r\n categoryId?: number;\r\n brandId?: number;\r\n description?: string;\r\n descriptionShort?: string;\r\n title?: string;\r\n linkId?: string;\r\n refId?: string;\r\n isVisible?: boolean;\r\n isActive?: boolean;\r\n keyWords?: string;\r\n releaseDate?: string;\r\n metaTagDescription?: string;\r\n showWithoutStock?: boolean;\r\n}\r\n\r\nexport interface VtexSkuBasicFieldsInput {\r\n name?: string;\r\n refId?: string;\r\n ean?: string;\r\n packagedHeight?: number;\r\n packagedLength?: number;\r\n packagedWidth?: number;\r\n packagedWeightKg?: number;\r\n height?: number;\r\n length?: number;\r\n width?: number;\r\n weightKg?: number;\r\n measurementUnit?: string;\r\n unitMultiplier?: number;\r\n manufacturerCode?: string;\r\n commercialConditionId?: number;\r\n isActive?: boolean;\r\n activateIfPossible?: boolean;\r\n}\r\n\r\nfunction pickRecord(source: Record<string, unknown>, keys: string[]): Record<string, unknown> {\r\n const picked: Record<string, unknown> = {};\r\n for (const key of keys) {\r\n if (key in source) {\r\n picked[key] = source[key];\r\n }\r\n }\r\n return picked;\r\n}\r\n\r\nexport async function getProduct(profileId: string, productId: string): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/product/${productId}`);\r\n return response.data;\r\n}\r\n\r\nexport async function createProduct(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/product\", payload);\r\n return response.data;\r\n}\r\n\r\nexport async function updateProduct(\r\n profileId: string,\r\n productId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.put<Record<string, unknown>>(`/api/catalog/pvt/product/${productId}`, payload);\r\n return response.data;\r\n}\r\n\r\nexport function buildProductUpdatePayload(\r\n current: Record<string, unknown>,\r\n updates: VtexProductBasicFieldsInput\r\n): Record<string, unknown> {\r\n const payload = pickRecord(current, [\r\n \"Name\",\r\n \"DepartmentId\",\r\n \"CategoryId\",\r\n \"BrandId\",\r\n \"LinkId\",\r\n \"RefId\",\r\n \"IsVisible\",\r\n \"Description\",\r\n \"DescriptionShort\",\r\n \"ReleaseDate\",\r\n \"KeyWords\",\r\n \"Title\",\r\n \"IsActive\",\r\n \"TaxCode\",\r\n \"MetaTagDescription\",\r\n \"SupplierId\",\r\n \"ShowWithoutStock\",\r\n \"AdWordsRemarketingCode\",\r\n \"LomadeeCampaignCode\",\r\n \"Score\",\r\n ]);\r\n\r\n if (updates.name !== undefined) payload.Name = updates.name;\r\n if (updates.categoryId !== undefined) payload.CategoryId = updates.categoryId;\r\n if (updates.brandId !== undefined) payload.BrandId = updates.brandId;\r\n if (updates.description !== undefined) payload.Description = updates.description;\r\n if (updates.descriptionShort !== undefined) payload.DescriptionShort = updates.descriptionShort;\r\n if (updates.title !== undefined) payload.Title = updates.title;\r\n if (updates.linkId !== undefined) payload.LinkId = updates.linkId;\r\n if (updates.refId !== undefined) payload.RefId = updates.refId;\r\n if (updates.isVisible !== undefined) payload.IsVisible = updates.isVisible;\r\n if (updates.isActive !== undefined) payload.IsActive = updates.isActive;\r\n if (updates.keyWords !== undefined) payload.KeyWords = updates.keyWords;\r\n if (updates.releaseDate !== undefined) payload.ReleaseDate = updates.releaseDate;\r\n if (updates.metaTagDescription !== undefined) {\r\n payload.MetaTagDescription = updates.metaTagDescription;\r\n }\r\n if (updates.showWithoutStock !== undefined) {\r\n payload.ShowWithoutStock = updates.showWithoutStock;\r\n }\r\n\r\n return payload;\r\n}\r\n\r\nexport async function getSku(profileId: string, skuId: string): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/stockkeepingunit/${skuId}`);\r\n return response.data;\r\n}\r\n\r\nexport async function createSku(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/stockkeepingunit\", payload);\r\n return response.data;\r\n}\r\n\r\nexport async function updateSku(\r\n profileId: string,\r\n skuId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.put<Record<string, unknown>>(`/api/catalog/pvt/stockkeepingunit/${skuId}`, payload);\r\n return response.data;\r\n}\r\n\r\nexport function buildSkuUpdatePayload(\r\n current: Record<string, unknown>,\r\n updates: VtexSkuBasicFieldsInput\r\n): Record<string, unknown> {\r\n const payload = pickRecord(current, [\r\n \"ProductId\",\r\n \"IsActive\",\r\n \"ActivateIfPossible\",\r\n \"Name\",\r\n \"RefId\",\r\n \"PackagedHeight\",\r\n \"PackagedLength\",\r\n \"PackagedWidth\",\r\n \"PackagedWeightKg\",\r\n \"Height\",\r\n \"Length\",\r\n \"Width\",\r\n \"WeightKg\",\r\n \"CubicWeight\",\r\n \"IsKit\",\r\n \"CreationDate\",\r\n \"RewardValue\",\r\n \"EstimatedDateArrival\",\r\n \"ManufacturerCode\",\r\n \"CommercialConditionId\",\r\n \"MeasurementUnit\",\r\n \"UnitMultiplier\",\r\n \"ModalType\",\r\n \"KitItensSellApart\",\r\n \"Videos\",\r\n ]);\r\n\r\n if (updates.name !== undefined) payload.Name = updates.name;\r\n if (updates.refId !== undefined) payload.RefId = updates.refId;\r\n if (updates.packagedHeight !== undefined) payload.PackagedHeight = updates.packagedHeight;\r\n if (updates.packagedLength !== undefined) payload.PackagedLength = updates.packagedLength;\r\n if (updates.packagedWidth !== undefined) payload.PackagedWidth = updates.packagedWidth;\r\n if (updates.packagedWeightKg !== undefined) payload.PackagedWeightKg = updates.packagedWeightKg;\r\n if (updates.height !== undefined) payload.Height = updates.height;\r\n if (updates.length !== undefined) payload.Length = updates.length;\r\n if (updates.width !== undefined) payload.Width = updates.width;\r\n if (updates.weightKg !== undefined) payload.WeightKg = updates.weightKg;\r\n if (updates.measurementUnit !== undefined) payload.MeasurementUnit = updates.measurementUnit;\r\n if (updates.unitMultiplier !== undefined) payload.UnitMultiplier = updates.unitMultiplier;\r\n if (updates.manufacturerCode !== undefined) payload.ManufacturerCode = updates.manufacturerCode;\r\n if (updates.commercialConditionId !== undefined) {\r\n payload.CommercialConditionId = updates.commercialConditionId;\r\n }\r\n if (updates.isActive !== undefined) payload.IsActive = updates.isActive;\r\n if (updates.activateIfPossible !== undefined) {\r\n payload.ActivateIfPossible = updates.activateIfPossible;\r\n }\r\n\r\n return payload;\r\n}\r\n\r\nexport async function getSkuEans(profileId: string, skuId: string): Promise<string[]> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<unknown>(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);\r\n const data = response.data;\r\n\r\n if (Array.isArray(data)) {\r\n return data.map((item) => String(item)).filter(Boolean);\r\n }\r\n\r\n if (data == null) {\r\n return [];\r\n }\r\n\r\n return [String(data)];\r\n}\r\n\r\nexport async function createSkuEan(\r\n profileId: string,\r\n skuId: string,\r\n ean: string\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.post(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean/${ean}`);\r\n}\r\n\r\nexport async function deleteAllSkuEans(profileId: string, skuId: string): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);\r\n}\r\n\r\nexport async function createBrand(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/brand\", payload);\r\n return response.data;\r\n}\r\n\r\nexport async function getBrand(profileId: string, brandId: string): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/brand/${brandId}`);\r\n return response.data;\r\n}\r\n\r\nexport async function createCategory(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/category\", payload);\r\n return response.data;\r\n}\r\n\r\nexport async function getCategory(\r\n profileId: string,\r\n categoryId: string\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/category/${categoryId}`);\r\n return response.data;\r\n}\r\n\r\nexport async function createSpecification(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/specification\", payload);\r\n return response.data;\r\n}\r\n\r\nexport async function createSpecificationValue(\r\n profileId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\r\n \"/api/catalog/pvt/specificationvalue\",\r\n payload\r\n );\r\n return response.data;\r\n}\r\n\r\nexport async function associateProductSpecification(\r\n profileId: string,\r\n productId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\r\n `/api/catalog/pvt/product/${productId}/specification`,\r\n payload\r\n );\r\n return response.data;\r\n}\r\n\r\nexport async function associateSkuSpecification(\r\n profileId: string,\r\n skuId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\r\n `/api/catalog/pvt/stockkeepingunit/${skuId}/specification`,\r\n payload\r\n );\r\n return response.data;\r\n}\r\n\r\nexport async function createSkuFile(\r\n profileId: string,\r\n skuId: string,\r\n payload: Record<string, unknown>\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.post<Record<string, unknown>>(\r\n `/api/catalog/pvt/stockkeepingunit/${skuId}/file`,\r\n payload\r\n );\r\n return response.data;\r\n}\r\n"],
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface VtexProductBasicFieldsInput {\n name?: string;\n categoryId?: number;\n brandId?: number;\n description?: string;\n descriptionShort?: string;\n title?: string;\n linkId?: string;\n refId?: string;\n isVisible?: boolean;\n isActive?: boolean;\n keyWords?: string;\n releaseDate?: string;\n metaTagDescription?: string;\n showWithoutStock?: boolean;\n}\n\nexport interface VtexSkuBasicFieldsInput {\n name?: string;\n refId?: string;\n ean?: string;\n packagedHeight?: number;\n packagedLength?: number;\n packagedWidth?: number;\n packagedWeightKg?: number;\n height?: number;\n length?: number;\n width?: number;\n weightKg?: number;\n measurementUnit?: string;\n unitMultiplier?: number;\n manufacturerCode?: string;\n commercialConditionId?: number;\n isActive?: boolean;\n activateIfPossible?: boolean;\n}\n\nfunction pickRecord(source: Record<string, unknown>, keys: string[]): Record<string, unknown> {\n const picked: Record<string, unknown> = {};\n for (const key of keys) {\n if (key in source) {\n picked[key] = source[key];\n }\n }\n return picked;\n}\n\nexport async function getProduct(profileId: string, productId: string): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/product/${productId}`);\n return response.data;\n}\n\nexport async function createProduct(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/product\", payload);\n return response.data;\n}\n\nexport async function updateProduct(\n profileId: string,\n productId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.put<Record<string, unknown>>(`/api/catalog/pvt/product/${productId}`, payload);\n return response.data;\n}\n\nexport function buildProductUpdatePayload(\n current: Record<string, unknown>,\n updates: VtexProductBasicFieldsInput\n): Record<string, unknown> {\n const payload = pickRecord(current, [\n \"Name\",\n \"DepartmentId\",\n \"CategoryId\",\n \"BrandId\",\n \"LinkId\",\n \"RefId\",\n \"IsVisible\",\n \"Description\",\n \"DescriptionShort\",\n \"ReleaseDate\",\n \"KeyWords\",\n \"Title\",\n \"IsActive\",\n \"TaxCode\",\n \"MetaTagDescription\",\n \"SupplierId\",\n \"ShowWithoutStock\",\n \"AdWordsRemarketingCode\",\n \"LomadeeCampaignCode\",\n \"Score\",\n ]);\n\n if (updates.name !== undefined) payload.Name = updates.name;\n if (updates.categoryId !== undefined) payload.CategoryId = updates.categoryId;\n if (updates.brandId !== undefined) payload.BrandId = updates.brandId;\n if (updates.description !== undefined) payload.Description = updates.description;\n if (updates.descriptionShort !== undefined) payload.DescriptionShort = updates.descriptionShort;\n if (updates.title !== undefined) payload.Title = updates.title;\n if (updates.linkId !== undefined) payload.LinkId = updates.linkId;\n if (updates.refId !== undefined) payload.RefId = updates.refId;\n if (updates.isVisible !== undefined) payload.IsVisible = updates.isVisible;\n if (updates.isActive !== undefined) payload.IsActive = updates.isActive;\n if (updates.keyWords !== undefined) payload.KeyWords = updates.keyWords;\n if (updates.releaseDate !== undefined) payload.ReleaseDate = updates.releaseDate;\n if (updates.metaTagDescription !== undefined) {\n payload.MetaTagDescription = updates.metaTagDescription;\n }\n if (updates.showWithoutStock !== undefined) {\n payload.ShowWithoutStock = updates.showWithoutStock;\n }\n\n return payload;\n}\n\nexport async function getSku(profileId: string, skuId: string): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/stockkeepingunit/${skuId}`);\n return response.data;\n}\n\nexport async function createSku(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/stockkeepingunit\", payload);\n return response.data;\n}\n\nexport async function updateSku(\n profileId: string,\n skuId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.put<Record<string, unknown>>(`/api/catalog/pvt/stockkeepingunit/${skuId}`, payload);\n return response.data;\n}\n\nexport function buildSkuUpdatePayload(\n current: Record<string, unknown>,\n updates: VtexSkuBasicFieldsInput\n): Record<string, unknown> {\n const payload = pickRecord(current, [\n \"ProductId\",\n \"IsActive\",\n \"ActivateIfPossible\",\n \"Name\",\n \"RefId\",\n \"PackagedHeight\",\n \"PackagedLength\",\n \"PackagedWidth\",\n \"PackagedWeightKg\",\n \"Height\",\n \"Length\",\n \"Width\",\n \"WeightKg\",\n \"CubicWeight\",\n \"IsKit\",\n \"CreationDate\",\n \"RewardValue\",\n \"EstimatedDateArrival\",\n \"ManufacturerCode\",\n \"CommercialConditionId\",\n \"MeasurementUnit\",\n \"UnitMultiplier\",\n \"ModalType\",\n \"KitItensSellApart\",\n \"Videos\",\n ]);\n\n if (updates.name !== undefined) payload.Name = updates.name;\n if (updates.refId !== undefined) payload.RefId = updates.refId;\n if (updates.packagedHeight !== undefined) payload.PackagedHeight = updates.packagedHeight;\n if (updates.packagedLength !== undefined) payload.PackagedLength = updates.packagedLength;\n if (updates.packagedWidth !== undefined) payload.PackagedWidth = updates.packagedWidth;\n if (updates.packagedWeightKg !== undefined) payload.PackagedWeightKg = updates.packagedWeightKg;\n if (updates.height !== undefined) payload.Height = updates.height;\n if (updates.length !== undefined) payload.Length = updates.length;\n if (updates.width !== undefined) payload.Width = updates.width;\n if (updates.weightKg !== undefined) payload.WeightKg = updates.weightKg;\n if (updates.measurementUnit !== undefined) payload.MeasurementUnit = updates.measurementUnit;\n if (updates.unitMultiplier !== undefined) payload.UnitMultiplier = updates.unitMultiplier;\n if (updates.manufacturerCode !== undefined) payload.ManufacturerCode = updates.manufacturerCode;\n if (updates.commercialConditionId !== undefined) {\n payload.CommercialConditionId = updates.commercialConditionId;\n }\n if (updates.isActive !== undefined) payload.IsActive = updates.isActive;\n if (updates.activateIfPossible !== undefined) {\n payload.ActivateIfPossible = updates.activateIfPossible;\n }\n\n return payload;\n}\n\nexport async function getSkuEans(profileId: string, skuId: string): Promise<string[]> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<unknown>(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);\n const data = response.data;\n\n if (Array.isArray(data)) {\n return data.map((item) => String(item)).filter(Boolean);\n }\n\n if (data == null) {\n return [];\n }\n\n return [String(data)];\n}\n\nexport async function createSkuEan(\n profileId: string,\n skuId: string,\n ean: string\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.post(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean/${ean}`);\n}\n\nexport async function deleteAllSkuEans(profileId: string, skuId: string): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);\n}\n\nexport async function createBrand(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/brand\", payload);\n return response.data;\n}\n\nexport async function getBrand(profileId: string, brandId: string): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/brand/${brandId}`);\n return response.data;\n}\n\nexport async function createCategory(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/category\", payload);\n return response.data;\n}\n\nexport async function getCategory(\n profileId: string,\n categoryId: string\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/catalog/pvt/category/${categoryId}`);\n return response.data;\n}\n\nexport async function createSpecification(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\"/api/catalog/pvt/specification\", payload);\n return response.data;\n}\n\nexport async function createSpecificationValue(\n profileId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\n \"/api/catalog/pvt/specificationvalue\",\n payload\n );\n return response.data;\n}\n\nexport async function associateProductSpecification(\n profileId: string,\n productId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\n `/api/catalog/pvt/product/${productId}/specification`,\n payload\n );\n return response.data;\n}\n\nexport async function associateSkuSpecification(\n profileId: string,\n skuId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\n `/api/catalog/pvt/stockkeepingunit/${skuId}/specification`,\n payload\n );\n return response.data;\n}\n\nexport async function createSkuFile(\n profileId: string,\n skuId: string,\n payload: Record<string, unknown>\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.post<Record<string, unknown>>(\n `/api/catalog/pvt/stockkeepingunit/${skuId}/file`,\n payload\n );\n return response.data;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-catalog.ts"],
4
- "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport type ProductOffersResponse = Record<string, unknown>[];\r\n\r\nexport async function getProductOffers(\r\n profileId: string,\r\n productId: string\r\n): Promise<ProductOffersResponse> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<ProductOffersResponse>(\r\n `/api/catalog_system/pub/products/offers/${productId}`\r\n );\r\n\r\n return response.data;\r\n}\r\n\r\nexport async function getSkuOffers(\r\n profileId: string,\r\n productId: string,\r\n skuId: string\r\n): Promise<ProductOffersResponse> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<ProductOffersResponse>(\r\n `/api/catalog_system/pub/products/offers/${productId}/sku/${skuId}`\r\n );\r\n\r\n return response.data;\r\n}\r\n"],
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport type ProductOffersResponse = Record<string, unknown>[];\n\nexport async function getProductOffers(\n profileId: string,\n productId: string\n): Promise<ProductOffersResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}`\n );\n\n return response.data;\n}\n\nexport async function getSkuOffers(\n profileId: string,\n productId: string,\n skuId: string\n): Promise<ProductOffersResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}/sku/${skuId}`\n );\n\n return response.data;\n}\n"],
5
5
  "mappings": "AAAA,SAAS,yBAAyB;AAIlC,eAAsB,iBACpB,WACA,WACgC;AAChC,QAAM,EAAE,QAAQ,IAAI,MAAM,kBAAkB,SAAS;AACrD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS;AAAA,EACtD;AAEA,SAAO,SAAS;AAClB;AAEA,eAAsB,aACpB,WACA,WACA,OACgC;AAChC,QAAM,EAAE,QAAQ,IAAI,MAAM,kBAAkB,SAAS;AACrD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS,QAAQ,KAAK;AAAA,EACnE;AAEA,SAAO,SAAS;AAClB;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-logistics.ts"],
4
- "sourcesContent": ["import axios from \"axios\";\r\nimport type { AxiosInstance } from \"axios\";\r\n\r\nimport { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport interface WarehouseBalance {\r\n warehouseId?: string;\r\n warehouseName?: string;\r\n totalQuantity?: number;\r\n reservedQuantity?: number;\r\n availableQuantity?: number;\r\n isUnlimited?: boolean;\r\n hasUnlimitedQuantity?: boolean;\r\n timeToRefill?: string;\r\n dateOfSupplyUtc?: string;\r\n leadTime?: string;\r\n}\r\n\r\nexport interface InventoryBySkuResponse {\r\n skuId?: string;\r\n balance?: WarehouseBalance[];\r\n}\r\n\r\nexport interface InventoryByWarehouseItem {\r\n skuId?: string;\r\n warehouseId?: string;\r\n totalQuantity?: number;\r\n reservedQuantity?: number;\r\n availableQuantity?: number;\r\n isUnlimited?: boolean;\r\n keepSellingAfterExpiration?: boolean;\r\n}\r\n\r\nexport interface UpdateInventoryQuantityPayload {\r\n quantity: number;\r\n unlimitedQuantity: boolean;\r\n dateUtcOnBalanceSystem?: string;\r\n}\r\n\r\nexport interface UpdateLeadTimePayload {\r\n leadTime: string;\r\n}\r\n\r\nexport interface GetInventoryBatchOptions {\r\n maxConcurrency?: number;\r\n maxRetries?: number;\r\n baseRetryDelayMs?: number;\r\n}\r\n\r\nexport interface InventoryBatchSuccess {\r\n skuId: string;\r\n document: InventoryBySkuResponse;\r\n}\r\n\r\nexport interface InventoryBatchFailure {\r\n skuId: string;\r\n message: string;\r\n statusCode?: number;\r\n attempts: number;\r\n retryable: boolean;\r\n}\r\n\r\nexport interface InventoryBatchResult {\r\n successful: InventoryBatchSuccess[];\r\n failed: InventoryBatchFailure[];\r\n}\r\n\r\ninterface InventoryFetchError extends Error {\r\n skuId: string;\r\n statusCode?: number;\r\n attempts: number;\r\n retryable: boolean;\r\n}\r\n\r\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\r\nconst DEFAULT_BATCH_CONCURRENCY = 10;\r\nconst DEFAULT_MAX_RETRIES = 2;\r\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\r\n\r\nexport async function getInventoryBySku(\r\n profileId: string,\r\n skuId: string\r\n): Promise<InventoryBySkuResponse> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\r\n return response.data;\r\n}\r\n\r\nasync function getInventoryBySkuWithClient(\r\n vtexApi: AxiosInstance,\r\n skuId: string\r\n): Promise<InventoryBySkuResponse> {\r\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\r\n return response.data;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => {\r\n setTimeout(resolve, ms);\r\n });\r\n}\r\n\r\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\r\n if (Array.isArray(headerValue)) {\r\n return parseRetryAfterMs(headerValue[0]);\r\n }\r\n\r\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\r\n return Math.max(0, Math.floor(headerValue * 1000));\r\n }\r\n\r\n if (typeof headerValue !== \"string\") {\r\n return undefined;\r\n }\r\n\r\n const trimmedValue = headerValue.trim();\r\n if (!trimmedValue) {\r\n return undefined;\r\n }\r\n\r\n const seconds = Number(trimmedValue);\r\n if (Number.isFinite(seconds)) {\r\n return Math.max(0, Math.floor(seconds * 1000));\r\n }\r\n\r\n const absoluteDateMs = Date.parse(trimmedValue);\r\n if (Number.isNaN(absoluteDateMs)) {\r\n return undefined;\r\n }\r\n\r\n return Math.max(0, absoluteDateMs - Date.now());\r\n}\r\n\r\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\r\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\r\n const jitter = Math.floor(Math.random() * 150);\r\n return exponential + jitter;\r\n}\r\n\r\nfunction isRetryableRequestError(error: unknown): boolean {\r\n if (!axios.isAxiosError(error)) {\r\n return false;\r\n }\r\n\r\n if (!error.response?.status) {\r\n return true;\r\n }\r\n\r\n return RETRYABLE_STATUS_CODES.has(error.response.status);\r\n}\r\n\r\nfunction toInventoryFetchError(\r\n skuId: string,\r\n source: unknown,\r\n attempts: number,\r\n retryable: boolean\r\n): InventoryFetchError {\r\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\r\n const message =\r\n source instanceof Error\r\n ? source.message\r\n : typeof source === \"string\"\r\n ? source\r\n : \"Unexpected error while fetching inventory details\";\r\n\r\n const error = new Error(message) as InventoryFetchError;\r\n error.skuId = skuId;\r\n error.statusCode = statusCode;\r\n error.attempts = attempts;\r\n error.retryable = retryable;\r\n return error;\r\n}\r\n\r\nfunction isInventoryFetchError(error: unknown): error is InventoryFetchError {\r\n if (!(error instanceof Error)) {\r\n return false;\r\n }\r\n\r\n return (\r\n \"skuId\" in error &&\r\n \"attempts\" in error &&\r\n \"retryable\" in error &&\r\n typeof (error as Partial<InventoryFetchError>).skuId === \"string\"\r\n );\r\n}\r\n\r\nasync function getInventoryBySkuWithRetry(\r\n vtexApi: AxiosInstance,\r\n skuId: string,\r\n options: GetInventoryBatchOptions\r\n): Promise<InventoryBatchSuccess> {\r\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\r\n const baseRetryDelayMs = Math.max(\r\n 50,\r\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\r\n );\r\n let attempts = 0;\r\n\r\n while (true) {\r\n attempts += 1;\r\n\r\n try {\r\n const document = await getInventoryBySkuWithClient(vtexApi, skuId);\r\n return { skuId, document };\r\n } catch (error) {\r\n const retryable = isRetryableRequestError(error);\r\n\r\n if (!retryable || attempts > maxRetries) {\r\n throw toInventoryFetchError(skuId, error, attempts, retryable);\r\n }\r\n\r\n const retryAfterHeader = axios.isAxiosError(error)\r\n ? error.response?.headers?.[\"retry-after\"]\r\n : undefined;\r\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\r\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\r\n await sleep(delayMs);\r\n }\r\n }\r\n}\r\n\r\nexport async function getInventoryBySkuBatch(\r\n profileId: string,\r\n skuIds: string[],\r\n options: GetInventoryBatchOptions = {}\r\n): Promise<InventoryBatchResult> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const maxConcurrency = Math.max(\r\n 1,\r\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\r\n );\r\n const successful: InventoryBatchSuccess[] = [];\r\n const failed: InventoryBatchFailure[] = [];\r\n\r\n for (let start = 0; start < skuIds.length; start += maxConcurrency) {\r\n const chunk = skuIds.slice(start, start + maxConcurrency);\r\n const settledChunk = await Promise.allSettled(\r\n chunk.map((skuId) => getInventoryBySkuWithRetry(vtexApi, skuId, options))\r\n );\r\n\r\n settledChunk.forEach((result, index) => {\r\n const skuId = chunk[index];\r\n\r\n if (result.status === \"fulfilled\") {\r\n successful.push(result.value);\r\n return;\r\n }\r\n\r\n if (isInventoryFetchError(result.reason)) {\r\n failed.push({\r\n skuId: result.reason.skuId,\r\n message: result.reason.message,\r\n statusCode: result.reason.statusCode,\r\n attempts: result.reason.attempts,\r\n retryable: result.reason.retryable,\r\n });\r\n return;\r\n }\r\n\r\n failed.push({\r\n skuId,\r\n message:\r\n result.reason instanceof Error\r\n ? result.reason.message\r\n : \"Unexpected error while fetching inventory details\",\r\n attempts: 1,\r\n retryable: false,\r\n });\r\n });\r\n }\r\n\r\n return { successful, failed };\r\n}\r\n\r\nexport async function getInventoryByWarehouse(\r\n profileId: string,\r\n skuId: string,\r\n warehouseId: string\r\n): Promise<InventoryByWarehouseItem[]> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<InventoryByWarehouseItem[]>(\r\n `/api/logistics/pvt/inventory/items/${skuId}/warehouses/${warehouseId}`\r\n );\r\n return response.data;\r\n}\r\n\r\nexport async function updateInventoryQuantity(\r\n profileId: string,\r\n skuId: string,\r\n warehouseId: string,\r\n payload: UpdateInventoryQuantityPayload\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/quantity`, payload);\r\n}\r\n\r\nexport async function updateInventoryLeadTime(\r\n profileId: string,\r\n skuId: string,\r\n warehouseId: string,\r\n payload: UpdateLeadTimePayload\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/lead-time`, payload);\r\n}\r\n"],
4
+ "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosInstance } from \"axios\";\n\nimport { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface WarehouseBalance {\n warehouseId?: string;\n warehouseName?: string;\n totalQuantity?: number;\n reservedQuantity?: number;\n availableQuantity?: number;\n isUnlimited?: boolean;\n hasUnlimitedQuantity?: boolean;\n timeToRefill?: string;\n dateOfSupplyUtc?: string;\n leadTime?: string;\n}\n\nexport interface InventoryBySkuResponse {\n skuId?: string;\n balance?: WarehouseBalance[];\n}\n\nexport interface InventoryByWarehouseItem {\n skuId?: string;\n warehouseId?: string;\n totalQuantity?: number;\n reservedQuantity?: number;\n availableQuantity?: number;\n isUnlimited?: boolean;\n keepSellingAfterExpiration?: boolean;\n}\n\nexport interface UpdateInventoryQuantityPayload {\n quantity: number;\n unlimitedQuantity: boolean;\n dateUtcOnBalanceSystem?: string;\n}\n\nexport interface UpdateLeadTimePayload {\n leadTime: string;\n}\n\nexport interface GetInventoryBatchOptions {\n maxConcurrency?: number;\n maxRetries?: number;\n baseRetryDelayMs?: number;\n}\n\nexport interface InventoryBatchSuccess {\n skuId: string;\n document: InventoryBySkuResponse;\n}\n\nexport interface InventoryBatchFailure {\n skuId: string;\n message: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nexport interface InventoryBatchResult {\n successful: InventoryBatchSuccess[];\n failed: InventoryBatchFailure[];\n}\n\ninterface InventoryFetchError extends Error {\n skuId: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\nconst DEFAULT_BATCH_CONCURRENCY = 10;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\n\nexport async function getInventoryBySku(\n profileId: string,\n skuId: string\n): Promise<InventoryBySkuResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\n return response.data;\n}\n\nasync function getInventoryBySkuWithClient(\n vtexApi: AxiosInstance,\n skuId: string\n): Promise<InventoryBySkuResponse> {\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\n return response.data;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\n if (Array.isArray(headerValue)) {\n return parseRetryAfterMs(headerValue[0]);\n }\n\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\n return Math.max(0, Math.floor(headerValue * 1000));\n }\n\n if (typeof headerValue !== \"string\") {\n return undefined;\n }\n\n const trimmedValue = headerValue.trim();\n if (!trimmedValue) {\n return undefined;\n }\n\n const seconds = Number(trimmedValue);\n if (Number.isFinite(seconds)) {\n return Math.max(0, Math.floor(seconds * 1000));\n }\n\n const absoluteDateMs = Date.parse(trimmedValue);\n if (Number.isNaN(absoluteDateMs)) {\n return undefined;\n }\n\n return Math.max(0, absoluteDateMs - Date.now());\n}\n\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n return exponential + jitter;\n}\n\nfunction isRetryableRequestError(error: unknown): boolean {\n if (!axios.isAxiosError(error)) {\n return false;\n }\n\n if (!error.response?.status) {\n return true;\n }\n\n return RETRYABLE_STATUS_CODES.has(error.response.status);\n}\n\nfunction toInventoryFetchError(\n skuId: string,\n source: unknown,\n attempts: number,\n retryable: boolean\n): InventoryFetchError {\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\n const message =\n source instanceof Error\n ? source.message\n : typeof source === \"string\"\n ? source\n : \"Unexpected error while fetching inventory details\";\n\n const error = new Error(message) as InventoryFetchError;\n error.skuId = skuId;\n error.statusCode = statusCode;\n error.attempts = attempts;\n error.retryable = retryable;\n return error;\n}\n\nfunction isInventoryFetchError(error: unknown): error is InventoryFetchError {\n if (!(error instanceof Error)) {\n return false;\n }\n\n return (\n \"skuId\" in error &&\n \"attempts\" in error &&\n \"retryable\" in error &&\n typeof (error as Partial<InventoryFetchError>).skuId === \"string\"\n );\n}\n\nasync function getInventoryBySkuWithRetry(\n vtexApi: AxiosInstance,\n skuId: string,\n options: GetInventoryBatchOptions\n): Promise<InventoryBatchSuccess> {\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\n const baseRetryDelayMs = Math.max(\n 50,\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\n );\n let attempts = 0;\n\n while (true) {\n attempts += 1;\n\n try {\n const document = await getInventoryBySkuWithClient(vtexApi, skuId);\n return { skuId, document };\n } catch (error) {\n const retryable = isRetryableRequestError(error);\n\n if (!retryable || attempts > maxRetries) {\n throw toInventoryFetchError(skuId, error, attempts, retryable);\n }\n\n const retryAfterHeader = axios.isAxiosError(error)\n ? error.response?.headers?.[\"retry-after\"]\n : undefined;\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\n await sleep(delayMs);\n }\n }\n}\n\nexport async function getInventoryBySkuBatch(\n profileId: string,\n skuIds: string[],\n options: GetInventoryBatchOptions = {}\n): Promise<InventoryBatchResult> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const maxConcurrency = Math.max(\n 1,\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\n );\n const successful: InventoryBatchSuccess[] = [];\n const failed: InventoryBatchFailure[] = [];\n\n for (let start = 0; start < skuIds.length; start += maxConcurrency) {\n const chunk = skuIds.slice(start, start + maxConcurrency);\n const settledChunk = await Promise.allSettled(\n chunk.map((skuId) => getInventoryBySkuWithRetry(vtexApi, skuId, options))\n );\n\n settledChunk.forEach((result, index) => {\n const skuId = chunk[index];\n\n if (result.status === \"fulfilled\") {\n successful.push(result.value);\n return;\n }\n\n if (isInventoryFetchError(result.reason)) {\n failed.push({\n skuId: result.reason.skuId,\n message: result.reason.message,\n statusCode: result.reason.statusCode,\n attempts: result.reason.attempts,\n retryable: result.reason.retryable,\n });\n return;\n }\n\n failed.push({\n skuId,\n message:\n result.reason instanceof Error\n ? result.reason.message\n : \"Unexpected error while fetching inventory details\",\n attempts: 1,\n retryable: false,\n });\n });\n }\n\n return { successful, failed };\n}\n\nexport async function getInventoryByWarehouse(\n profileId: string,\n skuId: string,\n warehouseId: string\n): Promise<InventoryByWarehouseItem[]> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<InventoryByWarehouseItem[]>(\n `/api/logistics/pvt/inventory/items/${skuId}/warehouses/${warehouseId}`\n );\n return response.data;\n}\n\nexport async function updateInventoryQuantity(\n profileId: string,\n skuId: string,\n warehouseId: string,\n payload: UpdateInventoryQuantityPayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/quantity`, payload);\n}\n\nexport async function updateInventoryLeadTime(\n profileId: string,\n skuId: string,\n warehouseId: string,\n payload: UpdateLeadTimePayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/lead-time`, payload);\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-orders-write.ts"],
4
- "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\r\nimport { getOrderDocument } from \"./vtex-orders.js\";\r\nimport { VtexOperationError } from \"./vtex-write.js\";\r\n\r\nexport interface VtexInvoiceItemInput {\r\n id: string;\r\n price: number;\r\n quantity: number;\r\n description?: string;\r\n}\r\n\r\nexport interface VtexInvoicePayload {\r\n type: \"Output\" | \"Input\";\r\n issuanceDate: string;\r\n invoiceNumber: string;\r\n invoiceValue: string;\r\n items: VtexInvoiceItemInput[];\r\n invoiceKey?: string;\r\n invoiceUrl?: string;\r\n invoiceOrderNumber?: string;\r\n courier?: string;\r\n trackingNumber?: string;\r\n trackingUrl?: string;\r\n}\r\n\r\nexport interface VtexPartialInvoicePayload {\r\n trackingNumber: string;\r\n trackingUrl?: string | null;\r\n courier?: string | null;\r\n dispatchedDate: string;\r\n}\r\n\r\nexport interface VtexTrackingEventInput {\r\n city: string;\r\n state: string;\r\n description: string;\r\n date: string;\r\n}\r\n\r\nexport interface VtexTrackingStatusPayload {\r\n isDelivered: boolean;\r\n deliveredDate?: string | null;\r\n events: VtexTrackingEventInput[];\r\n}\r\n\r\nexport interface VtexOrderStateSnapshot {\r\n orderId: string;\r\n status?: string;\r\n state?: string;\r\n allowCancellation?: boolean;\r\n invoicedDate?: string;\r\n invoiceNumbers: string[];\r\n}\r\n\r\nfunction toStringArray(value: unknown): string[] {\r\n if (!Array.isArray(value)) {\r\n return [];\r\n }\r\n\r\n return value\r\n .map((item) => (item == null ? undefined : String(item)))\r\n .filter((item): item is string => Boolean(item));\r\n}\r\n\r\nfunction readInvoiceNumbers(document: Record<string, unknown>): string[] {\r\n const invoiceData = document.invoiceData;\r\n if (!invoiceData || typeof invoiceData !== \"object\") {\r\n return [];\r\n }\r\n\r\n const invoices = Array.isArray((invoiceData as Record<string, unknown>).invoices)\r\n ? ((invoiceData as Record<string, unknown>).invoices as Array<Record<string, unknown>>)\r\n : [];\r\n\r\n const fromInvoices = invoices\r\n .map((invoice) => {\r\n const number =\r\n invoice.invoiceNumber ??\r\n invoice.number ??\r\n invoice.invoiceId ??\r\n invoice.receipt;\r\n\r\n return number == null ? undefined : String(number);\r\n })\r\n .filter((item): item is string => Boolean(item));\r\n\r\n const outputInvoices = toStringArray((invoiceData as Record<string, unknown>).invoiceOutput);\r\n return Array.from(new Set([...fromInvoices, ...outputInvoices]));\r\n}\r\n\r\nexport async function getOrderStateSnapshot(\r\n profileId: string,\r\n orderId: string,\r\n reason?: string\r\n): Promise<VtexOrderStateSnapshot> {\r\n const document = await getOrderDocument(profileId, orderId, reason);\r\n\r\n return {\r\n orderId,\r\n status: document.status == null ? undefined : String(document.status),\r\n state: document.state == null ? undefined : String(document.state),\r\n allowCancellation:\r\n typeof document.allowCancellation === \"boolean\" ? document.allowCancellation : undefined,\r\n invoicedDate: document.invoicedDate == null ? undefined : String(document.invoicedDate),\r\n invoiceNumbers: readInvoiceNumbers(document),\r\n };\r\n}\r\n\r\nfunction isCanceledStatus(snapshot: VtexOrderStateSnapshot): boolean {\r\n const states = [snapshot.status, snapshot.state]\r\n .filter(Boolean)\r\n .map((value) => String(value).toLowerCase());\r\n\r\n return states.some((value) => value.includes(\"cancel\"));\r\n}\r\n\r\nfunction ensureOrderCanBeCanceled(snapshot: VtexOrderStateSnapshot): void {\r\n if (isCanceledStatus(snapshot)) {\r\n throw new VtexOperationError(\"Order is already canceled.\", \"INVALID_ORDER_STATE\", {\r\n status: snapshot.status,\r\n state: snapshot.state,\r\n });\r\n }\r\n\r\n if (snapshot.allowCancellation === false) {\r\n throw new VtexOperationError(\r\n \"VTEX reports that this order can no longer be canceled.\",\r\n \"INVALID_ORDER_STATE\",\r\n {\r\n status: snapshot.status,\r\n state: snapshot.state,\r\n }\r\n );\r\n }\r\n\r\n if (snapshot.invoicedDate) {\r\n throw new VtexOperationError(\r\n \"Order is already invoiced, so VTEX no longer allows cancellation.\",\r\n \"INVALID_ORDER_STATE\",\r\n {\r\n invoiced_date: snapshot.invoicedDate,\r\n }\r\n );\r\n }\r\n}\r\n\r\nfunction ensureOrderCanBeInvoiced(snapshot: VtexOrderStateSnapshot): void {\r\n if (isCanceledStatus(snapshot)) {\r\n throw new VtexOperationError(\"Canceled orders cannot be invoiced.\", \"INVALID_ORDER_STATE\", {\r\n status: snapshot.status,\r\n state: snapshot.state,\r\n });\r\n }\r\n\r\n if (snapshot.invoicedDate || snapshot.invoiceNumbers.length > 0) {\r\n throw new VtexOperationError(\"Order already contains invoice data.\", \"INVALID_ORDER_STATE\", {\r\n invoiced_date: snapshot.invoicedDate,\r\n invoice_numbers: snapshot.invoiceNumbers,\r\n });\r\n }\r\n}\r\n\r\nfunction ensureOrderCanReceiveTracking(snapshot: VtexOrderStateSnapshot, invoiceNumber: string): void {\r\n if (isCanceledStatus(snapshot)) {\r\n throw new VtexOperationError(\r\n \"Canceled orders cannot receive tracking updates.\",\r\n \"INVALID_ORDER_STATE\",\r\n {\r\n status: snapshot.status,\r\n state: snapshot.state,\r\n }\r\n );\r\n }\r\n\r\n if (!snapshot.invoicedDate && snapshot.invoiceNumbers.length === 0) {\r\n throw new VtexOperationError(\r\n \"Order is not invoiced yet, so tracking cannot be added.\",\r\n \"INVALID_ORDER_STATE\",\r\n {\r\n status: snapshot.status,\r\n state: snapshot.state,\r\n }\r\n );\r\n }\r\n\r\n if (snapshot.invoiceNumbers.length > 0 && !snapshot.invoiceNumbers.includes(invoiceNumber)) {\r\n throw new VtexOperationError(\r\n \"The provided invoice number is not present in VTEX for this order.\",\r\n \"INVALID_OPERATION\",\r\n {\r\n provided_invoice_number: invoiceNumber,\r\n known_invoice_numbers: snapshot.invoiceNumbers,\r\n }\r\n );\r\n }\r\n}\r\n\r\nexport async function cancelOrder(\r\n profileId: string,\r\n orderId: string,\r\n reason?: string\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.post(`/api/oms/pvt/orders/${orderId}/cancel`, reason ? { reason } : {});\r\n}\r\n\r\nexport async function invoiceOrder(\r\n profileId: string,\r\n orderId: string,\r\n payload: VtexInvoicePayload\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.post(`/api/oms/pvt/orders/${orderId}/invoice`, payload);\r\n}\r\n\r\nexport async function updatePartialInvoiceTracking(\r\n profileId: string,\r\n orderId: string,\r\n invoiceNumber: string,\r\n payload: VtexPartialInvoicePayload\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.patch(`/api/oms/pvt/orders/${orderId}/invoice/${invoiceNumber}`, payload);\r\n}\r\n\r\nexport async function updateOrderTrackingStatus(\r\n profileId: string,\r\n orderId: string,\r\n invoiceNumber: string,\r\n payload: VtexTrackingStatusPayload\r\n): Promise<void> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n await vtexApi.put(`/api/oms/pvt/orders/${orderId}/invoice/${invoiceNumber}/tracking`, payload);\r\n}\r\n\r\nexport async function validateOrderForCancellation(\r\n profileId: string,\r\n orderId: string,\r\n reason?: string\r\n): Promise<VtexOrderStateSnapshot> {\r\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\r\n ensureOrderCanBeCanceled(snapshot);\r\n return snapshot;\r\n}\r\n\r\nexport async function validateOrderForInvoice(\r\n profileId: string,\r\n orderId: string,\r\n reason?: string\r\n): Promise<VtexOrderStateSnapshot> {\r\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\r\n ensureOrderCanBeInvoiced(snapshot);\r\n return snapshot;\r\n}\r\n\r\nexport async function validateOrderForTracking(\r\n profileId: string,\r\n orderId: string,\r\n invoiceNumber: string,\r\n reason?: string\r\n): Promise<VtexOrderStateSnapshot> {\r\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\r\n ensureOrderCanReceiveTracking(snapshot, invoiceNumber);\r\n return snapshot;\r\n}\r\n"],
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\nimport { getOrderDocument } from \"./vtex-orders.js\";\nimport { VtexOperationError } from \"./vtex-write.js\";\n\nexport interface VtexInvoiceItemInput {\n id: string;\n price: number;\n quantity: number;\n description?: string;\n}\n\nexport interface VtexInvoicePayload {\n type: \"Output\" | \"Input\";\n issuanceDate: string;\n invoiceNumber: string;\n invoiceValue: string;\n items: VtexInvoiceItemInput[];\n invoiceKey?: string;\n invoiceUrl?: string;\n invoiceOrderNumber?: string;\n courier?: string;\n trackingNumber?: string;\n trackingUrl?: string;\n}\n\nexport interface VtexPartialInvoicePayload {\n trackingNumber: string;\n trackingUrl?: string | null;\n courier?: string | null;\n dispatchedDate: string;\n}\n\nexport interface VtexTrackingEventInput {\n city: string;\n state: string;\n description: string;\n date: string;\n}\n\nexport interface VtexTrackingStatusPayload {\n isDelivered: boolean;\n deliveredDate?: string | null;\n events: VtexTrackingEventInput[];\n}\n\nexport interface VtexOrderStateSnapshot {\n orderId: string;\n status?: string;\n state?: string;\n allowCancellation?: boolean;\n invoicedDate?: string;\n invoiceNumbers: string[];\n}\n\nfunction toStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .map((item) => (item == null ? undefined : String(item)))\n .filter((item): item is string => Boolean(item));\n}\n\nfunction readInvoiceNumbers(document: Record<string, unknown>): string[] {\n const invoiceData = document.invoiceData;\n if (!invoiceData || typeof invoiceData !== \"object\") {\n return [];\n }\n\n const invoices = Array.isArray((invoiceData as Record<string, unknown>).invoices)\n ? ((invoiceData as Record<string, unknown>).invoices as Array<Record<string, unknown>>)\n : [];\n\n const fromInvoices = invoices\n .map((invoice) => {\n const number =\n invoice.invoiceNumber ??\n invoice.number ??\n invoice.invoiceId ??\n invoice.receipt;\n\n return number == null ? undefined : String(number);\n })\n .filter((item): item is string => Boolean(item));\n\n const outputInvoices = toStringArray((invoiceData as Record<string, unknown>).invoiceOutput);\n return Array.from(new Set([...fromInvoices, ...outputInvoices]));\n}\n\nexport async function getOrderStateSnapshot(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<VtexOrderStateSnapshot> {\n const document = await getOrderDocument(profileId, orderId, reason);\n\n return {\n orderId,\n status: document.status == null ? undefined : String(document.status),\n state: document.state == null ? undefined : String(document.state),\n allowCancellation:\n typeof document.allowCancellation === \"boolean\" ? document.allowCancellation : undefined,\n invoicedDate: document.invoicedDate == null ? undefined : String(document.invoicedDate),\n invoiceNumbers: readInvoiceNumbers(document),\n };\n}\n\nfunction isCanceledStatus(snapshot: VtexOrderStateSnapshot): boolean {\n const states = [snapshot.status, snapshot.state]\n .filter(Boolean)\n .map((value) => String(value).toLowerCase());\n\n return states.some((value) => value.includes(\"cancel\"));\n}\n\nfunction ensureOrderCanBeCanceled(snapshot: VtexOrderStateSnapshot): void {\n if (isCanceledStatus(snapshot)) {\n throw new VtexOperationError(\"Order is already canceled.\", \"INVALID_ORDER_STATE\", {\n status: snapshot.status,\n state: snapshot.state,\n });\n }\n\n if (snapshot.allowCancellation === false) {\n throw new VtexOperationError(\n \"VTEX reports that this order can no longer be canceled.\",\n \"INVALID_ORDER_STATE\",\n {\n status: snapshot.status,\n state: snapshot.state,\n }\n );\n }\n\n if (snapshot.invoicedDate) {\n throw new VtexOperationError(\n \"Order is already invoiced, so VTEX no longer allows cancellation.\",\n \"INVALID_ORDER_STATE\",\n {\n invoiced_date: snapshot.invoicedDate,\n }\n );\n }\n}\n\nfunction ensureOrderCanBeInvoiced(snapshot: VtexOrderStateSnapshot): void {\n if (isCanceledStatus(snapshot)) {\n throw new VtexOperationError(\"Canceled orders cannot be invoiced.\", \"INVALID_ORDER_STATE\", {\n status: snapshot.status,\n state: snapshot.state,\n });\n }\n\n if (snapshot.invoicedDate || snapshot.invoiceNumbers.length > 0) {\n throw new VtexOperationError(\"Order already contains invoice data.\", \"INVALID_ORDER_STATE\", {\n invoiced_date: snapshot.invoicedDate,\n invoice_numbers: snapshot.invoiceNumbers,\n });\n }\n}\n\nfunction ensureOrderCanReceiveTracking(snapshot: VtexOrderStateSnapshot, invoiceNumber: string): void {\n if (isCanceledStatus(snapshot)) {\n throw new VtexOperationError(\n \"Canceled orders cannot receive tracking updates.\",\n \"INVALID_ORDER_STATE\",\n {\n status: snapshot.status,\n state: snapshot.state,\n }\n );\n }\n\n if (!snapshot.invoicedDate && snapshot.invoiceNumbers.length === 0) {\n throw new VtexOperationError(\n \"Order is not invoiced yet, so tracking cannot be added.\",\n \"INVALID_ORDER_STATE\",\n {\n status: snapshot.status,\n state: snapshot.state,\n }\n );\n }\n\n if (snapshot.invoiceNumbers.length > 0 && !snapshot.invoiceNumbers.includes(invoiceNumber)) {\n throw new VtexOperationError(\n \"The provided invoice number is not present in VTEX for this order.\",\n \"INVALID_OPERATION\",\n {\n provided_invoice_number: invoiceNumber,\n known_invoice_numbers: snapshot.invoiceNumbers,\n }\n );\n }\n}\n\nexport async function cancelOrder(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.post(`/api/oms/pvt/orders/${orderId}/cancel`, reason ? { reason } : {});\n}\n\nexport async function invoiceOrder(\n profileId: string,\n orderId: string,\n payload: VtexInvoicePayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.post(`/api/oms/pvt/orders/${orderId}/invoice`, payload);\n}\n\nexport async function updatePartialInvoiceTracking(\n profileId: string,\n orderId: string,\n invoiceNumber: string,\n payload: VtexPartialInvoicePayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.patch(`/api/oms/pvt/orders/${orderId}/invoice/${invoiceNumber}`, payload);\n}\n\nexport async function updateOrderTrackingStatus(\n profileId: string,\n orderId: string,\n invoiceNumber: string,\n payload: VtexTrackingStatusPayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.put(`/api/oms/pvt/orders/${orderId}/invoice/${invoiceNumber}/tracking`, payload);\n}\n\nexport async function validateOrderForCancellation(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<VtexOrderStateSnapshot> {\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\n ensureOrderCanBeCanceled(snapshot);\n return snapshot;\n}\n\nexport async function validateOrderForInvoice(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<VtexOrderStateSnapshot> {\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\n ensureOrderCanBeInvoiced(snapshot);\n return snapshot;\n}\n\nexport async function validateOrderForTracking(\n profileId: string,\n orderId: string,\n invoiceNumber: string,\n reason?: string\n): Promise<VtexOrderStateSnapshot> {\n const snapshot = await getOrderStateSnapshot(profileId, orderId, reason);\n ensureOrderCanReceiveTracking(snapshot, invoiceNumber);\n return snapshot;\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-orders.ts"],
4
- "sourcesContent": ["import axios from \"axios\";\r\nimport type { AxiosInstance } from \"axios\";\r\n\r\nimport { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport interface VtexOrderListItem {\r\n orderId: string;\r\n creationDate?: string;\r\n status?: string;\r\n totalValue?: number;\r\n currencyCode?: string;\r\n paymentNames?: string;\r\n salesChannel?: string;\r\n origin?: string;\r\n totalItems?: number;\r\n lastChange?: string;\r\n orderIsComplete?: boolean;\r\n authorizedDate?: string;\r\n paymentApprovedDate?: string;\r\n readyForHandlingDate?: string;\r\n}\r\n\r\nexport interface VtexOrdersPaging {\r\n total?: number;\r\n pages?: number;\r\n currentPage?: number;\r\n perPage?: number;\r\n}\r\n\r\nexport interface VtexOrdersListResponse {\r\n list: VtexOrderListItem[];\r\n paging: VtexOrdersPaging;\r\n stats?: unknown;\r\n}\r\n\r\nexport interface ListOrdersParams {\r\n page?: number;\r\n per_page?: number;\r\n orderBy?: string;\r\n f_creationDate?: string;\r\n f_invoicedDate?: string;\r\n f_status?: string;\r\n f_salesChannel?: string;\r\n f_paymentNames?: string;\r\n f_UtmSource?: string;\r\n q?: string;\r\n}\r\n\r\nexport interface GetOrderDocumentsBatchOptions {\r\n reason?: string;\r\n maxConcurrency?: number;\r\n maxRetries?: number;\r\n baseRetryDelayMs?: number;\r\n}\r\n\r\nexport interface OrderDocumentSuccess {\r\n orderId: string;\r\n document: Record<string, unknown>;\r\n}\r\n\r\nexport interface OrderDocumentFailure {\r\n orderId: string;\r\n message: string;\r\n statusCode?: number;\r\n attempts: number;\r\n retryable: boolean;\r\n}\r\n\r\nexport interface OrderDocumentsBatchResult {\r\n successful: OrderDocumentSuccess[];\r\n failed: OrderDocumentFailure[];\r\n}\r\n\r\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\r\nconst DEFAULT_BATCH_CONCURRENCY = 10;\r\nconst DEFAULT_MAX_RETRIES = 2;\r\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\r\n\r\nexport async function listOrders(\r\n profileId: string,\r\n params: ListOrdersParams\r\n): Promise<VtexOrdersListResponse> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<VtexOrdersListResponse>(\"/api/oms/pvt/orders\", { params });\r\n return response.data;\r\n}\r\n\r\nexport async function getOrderDocument(\r\n profileId: string,\r\n orderId: string,\r\n reason?: string\r\n): Promise<Record<string, unknown>> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\r\n params: reason ? { reason } : undefined,\r\n });\r\n\r\n return response.data;\r\n}\r\n\r\ninterface OrderDocumentFetchError extends Error {\r\n orderId: string;\r\n statusCode?: number;\r\n attempts: number;\r\n retryable: boolean;\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => {\r\n setTimeout(resolve, ms);\r\n });\r\n}\r\n\r\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\r\n if (Array.isArray(headerValue)) {\r\n return parseRetryAfterMs(headerValue[0]);\r\n }\r\n\r\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\r\n return Math.max(0, Math.floor(headerValue * 1000));\r\n }\r\n\r\n if (typeof headerValue !== \"string\") {\r\n return undefined;\r\n }\r\n\r\n const trimmedValue = headerValue.trim();\r\n if (!trimmedValue) {\r\n return undefined;\r\n }\r\n\r\n const seconds = Number(trimmedValue);\r\n if (Number.isFinite(seconds)) {\r\n return Math.max(0, Math.floor(seconds * 1000));\r\n }\r\n\r\n const absoluteDateMs = Date.parse(trimmedValue);\r\n if (Number.isNaN(absoluteDateMs)) {\r\n return undefined;\r\n }\r\n\r\n return Math.max(0, absoluteDateMs - Date.now());\r\n}\r\n\r\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\r\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\r\n const jitter = Math.floor(Math.random() * 150);\r\n return exponential + jitter;\r\n}\r\n\r\nfunction isRetryableRequestError(error: unknown): boolean {\r\n if (!axios.isAxiosError(error)) {\r\n return false;\r\n }\r\n\r\n if (!error.response?.status) {\r\n return true;\r\n }\r\n\r\n return RETRYABLE_STATUS_CODES.has(error.response.status);\r\n}\r\n\r\nfunction toOrderDocumentFetchError(\r\n orderId: string,\r\n source: unknown,\r\n attempts: number,\r\n retryable: boolean\r\n): OrderDocumentFetchError {\r\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\r\n const message =\r\n source instanceof Error\r\n ? source.message\r\n : typeof source === \"string\"\r\n ? source\r\n : \"Unexpected error while fetching order details\";\r\n\r\n const error = new Error(message) as OrderDocumentFetchError;\r\n error.orderId = orderId;\r\n error.statusCode = statusCode;\r\n error.attempts = attempts;\r\n error.retryable = retryable;\r\n return error;\r\n}\r\n\r\nfunction isOrderDocumentFetchError(error: unknown): error is OrderDocumentFetchError {\r\n if (!(error instanceof Error)) {\r\n return false;\r\n }\r\n\r\n return (\r\n \"orderId\" in error &&\r\n \"attempts\" in error &&\r\n \"retryable\" in error &&\r\n typeof (error as Partial<OrderDocumentFetchError>).orderId === \"string\"\r\n );\r\n}\r\n\r\nasync function getOrderDocumentWithRetry(\r\n vtexApi: AxiosInstance,\r\n orderId: string,\r\n options: GetOrderDocumentsBatchOptions\r\n): Promise<OrderDocumentSuccess> {\r\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\r\n const baseRetryDelayMs = Math.max(\r\n 50,\r\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\r\n );\r\n let attempts = 0;\r\n\r\n while (true) {\r\n attempts += 1;\r\n\r\n try {\r\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\r\n params: options.reason ? { reason: options.reason } : undefined,\r\n });\r\n const document = response.data;\r\n return { orderId, document };\r\n } catch (error) {\r\n const retryable = isRetryableRequestError(error);\r\n\r\n if (!retryable || attempts > maxRetries) {\r\n throw toOrderDocumentFetchError(orderId, error, attempts, retryable);\r\n }\r\n\r\n const retryAfterHeader = axios.isAxiosError(error)\r\n ? error.response?.headers?.[\"retry-after\"]\r\n : undefined;\r\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\r\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\r\n await sleep(delayMs);\r\n }\r\n }\r\n}\r\n\r\nexport async function getOrderDocumentsBatch(\r\n profileId: string,\r\n orderIds: string[],\r\n options: GetOrderDocumentsBatchOptions = {}\r\n): Promise<OrderDocumentsBatchResult> {\r\n const { vtexApi } = await getVtexApiClients(profileId);\r\n const maxConcurrency = Math.max(\r\n 1,\r\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\r\n );\r\n const successful: OrderDocumentSuccess[] = [];\r\n const failed: OrderDocumentFailure[] = [];\r\n\r\n for (let start = 0; start < orderIds.length; start += maxConcurrency) {\r\n const chunk = orderIds.slice(start, start + maxConcurrency);\r\n const settledChunk = await Promise.allSettled(\r\n chunk.map((orderId) => getOrderDocumentWithRetry(vtexApi, orderId, options))\r\n );\r\n\r\n settledChunk.forEach((result, index) => {\r\n const orderId = chunk[index];\r\n\r\n if (result.status === \"fulfilled\") {\r\n successful.push(result.value);\r\n return;\r\n }\r\n\r\n if (isOrderDocumentFetchError(result.reason)) {\r\n failed.push({\r\n orderId: result.reason.orderId,\r\n message: result.reason.message,\r\n statusCode: result.reason.statusCode,\r\n attempts: result.reason.attempts,\r\n retryable: result.reason.retryable,\r\n });\r\n return;\r\n }\r\n\r\n failed.push({\r\n orderId,\r\n message:\r\n result.reason instanceof Error\r\n ? result.reason.message\r\n : \"Unexpected error while fetching order details\",\r\n attempts: 1,\r\n retryable: false,\r\n });\r\n });\r\n }\r\n\r\n return { successful, failed };\r\n}\r\n"],
4
+ "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosInstance } from \"axios\";\n\nimport { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface VtexOrderListItem {\n orderId: string;\n creationDate?: string;\n status?: string;\n totalValue?: number;\n currencyCode?: string;\n paymentNames?: string;\n salesChannel?: string;\n origin?: string;\n totalItems?: number;\n lastChange?: string;\n orderIsComplete?: boolean;\n authorizedDate?: string;\n paymentApprovedDate?: string;\n readyForHandlingDate?: string;\n}\n\nexport interface VtexOrdersPaging {\n total?: number;\n pages?: number;\n currentPage?: number;\n perPage?: number;\n}\n\nexport interface VtexOrdersListResponse {\n list: VtexOrderListItem[];\n paging: VtexOrdersPaging;\n stats?: unknown;\n}\n\nexport interface ListOrdersParams {\n page?: number;\n per_page?: number;\n orderBy?: string;\n f_creationDate?: string;\n f_invoicedDate?: string;\n f_status?: string;\n f_salesChannel?: string;\n f_paymentNames?: string;\n f_UtmSource?: string;\n q?: string;\n}\n\nexport interface GetOrderDocumentsBatchOptions {\n reason?: string;\n maxConcurrency?: number;\n maxRetries?: number;\n baseRetryDelayMs?: number;\n}\n\nexport interface OrderDocumentSuccess {\n orderId: string;\n document: Record<string, unknown>;\n}\n\nexport interface OrderDocumentFailure {\n orderId: string;\n message: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nexport interface OrderDocumentsBatchResult {\n successful: OrderDocumentSuccess[];\n failed: OrderDocumentFailure[];\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\nconst DEFAULT_BATCH_CONCURRENCY = 10;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\n\nexport async function listOrders(\n profileId: string,\n params: ListOrdersParams\n): Promise<VtexOrdersListResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<VtexOrdersListResponse>(\"/api/oms/pvt/orders\", { params });\n return response.data;\n}\n\nexport async function getOrderDocument(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\n params: reason ? { reason } : undefined,\n });\n\n return response.data;\n}\n\ninterface OrderDocumentFetchError extends Error {\n orderId: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\n if (Array.isArray(headerValue)) {\n return parseRetryAfterMs(headerValue[0]);\n }\n\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\n return Math.max(0, Math.floor(headerValue * 1000));\n }\n\n if (typeof headerValue !== \"string\") {\n return undefined;\n }\n\n const trimmedValue = headerValue.trim();\n if (!trimmedValue) {\n return undefined;\n }\n\n const seconds = Number(trimmedValue);\n if (Number.isFinite(seconds)) {\n return Math.max(0, Math.floor(seconds * 1000));\n }\n\n const absoluteDateMs = Date.parse(trimmedValue);\n if (Number.isNaN(absoluteDateMs)) {\n return undefined;\n }\n\n return Math.max(0, absoluteDateMs - Date.now());\n}\n\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n return exponential + jitter;\n}\n\nfunction isRetryableRequestError(error: unknown): boolean {\n if (!axios.isAxiosError(error)) {\n return false;\n }\n\n if (!error.response?.status) {\n return true;\n }\n\n return RETRYABLE_STATUS_CODES.has(error.response.status);\n}\n\nfunction toOrderDocumentFetchError(\n orderId: string,\n source: unknown,\n attempts: number,\n retryable: boolean\n): OrderDocumentFetchError {\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\n const message =\n source instanceof Error\n ? source.message\n : typeof source === \"string\"\n ? source\n : \"Unexpected error while fetching order details\";\n\n const error = new Error(message) as OrderDocumentFetchError;\n error.orderId = orderId;\n error.statusCode = statusCode;\n error.attempts = attempts;\n error.retryable = retryable;\n return error;\n}\n\nfunction isOrderDocumentFetchError(error: unknown): error is OrderDocumentFetchError {\n if (!(error instanceof Error)) {\n return false;\n }\n\n return (\n \"orderId\" in error &&\n \"attempts\" in error &&\n \"retryable\" in error &&\n typeof (error as Partial<OrderDocumentFetchError>).orderId === \"string\"\n );\n}\n\nasync function getOrderDocumentWithRetry(\n vtexApi: AxiosInstance,\n orderId: string,\n options: GetOrderDocumentsBatchOptions\n): Promise<OrderDocumentSuccess> {\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\n const baseRetryDelayMs = Math.max(\n 50,\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\n );\n let attempts = 0;\n\n while (true) {\n attempts += 1;\n\n try {\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\n params: options.reason ? { reason: options.reason } : undefined,\n });\n const document = response.data;\n return { orderId, document };\n } catch (error) {\n const retryable = isRetryableRequestError(error);\n\n if (!retryable || attempts > maxRetries) {\n throw toOrderDocumentFetchError(orderId, error, attempts, retryable);\n }\n\n const retryAfterHeader = axios.isAxiosError(error)\n ? error.response?.headers?.[\"retry-after\"]\n : undefined;\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\n await sleep(delayMs);\n }\n }\n}\n\nexport async function getOrderDocumentsBatch(\n profileId: string,\n orderIds: string[],\n options: GetOrderDocumentsBatchOptions = {}\n): Promise<OrderDocumentsBatchResult> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const maxConcurrency = Math.max(\n 1,\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\n );\n const successful: OrderDocumentSuccess[] = [];\n const failed: OrderDocumentFailure[] = [];\n\n for (let start = 0; start < orderIds.length; start += maxConcurrency) {\n const chunk = orderIds.slice(start, start + maxConcurrency);\n const settledChunk = await Promise.allSettled(\n chunk.map((orderId) => getOrderDocumentWithRetry(vtexApi, orderId, options))\n );\n\n settledChunk.forEach((result, index) => {\n const orderId = chunk[index];\n\n if (result.status === \"fulfilled\") {\n successful.push(result.value);\n return;\n }\n\n if (isOrderDocumentFetchError(result.reason)) {\n failed.push({\n orderId: result.reason.orderId,\n message: result.reason.message,\n statusCode: result.reason.statusCode,\n attempts: result.reason.attempts,\n retryable: result.reason.retryable,\n });\n return;\n }\n\n failed.push({\n orderId,\n message:\n result.reason instanceof Error\n ? result.reason.message\n : \"Unexpected error while fetching order details\",\n attempts: 1,\n retryable: false,\n });\n });\n }\n\n return { successful, failed };\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-pricing-write.ts"],
4
- "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport interface VtexFixedPriceInput {\r\n minQuantity: number;\r\n value: number;\r\n listPrice?: number;\r\n dateRange?: {\r\n from: string;\r\n to: string;\r\n };\r\n}\r\n\r\nexport interface VtexSkuPriceWritePayload {\r\n basePrice?: number;\r\n costPrice?: number;\r\n markup?: number;\r\n listPrice?: number;\r\n fixedPrices?: Array<{\r\n tradePolicyId: string;\r\n value: number;\r\n listPrice?: number;\r\n minQuantity: number;\r\n dateRange?: {\r\n from: string;\r\n to: string;\r\n };\r\n }>;\r\n}\r\n\r\nexport async function updateSkuPrice(\r\n profileId: string,\r\n itemId: string,\r\n payload: VtexSkuPriceWritePayload\r\n): Promise<void> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n await vtexPricingApi.put(`/pricing/prices/${itemId}`, payload);\r\n}\r\n\r\nexport async function patchFixedPrices(\r\n profileId: string,\r\n itemId: string,\r\n payload: VtexFixedPriceInput[]\r\n): Promise<void> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n await vtexPricingApi.patch(`/pricing/prices/${itemId}/fixed`, payload);\r\n}\r\n\r\nexport async function upsertFixedPricesForPriceTable(\r\n profileId: string,\r\n itemId: string,\r\n priceTableId: string,\r\n payload: VtexFixedPriceInput[]\r\n): Promise<void> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n await vtexPricingApi.post(`/pricing/prices/${itemId}/fixed/${priceTableId}`, payload);\r\n}\r\n\r\nexport async function deleteFixedPricesForPriceTable(\r\n profileId: string,\r\n itemId: string,\r\n priceTableId: string\r\n): Promise<void> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n await vtexPricingApi.delete(`/pricing/prices/${itemId}/fixed/${priceTableId}`);\r\n}\r\n"],
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface VtexFixedPriceInput {\n minQuantity: number;\n value: number;\n listPrice?: number;\n dateRange?: {\n from: string;\n to: string;\n };\n}\n\nexport interface VtexSkuPriceWritePayload {\n basePrice?: number;\n costPrice?: number;\n markup?: number;\n listPrice?: number;\n fixedPrices?: Array<{\n tradePolicyId: string;\n value: number;\n listPrice?: number;\n minQuantity: number;\n dateRange?: {\n from: string;\n to: string;\n };\n }>;\n}\n\nexport async function updateSkuPrice(\n profileId: string,\n itemId: string,\n payload: VtexSkuPriceWritePayload\n): Promise<void> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n await vtexPricingApi.put(`/pricing/prices/${itemId}`, payload);\n}\n\nexport async function patchFixedPrices(\n profileId: string,\n itemId: string,\n payload: VtexFixedPriceInput[]\n): Promise<void> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n await vtexPricingApi.patch(`/pricing/prices/${itemId}/fixed`, payload);\n}\n\nexport async function upsertFixedPricesForPriceTable(\n profileId: string,\n itemId: string,\n priceTableId: string,\n payload: VtexFixedPriceInput[]\n): Promise<void> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n await vtexPricingApi.post(`/pricing/prices/${itemId}/fixed/${priceTableId}`, payload);\n}\n\nexport async function deleteFixedPricesForPriceTable(\n profileId: string,\n itemId: string,\n priceTableId: string\n): Promise<void> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n await vtexPricingApi.delete(`/pricing/prices/${itemId}/fixed/${priceTableId}`);\n}\n"],
5
5
  "mappings": "AAAA,SAAS,yBAAyB;AA6BlC,eAAsB,eACpB,WACA,QACA,SACe;AACf,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,eAAe,IAAI,mBAAmB,MAAM,IAAI,OAAO;AAC/D;AAEA,eAAsB,iBACpB,WACA,QACA,SACe;AACf,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,eAAe,MAAM,mBAAmB,MAAM,UAAU,OAAO;AACvE;AAEA,eAAsB,+BACpB,WACA,QACA,cACA,SACe;AACf,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,eAAe,KAAK,mBAAmB,MAAM,UAAU,YAAY,IAAI,OAAO;AACtF;AAEA,eAAsB,+BACpB,WACA,QACA,cACe;AACf,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,eAAe,OAAO,mBAAmB,MAAM,UAAU,YAAY,EAAE;AAC/E;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-pricing.ts"],
4
- "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\r\n\r\nexport interface SkuFixedPrice {\r\n value?: number;\r\n listPrice?: number;\r\n minQuantity?: number;\r\n dateRange?: {\r\n from?: string;\r\n to?: string;\r\n };\r\n tradePolicyId?: string;\r\n}\r\n\r\nexport interface SkuPriceResponse {\r\n itemId: string;\r\n listPrice: number;\r\n costPrice: number;\r\n markup: number;\r\n basePrice: number;\r\n fixedPrices: SkuFixedPrice[];\r\n}\r\n\r\nexport interface ComputedPriceParams {\r\n categoryId: number;\r\n brandId: number;\r\n quantity: number;\r\n}\r\n\r\nexport interface ComputedPriceResponse {\r\n tradePolicyId: string;\r\n listPrice: number;\r\n costPrice?: number;\r\n sellingPrice: number;\r\n priceValidUntil: string;\r\n}\r\n\r\nexport async function getSkuPrice(\r\n profileId: string,\r\n itemId: string\r\n): Promise<SkuPriceResponse> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n const response = await vtexPricingApi.get<SkuPriceResponse>(`/pricing/prices/${itemId}`);\r\n return response.data;\r\n}\r\n\r\nexport async function getComputedPrice(\r\n profileId: string,\r\n itemId: string,\r\n priceTableId: string,\r\n params: ComputedPriceParams\r\n): Promise<ComputedPriceResponse> {\r\n const { vtexPricingApi } = await getVtexApiClients(profileId);\r\n const response = await vtexPricingApi.get<ComputedPriceResponse>(\r\n `/pricing/prices/${itemId}/computed/${priceTableId}`,\r\n { params }\r\n );\r\n\r\n return response.data;\r\n}\r\n"],
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface SkuFixedPrice {\n value?: number;\n listPrice?: number;\n minQuantity?: number;\n dateRange?: {\n from?: string;\n to?: string;\n };\n tradePolicyId?: string;\n}\n\nexport interface SkuPriceResponse {\n itemId: string;\n listPrice: number;\n costPrice: number;\n markup: number;\n basePrice: number;\n fixedPrices: SkuFixedPrice[];\n}\n\nexport interface ComputedPriceParams {\n categoryId: number;\n brandId: number;\n quantity: number;\n}\n\nexport interface ComputedPriceResponse {\n tradePolicyId: string;\n listPrice: number;\n costPrice?: number;\n sellingPrice: number;\n priceValidUntil: string;\n}\n\nexport async function getSkuPrice(\n profileId: string,\n itemId: string\n): Promise<SkuPriceResponse> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n const response = await vtexPricingApi.get<SkuPriceResponse>(`/pricing/prices/${itemId}`);\n return response.data;\n}\n\nexport async function getComputedPrice(\n profileId: string,\n itemId: string,\n priceTableId: string,\n params: ComputedPriceParams\n): Promise<ComputedPriceResponse> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n const response = await vtexPricingApi.get<ComputedPriceResponse>(\n `/pricing/prices/${itemId}/computed/${priceTableId}`,\n { params }\n );\n\n return response.data;\n}\n"],
5
5
  "mappings": "AAAA,SAAS,yBAAyB;AAoClC,eAAsB,YACpB,WACA,QAC2B;AAC3B,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,WAAW,MAAM,eAAe,IAAsB,mBAAmB,MAAM,EAAE;AACvF,SAAO,SAAS;AAClB;AAEA,eAAsB,iBACpB,WACA,QACA,cACA,QACgC;AAChC,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,WAAW,MAAM,eAAe;AAAA,IACpC,mBAAmB,MAAM,aAAa,YAAY;AAAA,IAClD,EAAE,OAAO;AAAA,EACX;AAEA,SAAO,SAAS;AAClB;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-write.ts"],
4
- "sourcesContent": ["export type VtexWriteRiskLevel = \"low\" | \"high\";\r\n\r\nexport type VtexWriteErrorCode =\r\n | \"EXPLICIT_CONFIRMATION_REQUIRED\"\r\n | \"INVALID_ORDER_STATE\"\r\n | \"RESOURCE_NOT_FOUND\"\r\n | \"INVALID_OPERATION\";\r\n\r\nexport interface VtexWriteSummary extends Record<string, unknown> {\r\n before?: Record<string, unknown> | null;\r\n after?: Record<string, unknown> | null;\r\n}\r\n\r\nexport interface VtexWriteResult extends Record<string, unknown> {\r\n success: boolean;\r\n profile_id?: string;\r\n operation: string;\r\n resource_id?: string;\r\n risk_level: VtexWriteRiskLevel;\r\n confirmed?: boolean;\r\n message: string;\r\n summary?: VtexWriteSummary;\r\n confirmation_note?: string;\r\n details?: Record<string, unknown>;\r\n}\r\n\r\nexport interface VtexWriteErrorResult extends Record<string, unknown> {\r\n success: false;\r\n error_code: VtexWriteErrorCode;\r\n message: string;\r\n operation: string;\r\n risk_level: VtexWriteRiskLevel;\r\n details?: Record<string, unknown>;\r\n}\r\n\r\nexport class VtexOperationError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly code: VtexWriteErrorCode,\r\n public readonly details?: Record<string, unknown>\r\n ) {\r\n super(message);\r\n this.name = \"VtexOperationError\";\r\n }\r\n}\r\n\r\nexport function buildConfirmationRequiredResult(\r\n operation: string,\r\n details?: Record<string, unknown>\r\n): VtexWriteErrorResult {\r\n return {\r\n success: false,\r\n error_code: \"EXPLICIT_CONFIRMATION_REQUIRED\",\r\n message: \"This VTEX operation is high-risk and requires explicit user confirmation before execution.\",\r\n operation,\r\n risk_level: \"high\",\r\n details,\r\n };\r\n}\r\n\r\nexport function buildWriteSuccessResult(params: {\r\n profileId: string;\r\n operation: string;\r\n resourceId?: string;\r\n riskLevel: VtexWriteRiskLevel;\r\n confirmed?: boolean;\r\n message: string;\r\n summary?: VtexWriteSummary;\r\n confirmationNote?: string;\r\n details?: Record<string, unknown>;\r\n}): VtexWriteResult {\r\n return {\r\n success: true,\r\n profile_id: params.profileId,\r\n operation: params.operation,\r\n resource_id: params.resourceId,\r\n risk_level: params.riskLevel,\r\n confirmed: params.confirmed,\r\n message: params.message,\r\n summary: params.summary,\r\n confirmation_note: params.confirmationNote,\r\n details: params.details,\r\n };\r\n}\r\n"],
4
+ "sourcesContent": ["export type VtexWriteRiskLevel = \"low\" | \"high\";\n\nexport type VtexWriteErrorCode =\n | \"EXPLICIT_CONFIRMATION_REQUIRED\"\n | \"INVALID_ORDER_STATE\"\n | \"RESOURCE_NOT_FOUND\"\n | \"INVALID_OPERATION\";\n\nexport interface VtexWriteSummary extends Record<string, unknown> {\n before?: Record<string, unknown> | null;\n after?: Record<string, unknown> | null;\n}\n\nexport interface VtexWriteResult extends Record<string, unknown> {\n success: boolean;\n profile_id?: string;\n operation: string;\n resource_id?: string;\n risk_level: VtexWriteRiskLevel;\n confirmed?: boolean;\n message: string;\n summary?: VtexWriteSummary;\n confirmation_note?: string;\n details?: Record<string, unknown>;\n}\n\nexport interface VtexWriteErrorResult extends Record<string, unknown> {\n success: false;\n error_code: VtexWriteErrorCode;\n message: string;\n operation: string;\n risk_level: VtexWriteRiskLevel;\n details?: Record<string, unknown>;\n}\n\nexport class VtexOperationError extends Error {\n constructor(\n message: string,\n public readonly code: VtexWriteErrorCode,\n public readonly details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"VtexOperationError\";\n }\n}\n\nexport function buildConfirmationRequiredResult(\n operation: string,\n details?: Record<string, unknown>\n): VtexWriteErrorResult {\n return {\n success: false,\n error_code: \"EXPLICIT_CONFIRMATION_REQUIRED\",\n message: \"This VTEX operation is high-risk and requires explicit user confirmation before execution.\",\n operation,\n risk_level: \"high\",\n details,\n };\n}\n\nexport function buildWriteSuccessResult(params: {\n profileId: string;\n operation: string;\n resourceId?: string;\n riskLevel: VtexWriteRiskLevel;\n confirmed?: boolean;\n message: string;\n summary?: VtexWriteSummary;\n confirmationNote?: string;\n details?: Record<string, unknown>;\n}): VtexWriteResult {\n return {\n success: true,\n profile_id: params.profileId,\n operation: params.operation,\n resource_id: params.resourceId,\n risk_level: params.riskLevel,\n confirmed: params.confirmed,\n message: params.message,\n summary: params.summary,\n confirmation_note: params.confirmationNote,\n details: params.details,\n };\n}\n"],
5
5
  "mappings": "AAmCO,MAAM,2BAA2B,MAAM;AAAA,EAC5C,YACE,SACgB,MACA,SAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,gCACd,WACA,SACsB;AACtB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,SAAS;AAAA,IACT;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF;AACF;AAEO,SAAS,wBAAwB,QAUpB;AAClB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY,OAAO;AAAA,IACnB,WAAW,OAAO;AAAA,IAClB,aAAa,OAAO;AAAA,IACpB,YAAY,OAAO;AAAA,IACnB,WAAW,OAAO;AAAA,IAClB,SAAS,OAAO;AAAA,IAChB,SAAS,OAAO;AAAA,IAChB,mBAAmB,OAAO;AAAA,IAC1B,SAAS,OAAO;AAAA,EAClB;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/attribution-gaps.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n detectSeverity,\r\n extractQuotaSnapshot,\r\n getDimensionValue,\r\n getMetricValueByName,\r\n isProblematicAttributionValue,\r\n resolveGa4PropertyId,\r\n round,\r\n toPercent,\r\n} from \"../../analytics/ga4-report-utils.js\";\r\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\r\nimport { stripNulls } from \"../../utils/strip-payload.js\";\r\n\r\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\r\n\r\nexport const attributionGapsSchema = z.object({\r\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\r\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\r\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, resolves profileId mapping first and then GA4_PROPERTY_ID.\"),\r\n profileId: z.string().optional().describe(\"Optional business profile ID used to resolve the mapped GA4 property.\"),\r\n limit: z.number().int().min(10).max(100).optional().describe(\"Maximum source / medium rows to inspect\"),\r\n});\r\n\r\nexport async function attributionGapsHandler(params: z.infer<typeof attributionGapsSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const limit = params.limit ?? 50;\r\n\r\n const [channelReport, sourceMediumReport, totalReport] = await Promise.all([\r\n runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n dimensions: [{ name: \"sessionDefaultChannelGroup\" }],\r\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\r\n }),\r\n runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n dimensions: [{ name: \"sessionSourceMedium\" }],\r\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\r\n orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\r\n limit,\r\n returnPropertyQuota: true,\r\n }),\r\n runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n metrics: [{ name: \"sessions\" }],\r\n }),\r\n ]);\r\n\r\n const totalSessions = getMetricValueByName(\r\n totalReport.rows?.[0] ?? {},\r\n totalReport.metricHeaders,\r\n \"sessions\"\r\n );\r\n\r\n const unassignedChannel = (channelReport.rows ?? []).find(\r\n (row) => getDimensionValue(row) === \"Unassigned\"\r\n );\r\n const unassignedSessions = getMetricValueByName(\r\n unassignedChannel ?? {},\r\n channelReport.metricHeaders,\r\n \"sessions\"\r\n );\r\n\r\n const problematicSourceMediumRows = (sourceMediumReport.rows ?? [])\r\n .filter((row) => isProblematicAttributionValue(getDimensionValue(row)))\r\n .map((row) => {\r\n const sessions = getMetricValueByName(row, sourceMediumReport.metricHeaders, \"sessions\");\r\n const users = getMetricValueByName(row, sourceMediumReport.metricHeaders, \"totalUsers\");\r\n\r\n return {\r\n source_medium: getDimensionValue(row),\r\n sessions,\r\n users,\r\n session_share_percent: round(toPercent(sessions, totalSessions)),\r\n };\r\n });\r\n\r\n const problematicSourceMediumSessions = problematicSourceMediumRows.reduce(\r\n (total, row) => total + row.sessions,\r\n 0\r\n );\r\n const unassignedSharePercent = round(toPercent(unassignedSessions, totalSessions));\r\n const problematicSourceMediumSharePercent = round(\r\n toPercent(problematicSourceMediumSessions, totalSessions)\r\n );\r\n\r\n return object(\r\n stripNulls({\r\n property_id: propertyId,\r\n date_range: {\r\n start_date: params.startDate,\r\n end_date: params.endDate,\r\n },\r\n overview: {\r\n total_sessions: totalSessions,\r\n attribution_warning: \"Las se\u00F1ales se reportan por separado para evitar doble conteo entre dimensiones distintas de GA4.\",\r\n },\r\n unassigned_channel_group: {\r\n sessions: unassignedSessions,\r\n session_share_percent: unassignedSharePercent,\r\n severity: detectSeverity(unassignedSharePercent),\r\n },\r\n problematic_source_medium: {\r\n sessions: problematicSourceMediumSessions,\r\n session_share_percent: problematicSourceMediumSharePercent,\r\n severity: detectSeverity(problematicSourceMediumSharePercent),\r\n },\r\n problematic_source_mediums: problematicSourceMediumRows,\r\n quota: extractQuotaSnapshot(sourceMediumReport),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to detect GA4 attribution gaps\");\r\n }\r\n}\r\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n detectSeverity,\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\n isProblematicAttributionValue,\n resolveGa4PropertyId,\n round,\n toPercent,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { runReport } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport const attributionGapsSchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n propertyId: z.string().optional().describe(\"GA4 property ID. If omitted, resolves profileId mapping first and then GA4_PROPERTY_ID.\"),\n profileId: z.string().optional().describe(\"Optional business profile ID used to resolve the mapped GA4 property.\"),\n limit: z.number().int().min(10).max(100).optional().describe(\"Maximum source / medium rows to inspect\"),\n});\n\nexport async function attributionGapsHandler(params: z.infer<typeof attributionGapsSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const limit = params.limit ?? 50;\n\n const [channelReport, sourceMediumReport, totalReport] = await Promise.all([\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"sessionDefaultChannelGroup\" }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n }),\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"sessionSourceMedium\" }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\n limit,\n returnPropertyQuota: true,\n }),\n runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [{ name: \"sessions\" }],\n }),\n ]);\n\n const totalSessions = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"sessions\"\n );\n\n const unassignedChannel = (channelReport.rows ?? []).find(\n (row) => getDimensionValue(row) === \"Unassigned\"\n );\n const unassignedSessions = getMetricValueByName(\n unassignedChannel ?? {},\n channelReport.metricHeaders,\n \"sessions\"\n );\n\n const problematicSourceMediumRows = (sourceMediumReport.rows ?? [])\n .filter((row) => isProblematicAttributionValue(getDimensionValue(row)))\n .map((row) => {\n const sessions = getMetricValueByName(row, sourceMediumReport.metricHeaders, \"sessions\");\n const users = getMetricValueByName(row, sourceMediumReport.metricHeaders, \"totalUsers\");\n\n return {\n source_medium: getDimensionValue(row),\n sessions,\n users,\n session_share_percent: round(toPercent(sessions, totalSessions)),\n };\n });\n\n const problematicSourceMediumSessions = problematicSourceMediumRows.reduce(\n (total, row) => total + row.sessions,\n 0\n );\n const unassignedSharePercent = round(toPercent(unassignedSessions, totalSessions));\n const problematicSourceMediumSharePercent = round(\n toPercent(problematicSourceMediumSessions, totalSessions)\n );\n\n return object(\n stripNulls({\n property_id: propertyId,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n overview: {\n total_sessions: totalSessions,\n attribution_warning: \"Las se\u00F1ales se reportan por separado para evitar doble conteo entre dimensiones distintas de GA4.\",\n },\n unassigned_channel_group: {\n sessions: unassignedSessions,\n session_share_percent: unassignedSharePercent,\n severity: detectSeverity(unassignedSharePercent),\n },\n problematic_source_medium: {\n sessions: problematicSourceMediumSessions,\n session_share_percent: problematicSourceMediumSharePercent,\n severity: detectSeverity(problematicSourceMediumSharePercent),\n },\n problematic_source_mediums: problematicSourceMediumRows,\n quota: extractQuotaSnapshot(sourceMediumReport),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to detect GA4 attribution gaps\");\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }