@yoryoboy/bi-mcp 1.5.2 → 1.6.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 (182) 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/decrypt-secret.js +36 -0
  16. package/dist/scripts/decrypt-secret.js.map +7 -0
  17. package/dist/scripts/run-migrations.js.map +1 -1
  18. package/dist/scripts/test-db-connection.js.map +1 -1
  19. package/dist/src/analytics/ga4-channel-groups.js.map +1 -1
  20. package/dist/src/analytics/ga4-report-utils.js.map +1 -1
  21. package/dist/src/config/benchmarks.js.map +1 -1
  22. package/dist/src/config/google-store.js.map +1 -1
  23. package/dist/src/config/google.js.map +1 -1
  24. package/dist/src/config/mercadolibre-profile-store.js.map +1 -1
  25. package/dist/src/config/mercadolibre.js.map +1 -1
  26. package/dist/src/config/meta.js.map +1 -1
  27. package/dist/src/config/profile-store.js.map +1 -1
  28. package/dist/src/config/vtex-crypto.js.map +1 -1
  29. package/dist/src/config/vtex-profile-store.js.map +1 -1
  30. package/dist/src/config/vtex.js.map +1 -1
  31. package/dist/src/db/client.js.map +1 -1
  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/services/analytics/ga4-client.js.map +1 -1
  35. package/dist/src/services/analytics/oauth.js.map +1 -1
  36. package/dist/src/services/google-ads/google-ads-client.js.map +1 -1
  37. package/dist/src/services/mercadolibre/mercadolibre-api.js.map +1 -1
  38. package/dist/src/services/mercadolibre/mercadolibre-items.js.map +1 -1
  39. package/dist/src/services/mercadolibre/mercadolibre-orders.js +19 -5
  40. package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +2 -2
  41. package/dist/src/services/mercadolibre/mercadolibre-questions.js.map +1 -1
  42. package/dist/src/services/meta/meta-ads.js.map +1 -1
  43. package/dist/src/services/meta/meta-api.js.map +1 -1
  44. package/dist/src/services/search-console/search-console-client.js.map +1 -1
  45. package/dist/src/services/search-console/search-console-utils.js.map +1 -1
  46. package/dist/src/services/vtex/vtex-api.js.map +1 -1
  47. package/dist/src/services/vtex/vtex-catalog-write.js.map +1 -1
  48. package/dist/src/services/vtex/vtex-catalog.js.map +1 -1
  49. package/dist/src/services/vtex/vtex-logistics.js.map +1 -1
  50. package/dist/src/services/vtex/vtex-orders-write.js.map +1 -1
  51. package/dist/src/services/vtex/vtex-orders.js.map +1 -1
  52. package/dist/src/services/vtex/vtex-pricing-write.js.map +1 -1
  53. package/dist/src/services/vtex/vtex-pricing.js.map +1 -1
  54. package/dist/src/services/vtex/vtex-write.js.map +1 -1
  55. package/dist/src/tools/analytics/attribution-gaps.js.map +1 -1
  56. package/dist/src/tools/analytics/channel-mix.js.map +1 -1
  57. package/dist/src/tools/analytics/ecommerce-tracking-health.js.map +1 -1
  58. package/dist/src/tools/analytics/engagement-overview.js.map +1 -1
  59. package/dist/src/tools/analytics/index.js.map +1 -1
  60. package/dist/src/tools/analytics/list-accessible-properties.js.map +1 -1
  61. package/dist/src/tools/analytics/property-info.js.map +1 -1
  62. package/dist/src/tools/analytics/revenue-by-channel.js.map +1 -1
  63. package/dist/src/tools/analytics/revenue-overview.js.map +1 -1
  64. package/dist/src/tools/analytics/revenue-trend.js.map +1 -1
  65. package/dist/src/tools/analytics/source-medium-breakdown.js.map +1 -1
  66. package/dist/src/tools/analytics/top-landing-pages.js.map +1 -1
  67. package/dist/src/tools/config/check-database-connection.js.map +1 -1
  68. package/dist/src/tools/config/index.js.map +1 -1
  69. package/dist/src/tools/config/list-profiles.js.map +1 -1
  70. package/dist/src/tools/google-ads/account-overview.js.map +1 -1
  71. package/dist/src/tools/google-ads/account-risks.js.map +1 -1
  72. package/dist/src/tools/google-ads/break-even-analysis.js.map +1 -1
  73. package/dist/src/tools/google-ads/campaign-performance.js.map +1 -1
  74. package/dist/src/tools/google-ads/channel-mix.js.map +1 -1
  75. package/dist/src/tools/google-ads/compare-accounts.js.map +1 -1
  76. package/dist/src/tools/google-ads/customer-clients.js.map +1 -1
  77. package/dist/src/tools/google-ads/customer-info.js.map +1 -1
  78. package/dist/src/tools/google-ads/index.js.map +1 -1
  79. package/dist/src/tools/google-ads/scaling-health.js.map +1 -1
  80. package/dist/src/tools/google-ads/search-terms-summary.js.map +1 -1
  81. package/dist/src/tools/google-ads/time-series.js.map +1 -1
  82. package/dist/src/tools/index.js.map +1 -1
  83. package/dist/src/tools/mercadolibre/answer-question.js.map +1 -1
  84. package/dist/src/tools/mercadolibre/create-item.js.map +1 -1
  85. package/dist/src/tools/mercadolibre/estimate-listing-fee.js.map +1 -1
  86. package/dist/src/tools/mercadolibre/get-account-context.js.map +1 -1
  87. package/dist/src/tools/mercadolibre/get-category-requirements.js.map +1 -1
  88. package/dist/src/tools/mercadolibre/get-item-details.js.map +1 -1
  89. package/dist/src/tools/mercadolibre/get-item-visits.js.map +1 -1
  90. package/dist/src/tools/mercadolibre/get-listing-quality.js.map +1 -1
  91. package/dist/src/tools/mercadolibre/get-order-details.js.map +1 -1
  92. package/dist/src/tools/mercadolibre/get-orders-summary.js +670 -38
  93. package/dist/src/tools/mercadolibre/get-orders-summary.js.map +2 -2
  94. package/dist/src/tools/mercadolibre/get-sales-by-item.js.map +1 -1
  95. package/dist/src/tools/mercadolibre/get-sales-trend.js.map +1 -1
  96. package/dist/src/tools/mercadolibre/get-shipping-summary.js.map +1 -1
  97. package/dist/src/tools/mercadolibre/get-store-performance.js.map +1 -1
  98. package/dist/src/tools/mercadolibre/helpers.js +13 -0
  99. package/dist/src/tools/mercadolibre/helpers.js.map +2 -2
  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 +4 -3
  178. package/public/icon.svg +6 -6
  179. package/dist/src/google-ads/report-utils.js +0 -78
  180. package/dist/src/google-ads/report-utils.js.map +0 -7
  181. package/dist/src/search-console/search-console-utils.js +0 -275
  182. package/dist/src/search-console/search-console-utils.js.map +0 -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\";\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"],
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"],
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\";\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"],
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"],
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\";\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"],
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"],
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\";\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"],
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"],
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\";\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"],
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"],
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\";\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"],
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"],
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\";\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"],
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"],
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/tools/analytics/channel-mix.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n sumMetricValues,\n toPercent,\n} from \"../../analytics/ga4-report-utils.js\";\nimport { isPaidDefaultChannelGroup } from \"../../analytics/ga4-channel-groups.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 channelMixSchema = 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});\n\nexport async function channelMixHandler(params: z.infer<typeof channelMixSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"sessionDefaultChannelGroup\" }],\n metrics: [{ name: \"sessions\" }, { name: \"totalUsers\" }],\n orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\n returnPropertyQuota: true,\n });\n\n const totalSessions = sumMetricValues(report.rows, report.metricHeaders, \"sessions\");\n const totalUsers = sumMetricValues(report.rows, report.metricHeaders, \"totalUsers\");\n\n const channels = (report.rows ?? []).map((row) => {\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\n const users = getMetricValueByName(row, report.metricHeaders, \"totalUsers\");\n\n return {\n channel: getDimensionValue(row),\n sessions,\n users,\n session_share_percent: round(toPercent(sessions, totalSessions)),\n user_share_percent: round(toPercent(users, totalUsers)),\n };\n });\n\n const paidSessions = channels\n .filter((channel) => isPaidDefaultChannelGroup(channel.channel))\n .reduce((total, channel) => total + channel.sessions, 0);\n const organicSessions = channels\n .filter((channel) => channel.channel.startsWith(\"Organic\"))\n .reduce((total, channel) => total + channel.sessions, 0);\n const directSessions = channels\n .filter((channel) => channel.channel === \"Direct\")\n .reduce((total, channel) => total + channel.sessions, 0);\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 total_users: totalUsers,\n top_channel: channels[0]?.channel,\n paid_session_share_percent: round(toPercent(paidSessions, totalSessions)),\n organic_session_share_percent: round(toPercent(organicSessions, totalSessions)),\n direct_session_share_percent: round(toPercent(directSessions, totalSessions)),\n },\n channels,\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 channel mix\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getDimensionValue,\r\n getMetricValueByName,\r\n resolveGa4PropertyId,\r\n round,\r\n sumMetricValues,\r\n toPercent,\r\n} from \"../../analytics/ga4-report-utils.js\";\r\nimport { isPaidDefaultChannelGroup } from \"../../analytics/ga4-channel-groups.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 channelMixSchema = 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});\r\n\r\nexport async function channelMixHandler(params: z.infer<typeof channelMixSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n\r\n const report = await 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 orderBys: [{ metric: { metricName: \"sessions\" }, desc: true }],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const totalSessions = sumMetricValues(report.rows, report.metricHeaders, \"sessions\");\r\n const totalUsers = sumMetricValues(report.rows, report.metricHeaders, \"totalUsers\");\r\n\r\n const channels = (report.rows ?? []).map((row) => {\r\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\r\n const users = getMetricValueByName(row, report.metricHeaders, \"totalUsers\");\r\n\r\n return {\r\n channel: getDimensionValue(row),\r\n sessions,\r\n users,\r\n session_share_percent: round(toPercent(sessions, totalSessions)),\r\n user_share_percent: round(toPercent(users, totalUsers)),\r\n };\r\n });\r\n\r\n const paidSessions = channels\r\n .filter((channel) => isPaidDefaultChannelGroup(channel.channel))\r\n .reduce((total, channel) => total + channel.sessions, 0);\r\n const organicSessions = channels\r\n .filter((channel) => channel.channel.startsWith(\"Organic\"))\r\n .reduce((total, channel) => total + channel.sessions, 0);\r\n const directSessions = channels\r\n .filter((channel) => channel.channel === \"Direct\")\r\n .reduce((total, channel) => total + channel.sessions, 0);\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 total_users: totalUsers,\r\n top_channel: channels[0]?.channel,\r\n paid_session_share_percent: round(toPercent(paidSessions, totalSessions)),\r\n organic_session_share_percent: round(toPercent(organicSessions, totalSessions)),\r\n direct_session_share_percent: round(toPercent(directSessions, totalSessions)),\r\n },\r\n channels,\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 channel mix\");\r\n }\r\n}\r\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/tools/analytics/ecommerce-tracking-health.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getMetricValueByName,\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 ecommerceTrackingHealthSchema = 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});\n\nexport async function ecommerceTrackingHealthHandler(\n params: z.infer<typeof ecommerceTrackingHealthSchema>\n) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [\n { name: \"itemViewEvents\" },\n { name: \"addToCarts\" },\n { name: \"checkouts\" },\n { name: \"transactions\" },\n { name: \"purchaseRevenue\" },\n { name: \"refundAmount\" },\n ],\n returnPropertyQuota: true,\n });\n\n const row = report.rows?.[0] ?? {};\n const itemViews = getMetricValueByName(row, report.metricHeaders, \"itemViewEvents\");\n const addToCarts = getMetricValueByName(row, report.metricHeaders, \"addToCarts\");\n const checkouts = getMetricValueByName(row, report.metricHeaders, \"checkouts\");\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\n const purchaseRevenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\n const refundAmount = getMetricValueByName(row, report.metricHeaders, \"refundAmount\");\n\n const warnings: string[] = [];\n if (itemViews === 0) {\n warnings.push(\"No se detectaron view_item events en el rango consultado.\");\n }\n if (addToCarts === 0 && itemViews > 0) {\n warnings.push(\"Hay view_item pero no add_to_cart. Revisar tagging de add_to_cart.\");\n }\n if (checkouts === 0 && addToCarts > 0) {\n warnings.push(\"Hay add_to_cart pero no begin_checkout. Revisar continuidad del funnel.\");\n }\n if (transactions === 0 && checkouts > 0) {\n warnings.push(\"Hay begin_checkout pero no purchase/transactions. Revisar tagging de compra.\");\n }\n if (purchaseRevenue > 0 && transactions === 0) {\n warnings.push(\"Hay revenue pero no transactions. Revisar consistencia de ecommerce events.\");\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 currency_code: report.metadata?.currencyCode,\n funnel: {\n item_view_events: itemViews,\n add_to_carts: addToCarts,\n checkouts,\n transactions,\n purchase_revenue: round(purchaseRevenue),\n refund_amount: round(refundAmount),\n add_to_cart_rate_percent: round(toPercent(addToCarts, itemViews)),\n checkout_rate_percent: round(toPercent(checkouts, addToCarts)),\n purchase_rate_percent: round(toPercent(transactions, checkouts)),\n },\n warnings,\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to evaluate GA4 ecommerce tracking health\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getMetricValueByName,\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 ecommerceTrackingHealthSchema = 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});\r\n\r\nexport async function ecommerceTrackingHealthHandler(\r\n params: z.infer<typeof ecommerceTrackingHealthSchema>\r\n) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const report = await runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n metrics: [\r\n { name: \"itemViewEvents\" },\r\n { name: \"addToCarts\" },\r\n { name: \"checkouts\" },\r\n { name: \"transactions\" },\r\n { name: \"purchaseRevenue\" },\r\n { name: \"refundAmount\" },\r\n ],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const row = report.rows?.[0] ?? {};\r\n const itemViews = getMetricValueByName(row, report.metricHeaders, \"itemViewEvents\");\r\n const addToCarts = getMetricValueByName(row, report.metricHeaders, \"addToCarts\");\r\n const checkouts = getMetricValueByName(row, report.metricHeaders, \"checkouts\");\r\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\r\n const purchaseRevenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\r\n const refundAmount = getMetricValueByName(row, report.metricHeaders, \"refundAmount\");\r\n\r\n const warnings: string[] = [];\r\n if (itemViews === 0) {\r\n warnings.push(\"No se detectaron view_item events en el rango consultado.\");\r\n }\r\n if (addToCarts === 0 && itemViews > 0) {\r\n warnings.push(\"Hay view_item pero no add_to_cart. Revisar tagging de add_to_cart.\");\r\n }\r\n if (checkouts === 0 && addToCarts > 0) {\r\n warnings.push(\"Hay add_to_cart pero no begin_checkout. Revisar continuidad del funnel.\");\r\n }\r\n if (transactions === 0 && checkouts > 0) {\r\n warnings.push(\"Hay begin_checkout pero no purchase/transactions. Revisar tagging de compra.\");\r\n }\r\n if (purchaseRevenue > 0 && transactions === 0) {\r\n warnings.push(\"Hay revenue pero no transactions. Revisar consistencia de ecommerce events.\");\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 currency_code: report.metadata?.currencyCode,\r\n funnel: {\r\n item_view_events: itemViews,\r\n add_to_carts: addToCarts,\r\n checkouts,\r\n transactions,\r\n purchase_revenue: round(purchaseRevenue),\r\n refund_amount: round(refundAmount),\r\n add_to_cart_rate_percent: round(toPercent(addToCarts, itemViews)),\r\n checkout_rate_percent: round(toPercent(checkouts, addToCarts)),\r\n purchase_rate_percent: round(toPercent(transactions, checkouts)),\r\n },\r\n warnings,\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(\r\n err instanceof Error ? err.message : \"Failed to evaluate GA4 ecommerce tracking health\"\r\n );\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,+BACpB,QACA;AACA,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,SAAS;AAAA,QACP,EAAE,MAAM,iBAAiB;AAAA,QACzB,EAAE,MAAM,aAAa;AAAA,QACrB,EAAE,MAAM,YAAY;AAAA,QACpB,EAAE,MAAM,eAAe;AAAA,QACvB,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,eAAe;AAAA,MACzB;AAAA,MACA,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC;AACjC,UAAM,YAAY,qBAAqB,KAAK,OAAO,eAAe,gBAAgB;AAClF,UAAM,aAAa,qBAAqB,KAAK,OAAO,eAAe,YAAY;AAC/E,UAAM,YAAY,qBAAqB,KAAK,OAAO,eAAe,WAAW;AAC7E,UAAM,eAAe,qBAAqB,KAAK,OAAO,eAAe,cAAc;AACnF,UAAM,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACzF,UAAM,eAAe,qBAAqB,KAAK,OAAO,eAAe,cAAc;AAEnF,UAAM,WAAqB,CAAC;AAC5B,QAAI,cAAc,GAAG;AACnB,eAAS,KAAK,2DAA2D;AAAA,IAC3E;AACA,QAAI,eAAe,KAAK,YAAY,GAAG;AACrC,eAAS,KAAK,oEAAoE;AAAA,IACpF;AACA,QAAI,cAAc,KAAK,aAAa,GAAG;AACrC,eAAS,KAAK,yEAAyE;AAAA,IACzF;AACA,QAAI,iBAAiB,KAAK,YAAY,GAAG;AACvC,eAAS,KAAK,8EAA8E;AAAA,IAC9F;AACA,QAAI,kBAAkB,KAAK,iBAAiB,GAAG;AAC7C,eAAS,KAAK,6EAA6E;AAAA,IAC7F;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,QAAQ;AAAA,UACN,kBAAkB;AAAA,UAClB,cAAc;AAAA,UACd;AAAA,UACA;AAAA,UACA,kBAAkB,MAAM,eAAe;AAAA,UACvC,eAAe,MAAM,YAAY;AAAA,UACjC,0BAA0B,MAAM,UAAU,YAAY,SAAS,CAAC;AAAA,UAChE,uBAAuB,MAAM,UAAU,WAAW,UAAU,CAAC;AAAA,UAC7D,uBAAuB,MAAM,UAAU,cAAc,SAAS,CAAC;AAAA,QACjE;AAAA,QACA;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/engagement-overview.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\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 engagementOverviewSchema = 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});\n\nexport async function engagementOverviewHandler(params: z.infer<typeof engagementOverviewSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [\n { name: \"sessions\" },\n { name: \"engagedSessions\" },\n { name: \"engagementRate\" },\n { name: \"averageSessionDuration\" },\n { name: \"screenPageViews\" },\n { name: \"screenPageViewsPerSession\" },\n { name: \"bounceRate\" },\n { name: \"userEngagementDuration\" },\n ],\n returnPropertyQuota: true,\n });\n\n const row = report.rows?.[0] ?? {};\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 sessions: getMetricValueByName(row, report.metricHeaders, \"sessions\"),\n engaged_sessions: getMetricValueByName(row, report.metricHeaders, \"engagedSessions\"),\n engagement_rate_percent: round(\n getMetricValueByName(row, report.metricHeaders, \"engagementRate\") * 100\n ),\n bounce_rate_percent: round(getMetricValueByName(row, report.metricHeaders, \"bounceRate\") * 100),\n average_session_duration_seconds: round(\n getMetricValueByName(row, report.metricHeaders, \"averageSessionDuration\")\n ),\n views: getMetricValueByName(row, report.metricHeaders, \"screenPageViews\"),\n views_per_session: round(\n getMetricValueByName(row, report.metricHeaders, \"screenPageViewsPerSession\")\n ),\n user_engagement_duration_seconds: round(\n getMetricValueByName(row, report.metricHeaders, \"userEngagementDuration\")\n ),\n },\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 engagement overview\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getMetricValueByName,\r\n resolveGa4PropertyId,\r\n round,\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 engagementOverviewSchema = 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});\r\n\r\nexport async function engagementOverviewHandler(params: z.infer<typeof engagementOverviewSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const report = await runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n metrics: [\r\n { name: \"sessions\" },\r\n { name: \"engagedSessions\" },\r\n { name: \"engagementRate\" },\r\n { name: \"averageSessionDuration\" },\r\n { name: \"screenPageViews\" },\r\n { name: \"screenPageViewsPerSession\" },\r\n { name: \"bounceRate\" },\r\n { name: \"userEngagementDuration\" },\r\n ],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const row = report.rows?.[0] ?? {};\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 sessions: getMetricValueByName(row, report.metricHeaders, \"sessions\"),\r\n engaged_sessions: getMetricValueByName(row, report.metricHeaders, \"engagedSessions\"),\r\n engagement_rate_percent: round(\r\n getMetricValueByName(row, report.metricHeaders, \"engagementRate\") * 100\r\n ),\r\n bounce_rate_percent: round(getMetricValueByName(row, report.metricHeaders, \"bounceRate\") * 100),\r\n average_session_duration_seconds: round(\r\n getMetricValueByName(row, report.metricHeaders, \"averageSessionDuration\")\r\n ),\r\n views: getMetricValueByName(row, report.metricHeaders, \"screenPageViews\"),\r\n views_per_session: round(\r\n getMetricValueByName(row, report.metricHeaders, \"screenPageViewsPerSession\")\r\n ),\r\n user_engagement_duration_seconds: round(\r\n getMetricValueByName(row, report.metricHeaders, \"userEngagementDuration\")\r\n ),\r\n },\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 engagement overview\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,0BAA0B,QAAkD;AAChG,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,SAAS;AAAA,QACP,EAAE,MAAM,WAAW;AAAA,QACnB,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,iBAAiB;AAAA,QACzB,EAAE,MAAM,yBAAyB;AAAA,QACjC,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,4BAA4B;AAAA,QACpC,EAAE,MAAM,aAAa;AAAA,QACrB,EAAE,MAAM,yBAAyB;AAAA,MACnC;AAAA,MACA,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC;AAEjC,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,UACR,UAAU,qBAAqB,KAAK,OAAO,eAAe,UAAU;AAAA,UACpE,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AAAA,UACnF,yBAAyB;AAAA,YACvB,qBAAqB,KAAK,OAAO,eAAe,gBAAgB,IAAI;AAAA,UACtE;AAAA,UACA,qBAAqB,MAAM,qBAAqB,KAAK,OAAO,eAAe,YAAY,IAAI,GAAG;AAAA,UAC9F,kCAAkC;AAAA,YAChC,qBAAqB,KAAK,OAAO,eAAe,wBAAwB;AAAA,UAC1E;AAAA,UACA,OAAO,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AAAA,UACxE,mBAAmB;AAAA,YACjB,qBAAqB,KAAK,OAAO,eAAe,2BAA2B;AAAA,UAC7E;AAAA,UACA,kCAAkC;AAAA,YAChC,qBAAqB,KAAK,OAAO,eAAe,wBAAwB;AAAA,UAC1E;AAAA,QACF;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,yCAAyC;AAAA,EAC7F;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/index.ts"],
4
- "sourcesContent": ["export * from \"./list-accessible-properties.js\";\nexport * from \"./property-info.js\";\nexport * from \"./channel-mix.js\";\nexport * from \"./source-medium-breakdown.js\";\nexport * from \"./revenue-overview.js\";\nexport * from \"./revenue-trend.js\";\nexport * from \"./revenue-by-channel.js\";\nexport * from \"./top-landing-pages.js\";\nexport * from \"./engagement-overview.js\";\nexport * from \"./attribution-gaps.js\";\nexport * from \"./ecommerce-tracking-health.js\";\n"],
4
+ "sourcesContent": ["export * from \"./list-accessible-properties.js\";\r\nexport * from \"./property-info.js\";\r\nexport * from \"./channel-mix.js\";\r\nexport * from \"./source-medium-breakdown.js\";\r\nexport * from \"./revenue-overview.js\";\r\nexport * from \"./revenue-trend.js\";\r\nexport * from \"./revenue-by-channel.js\";\r\nexport * from \"./top-landing-pages.js\";\r\nexport * from \"./engagement-overview.js\";\r\nexport * from \"./attribution-gaps.js\";\r\nexport * from \"./ecommerce-tracking-health.js\";\r\n"],
5
5
  "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/list-accessible-properties.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listAccountSummaries } from \"../../services/analytics/ga4-client.js\";\nimport { getDefaultGa4PropertyId } from \"../../config/google.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const listAccessiblePropertiesSchema = z.object({});\n\nexport async function listAccessiblePropertiesHandler(\n _params: z.infer<typeof listAccessiblePropertiesSchema>\n) {\n try {\n const { accountSummaries, nextPageToken } = await listAccountSummaries();\n const defaultPropertyId = getDefaultGa4PropertyId();\n\n const accounts = accountSummaries.map((account) => ({\n account_id: account.account.replace(\"accounts/\", \"\"),\n account_name: account.displayName,\n properties: (account.propertySummaries ?? []).map((property) => {\n const propertyId = property.property.replace(\"properties/\", \"\");\n\n return {\n property_id: propertyId,\n property_name: property.displayName,\n property_type: property.propertyType,\n is_default_property: propertyId === defaultPropertyId,\n };\n }),\n }));\n\n const totalProperties = accounts.reduce((total, account) => total + account.properties.length, 0);\n\n return object(\n stripNulls({\n metadata: {\n is_partial: Boolean(nextPageToken),\n next_page_token: nextPageToken,\n continuation_instructions: nextPageToken\n ? \"This response includes only the first page of accessible GA4 account summaries. Do not assume the account or property list is complete. If you need the full universe, request the next page using next_page_token.\"\n : undefined,\n },\n total_accounts: accounts.length,\n total_properties: totalProperties,\n default_property_id: defaultPropertyId,\n accounts,\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to list accessible GA4 properties\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport { listAccountSummaries } from \"../../services/analytics/ga4-client.js\";\r\nimport { getDefaultGa4PropertyId } from \"../../config/google.js\";\r\nimport { stripNulls } from \"../../utils/strip-payload.js\";\r\n\r\nexport const listAccessiblePropertiesSchema = z.object({});\r\n\r\nexport async function listAccessiblePropertiesHandler(\r\n _params: z.infer<typeof listAccessiblePropertiesSchema>\r\n) {\r\n try {\r\n const { accountSummaries, nextPageToken } = await listAccountSummaries();\r\n const defaultPropertyId = getDefaultGa4PropertyId();\r\n\r\n const accounts = accountSummaries.map((account) => ({\r\n account_id: account.account.replace(\"accounts/\", \"\"),\r\n account_name: account.displayName,\r\n properties: (account.propertySummaries ?? []).map((property) => {\r\n const propertyId = property.property.replace(\"properties/\", \"\");\r\n\r\n return {\r\n property_id: propertyId,\r\n property_name: property.displayName,\r\n property_type: property.propertyType,\r\n is_default_property: propertyId === defaultPropertyId,\r\n };\r\n }),\r\n }));\r\n\r\n const totalProperties = accounts.reduce((total, account) => total + account.properties.length, 0);\r\n\r\n return object(\r\n stripNulls({\r\n metadata: {\r\n is_partial: Boolean(nextPageToken),\r\n next_page_token: nextPageToken,\r\n continuation_instructions: nextPageToken\r\n ? \"This response includes only the first page of accessible GA4 account summaries. Do not assume the account or property list is complete. If you need the full universe, request the next page using next_page_token.\"\r\n : undefined,\r\n },\r\n total_accounts: accounts.length,\r\n total_properties: totalProperties,\r\n default_property_id: defaultPropertyId,\r\n accounts,\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to list accessible GA4 properties\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AACxC,SAAS,kBAAkB;AAEpB,MAAM,iCAAiC,EAAE,OAAO,CAAC,CAAC;AAEzD,eAAsB,gCACpB,SACA;AACA,MAAI;AACF,UAAM,EAAE,kBAAkB,cAAc,IAAI,MAAM,qBAAqB;AACvE,UAAM,oBAAoB,wBAAwB;AAElD,UAAM,WAAW,iBAAiB,IAAI,CAAC,aAAa;AAAA,MAClD,YAAY,QAAQ,QAAQ,QAAQ,aAAa,EAAE;AAAA,MACnD,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ,qBAAqB,CAAC,GAAG,IAAI,CAAC,aAAa;AAC9D,cAAM,aAAa,SAAS,SAAS,QAAQ,eAAe,EAAE;AAE9D,eAAO;AAAA,UACL,aAAa;AAAA,UACb,eAAe,SAAS;AAAA,UACxB,eAAe,SAAS;AAAA,UACxB,qBAAqB,eAAe;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH,EAAE;AAEF,UAAM,kBAAkB,SAAS,OAAO,CAAC,OAAO,YAAY,QAAQ,QAAQ,WAAW,QAAQ,CAAC;AAEhG,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,UACR,YAAY,QAAQ,aAAa;AAAA,UACjC,iBAAiB;AAAA,UACjB,2BAA2B,gBACvB,wNACA;AAAA,QACN;AAAA,QACA,gBAAgB,SAAS;AAAA,QACzB,kBAAkB;AAAA,QAClB,qBAAqB;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,0CAA0C;AAAA,EAC9F;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/property-info.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { findPropertySummary, resolveGa4PropertyId } from \"../../analytics/ga4-report-utils.js\";\nimport { getMetadata, listAccountSummaries } from \"../../services/analytics/ga4-client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const propertyInfoSchema = z.object({\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});\n\nexport async function propertyInfoHandler(params: z.infer<typeof propertyInfoSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n\n const [{ accountSummaries }, metadata] = await Promise.all([\n listAccountSummaries(),\n getMetadata(propertyId),\n ]);\n\n const propertySummary = findPropertySummary(accountSummaries, propertyId);\n const dimensions = metadata.dimensions ?? [];\n const metrics = metadata.metrics ?? [];\n\n return object(\n stripNulls({\n property: {\n property_id: propertyId,\n property_name: propertySummary?.propertyName,\n property_type: propertySummary?.propertyType,\n account_id: propertySummary?.accountId,\n account_name: propertySummary?.accountName,\n },\n capabilities: {\n supports_ecommerce:\n metrics.some((metric) => metric.apiName === \"purchaseRevenue\") &&\n metrics.some((metric) => metric.apiName === \"transactions\"),\n supports_google_ads_dimensions: dimensions.some((dimension) =>\n dimension.apiName.startsWith(\"sessionGoogleAds\")\n ),\n supports_search_console_metrics: metrics.some((metric) =>\n metric.apiName.startsWith(\"organicGoogleSearch\")\n ),\n custom_channel_groups: dimensions\n .filter((dimension) => dimension.apiName.includes(\"CustomChannelGroup\"))\n .map((dimension) => dimension.apiName),\n },\n metadata_summary: {\n total_dimensions: dimensions.length,\n total_metrics: metrics.length,\n sample_dimensions: dimensions.slice(0, 12).map((dimension) => dimension.apiName),\n sample_metrics: metrics.slice(0, 12).map((metric) => metric.apiName),\n },\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 property info\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport { findPropertySummary, resolveGa4PropertyId } from \"../../analytics/ga4-report-utils.js\";\r\nimport { getMetadata, listAccountSummaries } from \"../../services/analytics/ga4-client.js\";\r\nimport { stripNulls } from \"../../utils/strip-payload.js\";\r\n\r\nexport const propertyInfoSchema = z.object({\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});\r\n\r\nexport async function propertyInfoHandler(params: z.infer<typeof propertyInfoSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n\r\n const [{ accountSummaries }, metadata] = await Promise.all([\r\n listAccountSummaries(),\r\n getMetadata(propertyId),\r\n ]);\r\n\r\n const propertySummary = findPropertySummary(accountSummaries, propertyId);\r\n const dimensions = metadata.dimensions ?? [];\r\n const metrics = metadata.metrics ?? [];\r\n\r\n return object(\r\n stripNulls({\r\n property: {\r\n property_id: propertyId,\r\n property_name: propertySummary?.propertyName,\r\n property_type: propertySummary?.propertyType,\r\n account_id: propertySummary?.accountId,\r\n account_name: propertySummary?.accountName,\r\n },\r\n capabilities: {\r\n supports_ecommerce:\r\n metrics.some((metric) => metric.apiName === \"purchaseRevenue\") &&\r\n metrics.some((metric) => metric.apiName === \"transactions\"),\r\n supports_google_ads_dimensions: dimensions.some((dimension) =>\r\n dimension.apiName.startsWith(\"sessionGoogleAds\")\r\n ),\r\n supports_search_console_metrics: metrics.some((metric) =>\r\n metric.apiName.startsWith(\"organicGoogleSearch\")\r\n ),\r\n custom_channel_groups: dimensions\r\n .filter((dimension) => dimension.apiName.includes(\"CustomChannelGroup\"))\r\n .map((dimension) => dimension.apiName),\r\n },\r\n metadata_summary: {\r\n total_dimensions: dimensions.length,\r\n total_metrics: metrics.length,\r\n sample_dimensions: dimensions.slice(0, 12).map((dimension) => dimension.apiName),\r\n sample_metrics: metrics.slice(0, 12).map((metric) => metric.apiName),\r\n },\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 property info\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,qBAAqB,4BAA4B;AAC1D,SAAS,aAAa,4BAA4B;AAClD,SAAS,kBAAkB;AAEpB,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,oBAAoB,QAA4C;AACpF,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AAEjF,UAAM,CAAC,EAAE,iBAAiB,GAAG,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,MACzD,qBAAqB;AAAA,MACrB,YAAY,UAAU;AAAA,IACxB,CAAC;AAED,UAAM,kBAAkB,oBAAoB,kBAAkB,UAAU;AACxE,UAAM,aAAa,SAAS,cAAc,CAAC;AAC3C,UAAM,UAAU,SAAS,WAAW,CAAC;AAErC,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,UACR,aAAa;AAAA,UACb,eAAe,iBAAiB;AAAA,UAChC,eAAe,iBAAiB;AAAA,UAChC,YAAY,iBAAiB;AAAA,UAC7B,cAAc,iBAAiB;AAAA,QACjC;AAAA,QACA,cAAc;AAAA,UACZ,oBACE,QAAQ,KAAK,CAAC,WAAW,OAAO,YAAY,iBAAiB,KAC7D,QAAQ,KAAK,CAAC,WAAW,OAAO,YAAY,cAAc;AAAA,UAC5D,gCAAgC,WAAW;AAAA,YAAK,CAAC,cAC/C,UAAU,QAAQ,WAAW,kBAAkB;AAAA,UACjD;AAAA,UACA,iCAAiC,QAAQ;AAAA,YAAK,CAAC,WAC7C,OAAO,QAAQ,WAAW,qBAAqB;AAAA,UACjD;AAAA,UACA,uBAAuB,WACpB,OAAO,CAAC,cAAc,UAAU,QAAQ,SAAS,oBAAoB,CAAC,EACtE,IAAI,CAAC,cAAc,UAAU,OAAO;AAAA,QACzC;AAAA,QACA,kBAAkB;AAAA,UAChB,kBAAkB,WAAW;AAAA,UAC7B,eAAe,QAAQ;AAAA,UACvB,mBAAmB,WAAW,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,cAAc,UAAU,OAAO;AAAA,UAC/E,gBAAgB,QAAQ,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,WAAW,OAAO,OAAO;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,mCAAmC;AAAA,EACvF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/revenue-by-channel.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\n sumMetricValues,\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 revenueByChannelSchema = 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});\n\nexport async function revenueByChannelHandler(params: z.infer<typeof revenueByChannelSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"sessionDefaultChannelGroup\" }],\n metrics: [{ name: \"transactions\" }, { name: \"purchaseRevenue\" }, { name: \"sessions\" }],\n orderBys: [{ metric: { metricName: \"purchaseRevenue\" }, desc: true }],\n returnPropertyQuota: true,\n });\n\n const totalRevenue = sumMetricValues(report.rows, report.metricHeaders, \"purchaseRevenue\");\n const totalTransactions = sumMetricValues(report.rows, report.metricHeaders, \"transactions\");\n\n const channels = (report.rows ?? []).map((row) => {\n const revenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\n\n return {\n channel: getDimensionValue(row),\n sessions,\n transactions,\n purchase_revenue: round(revenue),\n revenue_share_percent: round(toPercent(revenue, totalRevenue)),\n transaction_share_percent: round(toPercent(transactions, totalTransactions)),\n };\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 currency_code: report.metadata?.currencyCode,\n overview: {\n total_purchase_revenue: round(totalRevenue),\n total_transactions: totalTransactions,\n top_revenue_channel: channels[0]?.channel,\n },\n channels,\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue by channel\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getDimensionValue,\r\n getMetricValueByName,\r\n resolveGa4PropertyId,\r\n round,\r\n sumMetricValues,\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 revenueByChannelSchema = 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});\r\n\r\nexport async function revenueByChannelHandler(params: z.infer<typeof revenueByChannelSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const report = await runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n dimensions: [{ name: \"sessionDefaultChannelGroup\" }],\r\n metrics: [{ name: \"transactions\" }, { name: \"purchaseRevenue\" }, { name: \"sessions\" }],\r\n orderBys: [{ metric: { metricName: \"purchaseRevenue\" }, desc: true }],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const totalRevenue = sumMetricValues(report.rows, report.metricHeaders, \"purchaseRevenue\");\r\n const totalTransactions = sumMetricValues(report.rows, report.metricHeaders, \"transactions\");\r\n\r\n const channels = (report.rows ?? []).map((row) => {\r\n const revenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\r\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\r\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\r\n\r\n return {\r\n channel: getDimensionValue(row),\r\n sessions,\r\n transactions,\r\n purchase_revenue: round(revenue),\r\n revenue_share_percent: round(toPercent(revenue, totalRevenue)),\r\n transaction_share_percent: round(toPercent(transactions, totalTransactions)),\r\n };\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 currency_code: report.metadata?.currencyCode,\r\n overview: {\r\n total_purchase_revenue: round(totalRevenue),\r\n total_transactions: totalTransactions,\r\n top_revenue_channel: channels[0]?.channel,\r\n },\r\n channels,\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue by channel\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,wBAAwB,QAAgD;AAC5F,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,YAAY,CAAC,EAAE,MAAM,6BAA6B,CAAC;AAAA,MACnD,SAAS,CAAC,EAAE,MAAM,eAAe,GAAG,EAAE,MAAM,kBAAkB,GAAG,EAAE,MAAM,WAAW,CAAC;AAAA,MACrF,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,kBAAkB,GAAG,MAAM,KAAK,CAAC;AAAA,MACpE,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,eAAe,gBAAgB,OAAO,MAAM,OAAO,eAAe,iBAAiB;AACzF,UAAM,oBAAoB,gBAAgB,OAAO,MAAM,OAAO,eAAe,cAAc;AAE3F,UAAM,YAAY,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ;AAChD,YAAM,UAAU,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACjF,YAAM,eAAe,qBAAqB,KAAK,OAAO,eAAe,cAAc;AACnF,YAAM,WAAW,qBAAqB,KAAK,OAAO,eAAe,UAAU;AAE3E,aAAO;AAAA,QACL,SAAS,kBAAkB,GAAG;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,kBAAkB,MAAM,OAAO;AAAA,QAC/B,uBAAuB,MAAM,UAAU,SAAS,YAAY,CAAC;AAAA,QAC7D,2BAA2B,MAAM,UAAU,cAAc,iBAAiB,CAAC;AAAA,MAC7E;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,UAAU;AAAA,UACR,wBAAwB,MAAM,YAAY;AAAA,UAC1C,oBAAoB;AAAA,UACpB,qBAAqB,SAAS,CAAC,GAAG;AAAA,QACpC;AAAA,QACA;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,wCAAwC;AAAA,EAC5F;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/revenue-overview.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getMetricValueByName,\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 revenueOverviewSchema = 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});\n\nexport async function revenueOverviewHandler(params: z.infer<typeof revenueOverviewSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n metrics: [\n { name: \"sessions\" },\n { name: \"totalUsers\" },\n { name: \"transactions\" },\n { name: \"purchaseRevenue\" },\n { name: \"averagePurchaseRevenue\" },\n { name: \"totalPurchasers\" },\n { name: \"purchaserRate\" },\n ],\n returnPropertyQuota: true,\n });\n\n const row = report.rows?.[0] ?? {};\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\n const totalUsers = getMetricValueByName(row, report.metricHeaders, \"totalUsers\");\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\n const purchaseRevenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\n const averagePurchaseRevenue = getMetricValueByName(\n row,\n report.metricHeaders,\n \"averagePurchaseRevenue\"\n );\n const totalPurchasers = getMetricValueByName(row, report.metricHeaders, \"totalPurchasers\");\n const purchaserRate = getMetricValueByName(row, report.metricHeaders, \"purchaserRate\");\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 currency_code: report.metadata?.currencyCode,\n overview: {\n sessions,\n total_users: totalUsers,\n transactions,\n total_purchasers: totalPurchasers,\n purchase_revenue: round(purchaseRevenue),\n average_purchase_revenue: round(averagePurchaseRevenue),\n purchaser_rate_percent: round(purchaserRate * 100),\n transactions_per_session_percent: round(toPercent(transactions, sessions)),\n transactions_per_user_percent: round(toPercent(transactions, totalUsers)),\n revenue_per_session: round(sessions > 0 ? purchaseRevenue / sessions : 0),\n },\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue overview\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getMetricValueByName,\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 revenueOverviewSchema = 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});\r\n\r\nexport async function revenueOverviewHandler(params: z.infer<typeof revenueOverviewSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const report = await runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n metrics: [\r\n { name: \"sessions\" },\r\n { name: \"totalUsers\" },\r\n { name: \"transactions\" },\r\n { name: \"purchaseRevenue\" },\r\n { name: \"averagePurchaseRevenue\" },\r\n { name: \"totalPurchasers\" },\r\n { name: \"purchaserRate\" },\r\n ],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const row = report.rows?.[0] ?? {};\r\n const sessions = getMetricValueByName(row, report.metricHeaders, \"sessions\");\r\n const totalUsers = getMetricValueByName(row, report.metricHeaders, \"totalUsers\");\r\n const transactions = getMetricValueByName(row, report.metricHeaders, \"transactions\");\r\n const purchaseRevenue = getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\");\r\n const averagePurchaseRevenue = getMetricValueByName(\r\n row,\r\n report.metricHeaders,\r\n \"averagePurchaseRevenue\"\r\n );\r\n const totalPurchasers = getMetricValueByName(row, report.metricHeaders, \"totalPurchasers\");\r\n const purchaserRate = getMetricValueByName(row, report.metricHeaders, \"purchaserRate\");\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 currency_code: report.metadata?.currencyCode,\r\n overview: {\r\n sessions,\r\n total_users: totalUsers,\r\n transactions,\r\n total_purchasers: totalPurchasers,\r\n purchase_revenue: round(purchaseRevenue),\r\n average_purchase_revenue: round(averagePurchaseRevenue),\r\n purchaser_rate_percent: round(purchaserRate * 100),\r\n transactions_per_session_percent: round(toPercent(transactions, sessions)),\r\n transactions_per_user_percent: round(toPercent(transactions, totalUsers)),\r\n revenue_per_session: round(sessions > 0 ? purchaseRevenue / sessions : 0),\r\n },\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue overview\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,uBAAuB,QAA+C;AAC1F,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,SAAS;AAAA,QACP,EAAE,MAAM,WAAW;AAAA,QACnB,EAAE,MAAM,aAAa;AAAA,QACrB,EAAE,MAAM,eAAe;AAAA,QACvB,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,yBAAyB;AAAA,QACjC,EAAE,MAAM,kBAAkB;AAAA,QAC1B,EAAE,MAAM,gBAAgB;AAAA,MAC1B;AAAA,MACA,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,MAAM,OAAO,OAAO,CAAC,KAAK,CAAC;AACjC,UAAM,WAAW,qBAAqB,KAAK,OAAO,eAAe,UAAU;AAC3E,UAAM,aAAa,qBAAqB,KAAK,OAAO,eAAe,YAAY;AAC/E,UAAM,eAAe,qBAAqB,KAAK,OAAO,eAAe,cAAc;AACnF,UAAM,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACzF,UAAM,yBAAyB;AAAA,MAC7B;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF;AACA,UAAM,kBAAkB,qBAAqB,KAAK,OAAO,eAAe,iBAAiB;AACzF,UAAM,gBAAgB,qBAAqB,KAAK,OAAO,eAAe,eAAe;AAErF,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,UAAU;AAAA,UACR;AAAA,UACA,aAAa;AAAA,UACb;AAAA,UACA,kBAAkB;AAAA,UAClB,kBAAkB,MAAM,eAAe;AAAA,UACvC,0BAA0B,MAAM,sBAAsB;AAAA,UACtD,wBAAwB,MAAM,gBAAgB,GAAG;AAAA,UACjD,kCAAkC,MAAM,UAAU,cAAc,QAAQ,CAAC;AAAA,UACzE,+BAA+B,MAAM,UAAU,cAAc,UAAU,CAAC;AAAA,UACxE,qBAAqB,MAAM,WAAW,IAAI,kBAAkB,WAAW,CAAC;AAAA,QAC1E;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,sCAAsC;AAAA,EAC1F;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/revenue-trend.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n formatGa4Date,\n getDimensionValue,\n getMetricValueByName,\n resolveGa4PropertyId,\n round,\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 revenueTrendSchema = 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});\n\nexport async function revenueTrendHandler(params: z.infer<typeof revenueTrendSchema>) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const report = await runReport(propertyId, {\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\n dimensions: [{ name: \"date\" }],\n metrics: [{ name: \"transactions\" }, { name: \"purchaseRevenue\" }],\n orderBys: [{ dimension: { dimensionName: \"date\" } }],\n returnPropertyQuota: true,\n });\n\n const daily = (report.rows ?? []).map((row) => ({\n date: formatGa4Date(getDimensionValue(row)),\n transactions: getMetricValueByName(row, report.metricHeaders, \"transactions\"),\n purchase_revenue: round(getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\")),\n }));\n\n const totalRevenue = daily.reduce((total, day) => total + day.purchase_revenue, 0);\n const totalTransactions = daily.reduce((total, day) => total + day.transactions, 0);\n const topRevenueDay = daily.reduce<(typeof daily)[number] | undefined>((currentTop, day) => {\n if (!currentTop || day.purchase_revenue > currentTop.purchase_revenue) {\n return day;\n }\n\n return currentTop;\n }, undefined);\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 currency_code: report.metadata?.currencyCode,\n overview: {\n days: daily.length,\n total_transactions: totalTransactions,\n total_purchase_revenue: round(totalRevenue),\n average_daily_revenue: round(daily.length > 0 ? totalRevenue / daily.length : 0),\n top_revenue_day: topRevenueDay,\n },\n daily,\n quota: extractQuotaSnapshot(report),\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue trend\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n formatGa4Date,\r\n getDimensionValue,\r\n getMetricValueByName,\r\n resolveGa4PropertyId,\r\n round,\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 revenueTrendSchema = 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});\r\n\r\nexport async function revenueTrendHandler(params: z.infer<typeof revenueTrendSchema>) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const report = await runReport(propertyId, {\r\n dateRanges: [{ startDate: params.startDate, endDate: params.endDate }],\r\n dimensions: [{ name: \"date\" }],\r\n metrics: [{ name: \"transactions\" }, { name: \"purchaseRevenue\" }],\r\n orderBys: [{ dimension: { dimensionName: \"date\" } }],\r\n returnPropertyQuota: true,\r\n });\r\n\r\n const daily = (report.rows ?? []).map((row) => ({\r\n date: formatGa4Date(getDimensionValue(row)),\r\n transactions: getMetricValueByName(row, report.metricHeaders, \"transactions\"),\r\n purchase_revenue: round(getMetricValueByName(row, report.metricHeaders, \"purchaseRevenue\")),\r\n }));\r\n\r\n const totalRevenue = daily.reduce((total, day) => total + day.purchase_revenue, 0);\r\n const totalTransactions = daily.reduce((total, day) => total + day.transactions, 0);\r\n const topRevenueDay = daily.reduce<(typeof daily)[number] | undefined>((currentTop, day) => {\r\n if (!currentTop || day.purchase_revenue > currentTop.purchase_revenue) {\r\n return day;\r\n }\r\n\r\n return currentTop;\r\n }, undefined);\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 currency_code: report.metadata?.currencyCode,\r\n overview: {\r\n days: daily.length,\r\n total_transactions: totalTransactions,\r\n total_purchase_revenue: round(totalRevenue),\r\n average_daily_revenue: round(daily.length > 0 ? totalRevenue / daily.length : 0),\r\n top_revenue_day: topRevenueDay,\r\n },\r\n daily,\r\n quota: extractQuotaSnapshot(report),\r\n })\r\n );\r\n } catch (err) {\r\n return error(err instanceof Error ? err.message : \"Failed to fetch GA4 revenue trend\");\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AACnH,CAAC;AAED,eAAsB,oBAAoB,QAA4C;AACpF,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,SAAS,MAAM,UAAU,YAAY;AAAA,MACzC,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,MACrE,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,MAC7B,SAAS,CAAC,EAAE,MAAM,eAAe,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAAA,MAC/D,UAAU,CAAC,EAAE,WAAW,EAAE,eAAe,OAAO,EAAE,CAAC;AAAA,MACnD,qBAAqB;AAAA,IACvB,CAAC;AAED,UAAM,SAAS,OAAO,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS;AAAA,MAC9C,MAAM,cAAc,kBAAkB,GAAG,CAAC;AAAA,MAC1C,cAAc,qBAAqB,KAAK,OAAO,eAAe,cAAc;AAAA,MAC5E,kBAAkB,MAAM,qBAAqB,KAAK,OAAO,eAAe,iBAAiB,CAAC;AAAA,IAC5F,EAAE;AAEF,UAAM,eAAe,MAAM,OAAO,CAAC,OAAO,QAAQ,QAAQ,IAAI,kBAAkB,CAAC;AACjF,UAAM,oBAAoB,MAAM,OAAO,CAAC,OAAO,QAAQ,QAAQ,IAAI,cAAc,CAAC;AAClF,UAAM,gBAAgB,MAAM,OAA2C,CAAC,YAAY,QAAQ;AAC1F,UAAI,CAAC,cAAc,IAAI,mBAAmB,WAAW,kBAAkB;AACrE,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,GAAG,MAAS;AAEZ,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,eAAe,OAAO,UAAU;AAAA,QAChC,UAAU;AAAA,UACR,MAAM,MAAM;AAAA,UACZ,oBAAoB;AAAA,UACpB,wBAAwB,MAAM,YAAY;AAAA,UAC1C,uBAAuB,MAAM,MAAM,SAAS,IAAI,eAAe,MAAM,SAAS,CAAC;AAAA,UAC/E,iBAAiB;AAAA,QACnB;AAAA,QACA;AAAA,QACA,OAAO,qBAAqB,MAAM;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,mCAAmC;AAAA,EACvF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/analytics/source-medium-breakdown.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n extractQuotaSnapshot,\n getDimensionValue,\n getMetricValueByName,\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 sourceMediumBreakdownSchema = 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(1).max(100).optional().describe(\"Maximum rows to return\"),\n});\n\nexport async function sourceMediumBreakdownHandler(\n params: z.infer<typeof sourceMediumBreakdownSchema>\n) {\n try {\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\n const limit = params.limit ?? 20;\n\n const [breakdownReport, totalReport] = await Promise.all([\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\" }, { name: \"totalUsers\" }],\n }),\n ]);\n\n const totalSessions = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"sessions\"\n );\n const totalUsers = getMetricValueByName(\n totalReport.rows?.[0] ?? {},\n totalReport.metricHeaders,\n \"totalUsers\"\n );\n\n const rows = (breakdownReport.rows ?? []).map((row) => {\n const sessions = getMetricValueByName(row, breakdownReport.metricHeaders, \"sessions\");\n const users = getMetricValueByName(row, breakdownReport.metricHeaders, \"totalUsers\");\n\n return {\n source_medium: getDimensionValue(row),\n sessions,\n users,\n session_share_percent: round(toPercent(sessions, totalSessions)),\n user_share_percent: round(toPercent(users, totalUsers)),\n };\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 total_users: totalUsers,\n returned_rows: rows.length,\n available_rows: breakdownReport.rowCount,\n },\n source_mediums: rows,\n quota: extractQuotaSnapshot(breakdownReport),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch GA4 source / medium breakdown\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\r\nimport { z } from \"zod\";\r\n\r\nimport {\r\n extractQuotaSnapshot,\r\n getDimensionValue,\r\n getMetricValueByName,\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 sourceMediumBreakdownSchema = 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(1).max(100).optional().describe(\"Maximum rows to return\"),\r\n});\r\n\r\nexport async function sourceMediumBreakdownHandler(\r\n params: z.infer<typeof sourceMediumBreakdownSchema>\r\n) {\r\n try {\r\n const propertyId = await resolveGa4PropertyId(params.propertyId, params.profileId);\r\n const limit = params.limit ?? 20;\r\n\r\n const [breakdownReport, totalReport] = await Promise.all([\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\" }, { name: \"totalUsers\" }],\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 const totalUsers = getMetricValueByName(\r\n totalReport.rows?.[0] ?? {},\r\n totalReport.metricHeaders,\r\n \"totalUsers\"\r\n );\r\n\r\n const rows = (breakdownReport.rows ?? []).map((row) => {\r\n const sessions = getMetricValueByName(row, breakdownReport.metricHeaders, \"sessions\");\r\n const users = getMetricValueByName(row, breakdownReport.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 user_share_percent: round(toPercent(users, totalUsers)),\r\n };\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 total_users: totalUsers,\r\n returned_rows: rows.length,\r\n available_rows: breakdownReport.rowCount,\r\n },\r\n source_mediums: rows,\r\n quota: extractQuotaSnapshot(breakdownReport),\r\n })\r\n );\r\n } catch (err) {\r\n return error(\r\n err instanceof Error ? err.message : \"Failed to fetch GA4 source / medium breakdown\"\r\n );\r\n }\r\n}\r\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAE3B,MAAM,YAAY;AAEX,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAClD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,iCAAiC;AAAA,EACjF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,+BAA+B;AAAA,EAC7E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,EACpI,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uEAAuE;AAAA,EACjH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS,EAAE,SAAS,wBAAwB;AACtF,CAAC;AAED,eAAsB,6BACpB,QACA;AACA,MAAI;AACF,UAAM,aAAa,MAAM,qBAAqB,OAAO,YAAY,OAAO,SAAS;AACjF,UAAM,QAAQ,OAAO,SAAS;AAE9B,UAAM,CAAC,iBAAiB,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,YAAY,CAAC,EAAE,MAAM,sBAAsB,CAAC;AAAA,QAC5C,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,QACtD,UAAU,CAAC,EAAE,QAAQ,EAAE,YAAY,WAAW,GAAG,MAAM,KAAK,CAAC;AAAA,QAC7D;AAAA,QACA,qBAAqB;AAAA,MACvB,CAAC;AAAA,MACD,UAAU,YAAY;AAAA,QACpB,YAAY,CAAC,EAAE,WAAW,OAAO,WAAW,SAAS,OAAO,QAAQ,CAAC;AAAA,QACrE,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,EAAE,MAAM,aAAa,CAAC;AAAA,MACxD,CAAC;AAAA,IACH,CAAC;AAED,UAAM,gBAAgB;AAAA,MACpB,YAAY,OAAO,CAAC,KAAK,CAAC;AAAA,MAC1B,YAAY;AAAA,MACZ;AAAA,IACF;AACA,UAAM,aAAa;AAAA,MACjB,YAAY,OAAO,CAAC,KAAK,CAAC;AAAA,MAC1B,YAAY;AAAA,MACZ;AAAA,IACF;AAEA,UAAM,QAAQ,gBAAgB,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ;AACrD,YAAM,WAAW,qBAAqB,KAAK,gBAAgB,eAAe,UAAU;AACpF,YAAM,QAAQ,qBAAqB,KAAK,gBAAgB,eAAe,YAAY;AAEnF,aAAO;AAAA,QACL,eAAe,kBAAkB,GAAG;AAAA,QACpC;AAAA,QACA;AAAA,QACA,uBAAuB,MAAM,UAAU,UAAU,aAAa,CAAC;AAAA,QAC/D,oBAAoB,MAAM,UAAU,OAAO,UAAU,CAAC;AAAA,MACxD;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa;AAAA,QACb,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,UACR,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,eAAe,KAAK;AAAA,UACpB,gBAAgB,gBAAgB;AAAA,QAClC;AAAA,QACA,gBAAgB;AAAA,QAChB,OAAO,qBAAqB,eAAe;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }