@yoryoboy/bi-mcp 1.2.0 → 1.3.1

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 (92) hide show
  1. package/README.md +38 -427
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +302 -2
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +2 -2
  6. package/dist/src/services/search-console/search-console-utils.js +275 -0
  7. package/dist/src/services/search-console/search-console-utils.js.map +7 -0
  8. package/dist/src/services/vtex/vtex-catalog-write.js +233 -0
  9. package/dist/src/services/vtex/vtex-catalog-write.js.map +7 -0
  10. package/dist/src/services/vtex/vtex-orders-write.js +152 -0
  11. package/dist/src/services/vtex/vtex-orders-write.js.map +7 -0
  12. package/dist/src/services/vtex/vtex-pricing-write.js +24 -0
  13. package/dist/src/services/vtex/vtex-pricing-write.js.map +7 -0
  14. package/dist/src/services/vtex/vtex-write.js +38 -0
  15. package/dist/src/services/vtex/vtex-write.js.map +7 -0
  16. package/dist/src/tools/search-console/country-breakdown.js +1 -1
  17. package/dist/src/tools/search-console/country-breakdown.js.map +1 -1
  18. package/dist/src/tools/search-console/device-breakdown.js +1 -1
  19. package/dist/src/tools/search-console/device-breakdown.js.map +1 -1
  20. package/dist/src/tools/search-console/high-impression-low-click-queries.js +1 -1
  21. package/dist/src/tools/search-console/high-impression-low-click-queries.js.map +1 -1
  22. package/dist/src/tools/search-console/list-accessible-sites.js +1 -1
  23. package/dist/src/tools/search-console/list-accessible-sites.js.map +1 -1
  24. package/dist/src/tools/search-console/low-ctr-opportunities.js +1 -1
  25. package/dist/src/tools/search-console/low-ctr-opportunities.js.map +1 -1
  26. package/dist/src/tools/search-console/page-performance.js +1 -1
  27. package/dist/src/tools/search-console/page-performance.js.map +1 -1
  28. package/dist/src/tools/search-console/product-demand-low-capture-queries.js +1 -1
  29. package/dist/src/tools/search-console/product-demand-low-capture-queries.js.map +1 -1
  30. package/dist/src/tools/search-console/query-page-matrix.js +1 -1
  31. package/dist/src/tools/search-console/query-page-matrix.js.map +1 -1
  32. package/dist/src/tools/search-console/query-performance.js +1 -1
  33. package/dist/src/tools/search-console/query-performance.js.map +1 -1
  34. package/dist/src/tools/search-console/quick-win-opportunities.js +1 -1
  35. package/dist/src/tools/search-console/quick-win-opportunities.js.map +1 -1
  36. package/dist/src/tools/search-console/rising-non-brand-queries.js +1 -1
  37. package/dist/src/tools/search-console/rising-non-brand-queries.js.map +1 -1
  38. package/dist/src/tools/search-console/search-performance.js +1 -1
  39. package/dist/src/tools/search-console/search-performance.js.map +1 -1
  40. package/dist/src/tools/search-console/site-context.js +1 -1
  41. package/dist/src/tools/search-console/site-context.js.map +1 -1
  42. package/dist/src/tools/search-console/visibility-declines.js +1 -1
  43. package/dist/src/tools/search-console/visibility-declines.js.map +1 -1
  44. package/dist/src/tools/vtex/activate-sku.js +53 -0
  45. package/dist/src/tools/vtex/activate-sku.js.map +7 -0
  46. package/dist/src/tools/vtex/add-order-tracking.js +103 -0
  47. package/dist/src/tools/vtex/add-order-tracking.js.map +7 -0
  48. package/dist/src/tools/vtex/associate-specification.js +60 -0
  49. package/dist/src/tools/vtex/associate-specification.js.map +7 -0
  50. package/dist/src/tools/vtex/attach-catalog-image.js +63 -0
  51. package/dist/src/tools/vtex/attach-catalog-image.js.map +7 -0
  52. package/dist/src/tools/vtex/cancel-order.js +67 -0
  53. package/dist/src/tools/vtex/cancel-order.js.map +7 -0
  54. package/dist/src/tools/vtex/create-brand.js +69 -0
  55. package/dist/src/tools/vtex/create-brand.js.map +7 -0
  56. package/dist/src/tools/vtex/create-category.js +81 -0
  57. package/dist/src/tools/vtex/create-category.js.map +7 -0
  58. package/dist/src/tools/vtex/create-product-with-sku.js +120 -0
  59. package/dist/src/tools/vtex/create-product-with-sku.js.map +7 -0
  60. package/dist/src/tools/vtex/create-product.js +111 -0
  61. package/dist/src/tools/vtex/create-product.js.map +7 -0
  62. package/dist/src/tools/vtex/create-sku.js +103 -0
  63. package/dist/src/tools/vtex/create-sku.js.map +7 -0
  64. package/dist/src/tools/vtex/create-specification-value.js +53 -0
  65. package/dist/src/tools/vtex/create-specification-value.js.map +7 -0
  66. package/dist/src/tools/vtex/create-specification.js +85 -0
  67. package/dist/src/tools/vtex/create-specification.js.map +7 -0
  68. package/dist/src/tools/vtex/deactivate-sku.js +53 -0
  69. package/dist/src/tools/vtex/deactivate-sku.js.map +7 -0
  70. package/dist/src/tools/vtex/delete-fixed-price.js +53 -0
  71. package/dist/src/tools/vtex/delete-fixed-price.js.map +7 -0
  72. package/dist/src/tools/vtex/index.js +20 -0
  73. package/dist/src/tools/vtex/index.js.map +2 -2
  74. package/dist/src/tools/vtex/invoice-order.js +84 -0
  75. package/dist/src/tools/vtex/invoice-order.js.map +7 -0
  76. package/dist/src/tools/vtex/toggle-unlimited-quantity.js +65 -0
  77. package/dist/src/tools/vtex/toggle-unlimited-quantity.js.map +7 -0
  78. package/dist/src/tools/vtex/update-inventory.js +34 -19
  79. package/dist/src/tools/vtex/update-inventory.js.map +2 -2
  80. package/dist/src/tools/vtex/update-lead-time.js +34 -17
  81. package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
  82. package/dist/src/tools/vtex/update-product-basic-fields.js +71 -0
  83. package/dist/src/tools/vtex/update-product-basic-fields.js.map +7 -0
  84. package/dist/src/tools/vtex/update-sku-basic-fields.js +92 -0
  85. package/dist/src/tools/vtex/update-sku-basic-fields.js.map +7 -0
  86. package/dist/src/tools/vtex/update-sku-price.js +81 -0
  87. package/dist/src/tools/vtex/update-sku-price.js.map +7 -0
  88. package/dist/src/tools/vtex/upsert-fixed-price.js +69 -0
  89. package/dist/src/tools/vtex/upsert-fixed-price.js.map +7 -0
  90. package/dist/src/tools/vtex/write-helpers.js +73 -0
  91. package/dist/src/tools/vtex/write-helpers.js.map +7 -0
  92. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/query-performance.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildPaginationMetadata,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n rowLimitSchemaField,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n startRowSchemaField,\n sumSearchConsoleRows,\n normalizeSearchConsoleRow,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleQueryPerformanceSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n includeBrand: z\n .enum([\"all\", \"only_brand\", \"only_non_brand\"])\n .optional()\n .describe(\"How to filter the query list when brandTerms are provided.\"),\n rowLimit: rowLimitSchemaField,\n startRow: startRowSchemaField,\n});\n\nexport async function searchConsoleQueryPerformanceHandler(\n params: z.infer<typeof searchConsoleQueryPerformanceSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const response = await querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: params.rowLimit,\n startRow: params.startRow,\n })\n );\n\n const includeBrand = params.includeBrand ?? \"all\";\n const rows = (response.rows ?? [])\n .map((row) => normalizeSearchConsoleRow(row, [\"query\"]))\n .map((row) => ({\n query: row.dimensions.query,\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n }))\n .filter((row) => {\n if (includeBrand === \"only_brand\") {\n return row.brand_classification === \"brand\";\n }\n\n if (includeBrand === \"only_non_brand\") {\n return row.brand_classification === \"non_brand\";\n }\n\n return true;\n });\n\n const totals = sumSearchConsoleRows(\n rows.map((row) => ({\n keys: [row.query],\n dimensions: { query: row.query },\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n }))\n );\n\n return object(\n stripNulls({\n site_url: siteUrl,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n filters: {\n search_type: params.searchType ?? \"web\",\n include_brand: includeBrand,\n brand_terms: params.brandTerms,\n },\n overview: {\n total_clicks: totals.clicks,\n total_impressions: totals.impressions,\n average_ctr_percent: totals.ctrPercent,\n average_position: totals.averagePosition,\n },\n queries: rows,\n metadata: buildPaginationMetadata({\n startRow: params.startRow,\n rowLimit: params.rowLimit,\n returnedRows: response.rows?.length ?? 0,\n }),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Search Console query performance\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildPaginationMetadata,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n rowLimitSchemaField,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n startRowSchemaField,\n sumSearchConsoleRows,\n normalizeSearchConsoleRow,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleQueryPerformanceSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n includeBrand: z\n .enum([\"all\", \"only_brand\", \"only_non_brand\"])\n .optional()\n .describe(\"How to filter the query list when brandTerms are provided.\"),\n rowLimit: rowLimitSchemaField,\n startRow: startRowSchemaField,\n});\n\nexport async function searchConsoleQueryPerformanceHandler(\n params: z.infer<typeof searchConsoleQueryPerformanceSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const response = await querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: params.rowLimit,\n startRow: params.startRow,\n })\n );\n\n const includeBrand = params.includeBrand ?? \"all\";\n const rows = (response.rows ?? [])\n .map((row) => normalizeSearchConsoleRow(row, [\"query\"]))\n .map((row) => ({\n query: row.dimensions.query,\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n }))\n .filter((row) => {\n if (includeBrand === \"only_brand\") {\n return row.brand_classification === \"brand\";\n }\n\n if (includeBrand === \"only_non_brand\") {\n return row.brand_classification === \"non_brand\";\n }\n\n return true;\n });\n\n const totals = sumSearchConsoleRows(\n rows.map((row) => ({\n keys: [row.query],\n dimensions: { query: row.query },\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n }))\n );\n\n return object(\n stripNulls({\n site_url: siteUrl,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n filters: {\n search_type: params.searchType ?? \"web\",\n include_brand: includeBrand,\n brand_terms: params.brandTerms,\n },\n overview: {\n total_clicks: totals.clicks,\n total_impressions: totals.impressions,\n average_ctr_percent: totals.ctrPercent,\n average_position: totals.averagePosition,\n },\n queries: rows,\n metadata: buildPaginationMetadata({\n startRow: params.startRow,\n rowLimit: params.rowLimit,\n returnedRows: response.rows?.length ?? 0,\n }),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Search Console query performance\"\n );\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,qCAAqC;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,sCAAsC,EAAE,OAAO;AAAA,EAC1D,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc,EACX,KAAK,CAAC,OAAO,cAAc,gBAAgB,CAAC,EAC5C,SAAS,EACT,SAAS,4DAA4D;AAAA,EACxE,UAAU;AAAA,EACV,UAAU;AACZ,CAAC;AAED,eAAsB,qCACpB,QACA;AACA,MAAI;AACF,UAAM,UAAU,4BAA4B,OAAO,SAAS,OAAO,SAAS;AAC5E,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,4BAA4B;AAAA,QAC1B,WAAW,OAAO;AAAA,QAClB,SAAS,OAAO;AAAA,QAChB,YAAY,CAAC,OAAO;AAAA,QACpB,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,UAAM,eAAe,OAAO,gBAAgB;AAC5C,UAAM,QAAQ,SAAS,QAAQ,CAAC,GAC7B,IAAI,CAAC,QAAQ,0BAA0B,KAAK,CAAC,OAAO,CAAC,CAAC,EACtD,IAAI,CAAC,SAAS;AAAA,MACb,OAAO,IAAI,WAAW;AAAA,MACtB,QAAQ,IAAI;AAAA,MACZ,aAAa,IAAI;AAAA,MACjB,aAAa,IAAI;AAAA,MACjB,UAAU,IAAI;AAAA,MACd,sBAAsB,mBAAmB,IAAI,WAAW,OAAO,OAAO,UAAU;AAAA,IAClF,EAAE,EACD,OAAO,CAAC,QAAQ;AACf,UAAI,iBAAiB,cAAc;AACjC,eAAO,IAAI,yBAAyB;AAAA,MACtC;AAEA,UAAI,iBAAiB,kBAAkB;AACrC,eAAO,IAAI,yBAAyB;AAAA,MACtC;AAEA,aAAO;AAAA,IACT,CAAC;AAEH,UAAM,SAAS;AAAA,MACb,KAAK,IAAI,CAAC,SAAS;AAAA,QACjB,MAAM,CAAC,IAAI,KAAK;AAAA,QAChB,YAAY,EAAE,OAAO,IAAI,MAAM;AAAA,QAC/B,QAAQ,IAAI;AAAA,QACZ,aAAa,IAAI;AAAA,QACjB,aAAa,IAAI;AAAA,QACjB,UAAU,IAAI;AAAA,MAChB,EAAE;AAAA,IACJ;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,SAAS;AAAA,UACP,aAAa,OAAO,cAAc;AAAA,UAClC,eAAe;AAAA,UACf,aAAa,OAAO;AAAA,QACtB;AAAA,QACA,UAAU;AAAA,UACR,cAAc,OAAO;AAAA,UACrB,mBAAmB,OAAO;AAAA,UAC1B,qBAAqB,OAAO;AAAA,UAC5B,kBAAkB,OAAO;AAAA,QAC3B;AAAA,QACA,SAAS;AAAA,QACT,UAAU,wBAAwB;AAAA,UAChC,UAAU,OAAO;AAAA,UACjB,UAAU,OAAO;AAAA,UACjB,cAAc,SAAS,MAAM,UAAU;AAAA,QACzC,CAAC;AAAA,MACH,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
  }
@@ -14,7 +14,7 @@ import {
14
14
  siteUrlSchemaField,
15
15
  startDateSchemaField,
16
16
  normalizeSearchConsoleRow
17
- } from "../../search-console/search-console-utils.js";
17
+ } from "../../services/search-console/search-console-utils.js";
18
18
  import { stripNulls } from "../../utils/strip-payload.js";
19
19
  const searchConsoleQuickWinOpportunitiesSchema = z.object({
20
20
  startDate: startDateSchemaField,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/quick-win-opportunities.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n classifyQuickWinType,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n scoreQuickWinOpportunity,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleQuickWinOpportunitiesSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum impressions required to consider a quick win.\"),\n quickWinMode: z\n .enum([\"ctr\", \"position\", \"mixed\"])\n .optional()\n .describe(\"Whether to prioritize CTR fixes, ranking improvements, or both.\"),\n});\n\nexport async function searchConsoleQuickWinOpportunitiesHandler(\n params: z.infer<typeof searchConsoleQuickWinOpportunitiesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const minImpressions = params.minImpressions ?? 80;\n const quickWinMode = params.quickWinMode ?? \"mixed\";\n\n const response = await querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n );\n\n const opportunities = (response.rows ?? [])\n .map((row) => normalizeSearchConsoleRow(row, [\"query\"]))\n .filter((row) => row.impressions >= minImpressions)\n .map((row) => {\n const quickWinType = classifyQuickWinType(row.position, row.ctr_percent);\n return {\n query: row.dimensions.query,\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n quick_win_type: quickWinType,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n opportunity_score: scoreQuickWinOpportunity({\n impressions: row.impressions,\n ctrPercent: row.ctr_percent,\n position: row.position,\n }),\n };\n })\n .filter((row) => {\n if (quickWinMode === \"mixed\") {\n return row.position > 0 && row.position <= 20;\n }\n\n return row.quick_win_type === quickWinMode;\n })\n .sort((left, right) => right.opportunity_score - left.opportunity_score)\n .map((row) => ({\n ...row,\n reason:\n row.quick_win_type === \"ctr\"\n ? \"The query already ranks fairly well, so a CTR lift is the fastest path.\"\n : \"The query has traction, but ranking improvement appears to be the faster lever.\",\n }));\n\n return object(\n stripNulls({\n site_url: siteUrl,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n thresholds: {\n min_impressions: minImpressions,\n quick_win_mode: quickWinMode,\n },\n opportunities,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to find Search Console quick-win opportunities\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n classifyQuickWinType,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n scoreQuickWinOpportunity,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleQuickWinOpportunitiesSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum impressions required to consider a quick win.\"),\n quickWinMode: z\n .enum([\"ctr\", \"position\", \"mixed\"])\n .optional()\n .describe(\"Whether to prioritize CTR fixes, ranking improvements, or both.\"),\n});\n\nexport async function searchConsoleQuickWinOpportunitiesHandler(\n params: z.infer<typeof searchConsoleQuickWinOpportunitiesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const minImpressions = params.minImpressions ?? 80;\n const quickWinMode = params.quickWinMode ?? \"mixed\";\n\n const response = await querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n );\n\n const opportunities = (response.rows ?? [])\n .map((row) => normalizeSearchConsoleRow(row, [\"query\"]))\n .filter((row) => row.impressions >= minImpressions)\n .map((row) => {\n const quickWinType = classifyQuickWinType(row.position, row.ctr_percent);\n return {\n query: row.dimensions.query,\n clicks: row.clicks,\n impressions: row.impressions,\n ctr_percent: row.ctr_percent,\n position: row.position,\n quick_win_type: quickWinType,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n opportunity_score: scoreQuickWinOpportunity({\n impressions: row.impressions,\n ctrPercent: row.ctr_percent,\n position: row.position,\n }),\n };\n })\n .filter((row) => {\n if (quickWinMode === \"mixed\") {\n return row.position > 0 && row.position <= 20;\n }\n\n return row.quick_win_type === quickWinMode;\n })\n .sort((left, right) => right.opportunity_score - left.opportunity_score)\n .map((row) => ({\n ...row,\n reason:\n row.quick_win_type === \"ctr\"\n ? \"The query already ranks fairly well, so a CTR lift is the fastest path.\"\n : \"The query has traction, but ranking improvement appears to be the faster lever.\",\n }));\n\n return object(\n stripNulls({\n site_url: siteUrl,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n thresholds: {\n min_impressions: minImpressions,\n quick_win_mode: quickWinMode,\n },\n opportunities,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to find Search Console quick-win opportunities\"\n );\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,qCAAqC;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,2CAA2C,EAAE,OAAO;AAAA,EAC/D,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,gBAAgB,EACb,OAAO,EACP,IAAI,CAAC,EACL,SAAS,EACT,SAAS,uDAAuD;AAAA,EACnE,cAAc,EACX,KAAK,CAAC,OAAO,YAAY,OAAO,CAAC,EACjC,SAAS,EACT,SAAS,iEAAiE;AAC/E,CAAC;AAED,eAAsB,0CACpB,QACA;AACA,MAAI;AACF,UAAM,UAAU,4BAA4B,OAAO,SAAS,OAAO,SAAS;AAC5E,UAAM,iBAAiB,OAAO,kBAAkB;AAChD,UAAM,eAAe,OAAO,gBAAgB;AAE5C,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,4BAA4B;AAAA,QAC1B,WAAW,OAAO;AAAA,QAClB,SAAS,OAAO;AAAA,QAChB,YAAY,CAAC,OAAO;AAAA,QACpB,YAAY,OAAO;AAAA,QACnB,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAEA,UAAM,iBAAiB,SAAS,QAAQ,CAAC,GACtC,IAAI,CAAC,QAAQ,0BAA0B,KAAK,CAAC,OAAO,CAAC,CAAC,EACtD,OAAO,CAAC,QAAQ,IAAI,eAAe,cAAc,EACjD,IAAI,CAAC,QAAQ;AACZ,YAAM,eAAe,qBAAqB,IAAI,UAAU,IAAI,WAAW;AACvE,aAAO;AAAA,QACL,OAAO,IAAI,WAAW;AAAA,QACtB,QAAQ,IAAI;AAAA,QACZ,aAAa,IAAI;AAAA,QACjB,aAAa,IAAI;AAAA,QACjB,UAAU,IAAI;AAAA,QACd,gBAAgB;AAAA,QAChB,sBAAsB,mBAAmB,IAAI,WAAW,OAAO,OAAO,UAAU;AAAA,QAChF,mBAAmB,yBAAyB;AAAA,UAC1C,aAAa,IAAI;AAAA,UACjB,YAAY,IAAI;AAAA,UAChB,UAAU,IAAI;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF,CAAC,EACA,OAAO,CAAC,QAAQ;AACf,UAAI,iBAAiB,SAAS;AAC5B,eAAO,IAAI,WAAW,KAAK,IAAI,YAAY;AAAA,MAC7C;AAEA,aAAO,IAAI,mBAAmB;AAAA,IAChC,CAAC,EACA,KAAK,CAAC,MAAM,UAAU,MAAM,oBAAoB,KAAK,iBAAiB,EACtE,IAAI,CAAC,SAAS;AAAA,MACb,GAAG;AAAA,MACH,QACE,IAAI,mBAAmB,QACnB,4EACA;AAAA,IACR,EAAE;AAEJ,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,YAAY;AAAA,UACV,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,QACA;AAAA,MACF,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
  }
@@ -16,7 +16,7 @@ import {
16
16
  searchTypeSchemaField,
17
17
  siteUrlSchemaField,
18
18
  normalizeSearchConsoleRow
19
- } from "../../search-console/search-console-utils.js";
19
+ } from "../../services/search-console/search-console-utils.js";
20
20
  import { stripNulls } from "../../utils/strip-payload.js";
21
21
  const searchConsoleRisingNonBrandQueriesSchema = z.object({
22
22
  currentStartDate: currentStartDateSchemaField,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/rising-non-brand-queries.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildComparisonMap,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n computeChangePercent,\n currentEndDateSchemaField,\n currentStartDateSchemaField,\n previousEndDateSchemaField,\n previousStartDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n searchTypeSchemaField,\n siteUrlSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleRisingNonBrandQueriesSchema = z.object({\n currentStartDate: currentStartDateSchemaField,\n currentEndDate: currentEndDateSchemaField,\n previousStartDate: previousStartDateSchemaField,\n previousEndDate: previousEndDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum current-period impressions required to include a query.\"),\n minGrowthRate: z\n .number()\n .min(0)\n .optional()\n .describe(\"Minimum impressions growth percentage required to consider a query rising.\"),\n});\n\nexport async function searchConsoleRisingNonBrandQueriesHandler(\n params: z.infer<typeof searchConsoleRisingNonBrandQueriesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const minImpressions = params.minImpressions ?? 50;\n const minGrowthRate = params.minGrowthRate ?? 20;\n\n const [currentResponse, previousResponse] = await Promise.all([\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.currentStartDate,\n endDate: params.currentEndDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n ),\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.previousStartDate,\n endDate: params.previousEndDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n ),\n ]);\n\n const currentRows = (currentResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"query\"])\n );\n const previousRows = (previousResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"query\"])\n );\n const previousMap = buildComparisonMap(previousRows, (row) => row.dimensions.query);\n\n const risingQueries = currentRows\n .map((row) => {\n const previousRow = previousMap.get(row.dimensions.query);\n return {\n query: row.dimensions.query,\n current_clicks: row.clicks,\n previous_clicks: previousRow?.clicks ?? 0,\n current_impressions: row.impressions,\n previous_impressions: previousRow?.impressions ?? 0,\n current_ctr_percent: row.ctr_percent,\n previous_ctr_percent: previousRow?.ctr_percent ?? 0,\n current_position: row.position,\n previous_position: previousRow?.position ?? 0,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n };\n })\n .filter((row) => row.brand_classification === \"non_brand\")\n .filter((row) => row.current_impressions >= minImpressions)\n .map((row) => ({\n ...row,\n impressions_growth_percent: computeChangePercent(\n row.current_impressions,\n row.previous_impressions\n ),\n clicks_growth_percent: computeChangePercent(row.current_clicks, row.previous_clicks),\n }))\n .filter((row) => (row.impressions_growth_percent ?? 0) >= minGrowthRate)\n .sort(\n (left, right) =>\n (right.impressions_growth_percent ?? 0) - (left.impressions_growth_percent ?? 0)\n );\n\n return object(\n stripNulls({\n site_url: siteUrl,\n comparison: {\n current_period: {\n start_date: params.currentStartDate,\n end_date: params.currentEndDate,\n },\n previous_period: {\n start_date: params.previousStartDate,\n end_date: params.previousEndDate,\n },\n },\n thresholds: {\n min_impressions: minImpressions,\n min_growth_rate_percent: minGrowthRate,\n },\n rising_queries: risingQueries,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to find Search Console rising non-brand queries\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n brandTermsSchemaField,\n buildComparisonMap,\n buildSearchConsoleQueryBody,\n classifyBrandLabel,\n computeChangePercent,\n currentEndDateSchemaField,\n currentStartDateSchemaField,\n previousEndDateSchemaField,\n previousStartDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n searchTypeSchemaField,\n siteUrlSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleRisingNonBrandQueriesSchema = z.object({\n currentStartDate: currentStartDateSchemaField,\n currentEndDate: currentEndDateSchemaField,\n previousStartDate: previousStartDateSchemaField,\n previousEndDate: previousEndDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n brandTerms: brandTermsSchemaField,\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum current-period impressions required to include a query.\"),\n minGrowthRate: z\n .number()\n .min(0)\n .optional()\n .describe(\"Minimum impressions growth percentage required to consider a query rising.\"),\n});\n\nexport async function searchConsoleRisingNonBrandQueriesHandler(\n params: z.infer<typeof searchConsoleRisingNonBrandQueriesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const minImpressions = params.minImpressions ?? 50;\n const minGrowthRate = params.minGrowthRate ?? 20;\n\n const [currentResponse, previousResponse] = await Promise.all([\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.currentStartDate,\n endDate: params.currentEndDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n ),\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.previousStartDate,\n endDate: params.previousEndDate,\n dimensions: [\"query\"],\n searchType: params.searchType,\n rowLimit: 250,\n })\n ),\n ]);\n\n const currentRows = (currentResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"query\"])\n );\n const previousRows = (previousResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"query\"])\n );\n const previousMap = buildComparisonMap(previousRows, (row) => row.dimensions.query);\n\n const risingQueries = currentRows\n .map((row) => {\n const previousRow = previousMap.get(row.dimensions.query);\n return {\n query: row.dimensions.query,\n current_clicks: row.clicks,\n previous_clicks: previousRow?.clicks ?? 0,\n current_impressions: row.impressions,\n previous_impressions: previousRow?.impressions ?? 0,\n current_ctr_percent: row.ctr_percent,\n previous_ctr_percent: previousRow?.ctr_percent ?? 0,\n current_position: row.position,\n previous_position: previousRow?.position ?? 0,\n brand_classification: classifyBrandLabel(row.dimensions.query, params.brandTerms),\n };\n })\n .filter((row) => row.brand_classification === \"non_brand\")\n .filter((row) => row.current_impressions >= minImpressions)\n .map((row) => ({\n ...row,\n impressions_growth_percent: computeChangePercent(\n row.current_impressions,\n row.previous_impressions\n ),\n clicks_growth_percent: computeChangePercent(row.current_clicks, row.previous_clicks),\n }))\n .filter((row) => (row.impressions_growth_percent ?? 0) >= minGrowthRate)\n .sort(\n (left, right) =>\n (right.impressions_growth_percent ?? 0) - (left.impressions_growth_percent ?? 0)\n );\n\n return object(\n stripNulls({\n site_url: siteUrl,\n comparison: {\n current_period: {\n start_date: params.currentStartDate,\n end_date: params.currentEndDate,\n },\n previous_period: {\n start_date: params.previousStartDate,\n end_date: params.previousEndDate,\n },\n },\n thresholds: {\n min_impressions: minImpressions,\n min_growth_rate_percent: minGrowthRate,\n },\n rising_queries: risingQueries,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to find Search Console rising non-brand queries\"\n );\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -17,7 +17,7 @@ import {
17
17
  startRowSchemaField,
18
18
  sumSearchConsoleRows,
19
19
  normalizeSearchConsoleRow
20
- } from "../../search-console/search-console-utils.js";
20
+ } from "../../services/search-console/search-console-utils.js";
21
21
  import { stripNulls } from "../../utils/strip-payload.js";
22
22
  const searchConsoleSearchPerformanceSchema = z.object({
23
23
  startDate: startDateSchemaField,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/search-performance.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n buildPaginationMetadata,\n buildSearchConsoleQueryBody,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n rowLimitSchemaField,\n searchConsoleAggregationTypes,\n searchConsoleDimensionFilterSchema,\n searchConsoleDimensions,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n startRowSchemaField,\n sumSearchConsoleRows,\n normalizeSearchConsoleRow,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleSearchPerformanceSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n dimensions: z\n .array(z.enum(searchConsoleDimensions))\n .max(5)\n .optional()\n .describe(\"Dimensions to group the Search Console query by.\"),\n searchType: searchTypeSchemaField,\n dimensionFilters: z\n .array(searchConsoleDimensionFilterSchema)\n .max(10)\n .optional()\n .describe(\"Optional Search Console dimension filters.\"),\n aggregationType: z\n .enum(searchConsoleAggregationTypes)\n .optional()\n .describe(\"Aggregation type for the Search Console query.\"),\n rowLimit: rowLimitSchemaField,\n startRow: startRowSchemaField,\n});\n\nexport async function searchConsoleSearchPerformanceHandler(\n params: z.infer<typeof searchConsoleSearchPerformanceSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const dimensions = params.dimensions ?? [];\n const body = buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions,\n searchType: params.searchType,\n dimensionFilters: params.dimensionFilters,\n aggregationType: params.aggregationType,\n rowLimit: params.rowLimit,\n startRow: params.startRow,\n });\n\n const response = await querySearchConsolePerformance(siteUrl, body);\n const rows = (response.rows ?? []).map((row) => normalizeSearchConsoleRow(row, dimensions));\n const totals = sumSearchConsoleRows(rows);\n\n return object(\n stripNulls({\n site_url: siteUrl,\n profile_id: params.profileId?.trim() || undefined,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n query: {\n dimensions,\n search_type: params.searchType ?? \"web\",\n aggregation_type: params.aggregationType ?? response.responseAggregationType,\n dimension_filters: params.dimensionFilters,\n },\n overview: {\n total_clicks: totals.clicks,\n total_impressions: totals.impressions,\n average_ctr_percent: totals.ctrPercent,\n average_position: totals.averagePosition,\n },\n rows,\n metadata: buildPaginationMetadata({\n startRow: params.startRow,\n rowLimit: params.rowLimit,\n returnedRows: rows.length,\n }),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Search Console search performance\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n buildPaginationMetadata,\n buildSearchConsoleQueryBody,\n endDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n rowLimitSchemaField,\n searchConsoleAggregationTypes,\n searchConsoleDimensionFilterSchema,\n searchConsoleDimensions,\n searchTypeSchemaField,\n siteUrlSchemaField,\n startDateSchemaField,\n startRowSchemaField,\n sumSearchConsoleRows,\n normalizeSearchConsoleRow,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleSearchPerformanceSchema = z.object({\n startDate: startDateSchemaField,\n endDate: endDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n dimensions: z\n .array(z.enum(searchConsoleDimensions))\n .max(5)\n .optional()\n .describe(\"Dimensions to group the Search Console query by.\"),\n searchType: searchTypeSchemaField,\n dimensionFilters: z\n .array(searchConsoleDimensionFilterSchema)\n .max(10)\n .optional()\n .describe(\"Optional Search Console dimension filters.\"),\n aggregationType: z\n .enum(searchConsoleAggregationTypes)\n .optional()\n .describe(\"Aggregation type for the Search Console query.\"),\n rowLimit: rowLimitSchemaField,\n startRow: startRowSchemaField,\n});\n\nexport async function searchConsoleSearchPerformanceHandler(\n params: z.infer<typeof searchConsoleSearchPerformanceSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const dimensions = params.dimensions ?? [];\n const body = buildSearchConsoleQueryBody({\n startDate: params.startDate,\n endDate: params.endDate,\n dimensions,\n searchType: params.searchType,\n dimensionFilters: params.dimensionFilters,\n aggregationType: params.aggregationType,\n rowLimit: params.rowLimit,\n startRow: params.startRow,\n });\n\n const response = await querySearchConsolePerformance(siteUrl, body);\n const rows = (response.rows ?? []).map((row) => normalizeSearchConsoleRow(row, dimensions));\n const totals = sumSearchConsoleRows(rows);\n\n return object(\n stripNulls({\n site_url: siteUrl,\n profile_id: params.profileId?.trim() || undefined,\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n query: {\n dimensions,\n search_type: params.searchType ?? \"web\",\n aggregation_type: params.aggregationType ?? response.responseAggregationType,\n dimension_filters: params.dimensionFilters,\n },\n overview: {\n total_clicks: totals.clicks,\n total_impressions: totals.impressions,\n average_ctr_percent: totals.ctrPercent,\n average_position: totals.averagePosition,\n },\n rows,\n metadata: buildPaginationMetadata({\n startRow: params.startRow,\n rowLimit: params.rowLimit,\n returnedRows: rows.length,\n }),\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Search Console search performance\"\n );\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,qCAAqC;AAC9C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,uCAAuC,EAAE,OAAO;AAAA,EAC3D,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY,EACT,MAAM,EAAE,KAAK,uBAAuB,CAAC,EACrC,IAAI,CAAC,EACL,SAAS,EACT,SAAS,kDAAkD;AAAA,EAC9D,YAAY;AAAA,EACZ,kBAAkB,EACf,MAAM,kCAAkC,EACxC,IAAI,EAAE,EACN,SAAS,EACT,SAAS,4CAA4C;AAAA,EACxD,iBAAiB,EACd,KAAK,6BAA6B,EAClC,SAAS,EACT,SAAS,gDAAgD;AAAA,EAC5D,UAAU;AAAA,EACV,UAAU;AACZ,CAAC;AAED,eAAsB,sCACpB,QACA;AACA,MAAI;AACF,UAAM,UAAU,4BAA4B,OAAO,SAAS,OAAO,SAAS;AAC5E,UAAM,aAAa,OAAO,cAAc,CAAC;AACzC,UAAM,OAAO,4BAA4B;AAAA,MACvC,WAAW,OAAO;AAAA,MAClB,SAAS,OAAO;AAAA,MAChB;AAAA,MACA,YAAY,OAAO;AAAA,MACnB,kBAAkB,OAAO;AAAA,MACzB,iBAAiB,OAAO;AAAA,MACxB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,IACnB,CAAC;AAED,UAAM,WAAW,MAAM,8BAA8B,SAAS,IAAI;AAClE,UAAM,QAAQ,SAAS,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,0BAA0B,KAAK,UAAU,CAAC;AAC1F,UAAM,SAAS,qBAAqB,IAAI;AAExC,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,QACV,YAAY,OAAO,WAAW,KAAK,KAAK;AAAA,QACxC,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,OAAO;AAAA,UACL;AAAA,UACA,aAAa,OAAO,cAAc;AAAA,UAClC,kBAAkB,OAAO,mBAAmB,SAAS;AAAA,UACrD,mBAAmB,OAAO;AAAA,QAC5B;AAAA,QACA,UAAU;AAAA,UACR,cAAc,OAAO;AAAA,UACrB,mBAAmB,OAAO;AAAA,UAC1B,qBAAqB,OAAO;AAAA,UAC5B,kBAAkB,OAAO;AAAA,QAC3B;AAAA,QACA;AAAA,QACA,UAAU,wBAAwB;AAAA,UAChC,UAAU,OAAO;AAAA,UACjB,UAAU,OAAO;AAAA,UACjB,cAAc,KAAK;AAAA,QACrB,CAAC;AAAA,MACH,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
  }
@@ -6,7 +6,7 @@ import {
6
6
  profileIdSchemaField,
7
7
  resolveSearchConsoleSiteUrl,
8
8
  siteUrlSchemaField
9
- } from "../../search-console/search-console-utils.js";
9
+ } from "../../services/search-console/search-console-utils.js";
10
10
  import { stripNulls } from "../../utils/strip-payload.js";
11
11
  const searchConsoleSiteContextSchema = z.object({
12
12
  siteUrl: siteUrlSchemaField,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/site-context.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listSearchConsoleSites } from \"../../services/search-console/search-console-client.js\";\nimport {\n inferSearchConsolePropertyType,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n siteUrlSchemaField,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleSiteContextSchema = z.object({\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n});\n\nexport async function searchConsoleSiteContextHandler(\n params: z.infer<typeof searchConsoleSiteContextSchema>\n) {\n try {\n const resolvedSiteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const sites = await listSearchConsoleSites();\n const matchingSite = sites.find((site) => site.siteUrl === resolvedSiteUrl);\n\n if (!matchingSite) {\n throw new Error(\n `Search Console site \"${resolvedSiteUrl}\" is not accessible with the current credentials. Call gsc_list_accessible_sites to see the available properties.`\n );\n }\n\n return object(\n stripNulls({\n site_url: resolvedSiteUrl,\n source: params.siteUrl?.trim() ? \"explicit_parameter\" : \"future_profile_resolution\",\n property_type: inferSearchConsolePropertyType(resolvedSiteUrl),\n permission_level: matchingSite.permissionLevel?.toLowerCase(),\n profile_id: params.profileId?.trim() || undefined,\n is_accessible: true,\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to resolve Search Console site context\");\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listSearchConsoleSites } from \"../../services/search-console/search-console-client.js\";\nimport {\n inferSearchConsolePropertyType,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n siteUrlSchemaField,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleSiteContextSchema = z.object({\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n});\n\nexport async function searchConsoleSiteContextHandler(\n params: z.infer<typeof searchConsoleSiteContextSchema>\n) {\n try {\n const resolvedSiteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const sites = await listSearchConsoleSites();\n const matchingSite = sites.find((site) => site.siteUrl === resolvedSiteUrl);\n\n if (!matchingSite) {\n throw new Error(\n `Search Console site \"${resolvedSiteUrl}\" is not accessible with the current credentials. Call gsc_list_accessible_sites to see the available properties.`\n );\n }\n\n return object(\n stripNulls({\n site_url: resolvedSiteUrl,\n source: params.siteUrl?.trim() ? \"explicit_parameter\" : \"future_profile_resolution\",\n property_type: inferSearchConsolePropertyType(resolvedSiteUrl),\n permission_level: matchingSite.permissionLevel?.toLowerCase(),\n profile_id: params.profileId?.trim() || undefined,\n is_accessible: true,\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to resolve Search Console site context\");\n }\n}\n"],
5
5
  "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,iCAAiC,EAAE,OAAO;AAAA,EACrD,SAAS;AAAA,EACT,WAAW;AACb,CAAC;AAED,eAAsB,gCACpB,QACA;AACA,MAAI;AACF,UAAM,kBAAkB,4BAA4B,OAAO,SAAS,OAAO,SAAS;AACpF,UAAM,QAAQ,MAAM,uBAAuB;AAC3C,UAAM,eAAe,MAAM,KAAK,CAAC,SAAS,KAAK,YAAY,eAAe;AAE1E,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI;AAAA,QACR,wBAAwB,eAAe;AAAA,MACzC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,OAAO,SAAS,KAAK,IAAI,uBAAuB;AAAA,QACxD,eAAe,+BAA+B,eAAe;AAAA,QAC7D,kBAAkB,aAAa,iBAAiB,YAAY;AAAA,QAC5D,YAAY,OAAO,WAAW,KAAK,KAAK;AAAA,QACxC,eAAe;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,+CAA+C;AAAA,EACnG;AACF;",
6
6
  "names": []
7
7
  }
@@ -14,7 +14,7 @@ import {
14
14
  searchTypeSchemaField,
15
15
  siteUrlSchemaField,
16
16
  normalizeSearchConsoleRow
17
- } from "../../search-console/search-console-utils.js";
17
+ } from "../../services/search-console/search-console-utils.js";
18
18
  import { stripNulls } from "../../utils/strip-payload.js";
19
19
  const searchConsoleVisibilityDeclinesSchema = z.object({
20
20
  currentStartDate: currentStartDateSchemaField,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/search-console/visibility-declines.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n buildComparisonMap,\n buildSearchConsoleQueryBody,\n computeChangePercent,\n currentEndDateSchemaField,\n currentStartDateSchemaField,\n previousEndDateSchemaField,\n previousStartDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n searchTypeSchemaField,\n siteUrlSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleVisibilityDeclinesSchema = z.object({\n currentStartDate: currentStartDateSchemaField,\n currentEndDate: currentEndDateSchemaField,\n previousStartDate: previousStartDateSchemaField,\n previousEndDate: previousEndDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n entityType: z\n .enum([\"page\", \"pattern\"])\n .optional()\n .describe(\"Analyze individual pages or a filtered page pattern.\"),\n pageContains: z\n .string()\n .optional()\n .describe(\"Optional page substring filter to focus the visibility decline analysis.\"),\n pageRegex: z\n .string()\n .optional()\n .describe(\"Optional regex page filter to focus the decline analysis.\"),\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum previous-period impressions required to include an entity in the decline analysis.\"),\n});\n\nexport async function searchConsoleVisibilityDeclinesHandler(\n params: z.infer<typeof searchConsoleVisibilityDeclinesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const entityType = params.entityType ?? \"page\";\n const minImpressions = params.minImpressions ?? 50;\n const dimensionFilters = [];\n\n if (params.pageContains?.trim()) {\n dimensionFilters.push({\n dimension: \"page\",\n operator: \"contains\",\n expression: params.pageContains.trim(),\n });\n }\n\n if (params.pageRegex?.trim()) {\n dimensionFilters.push({\n dimension: \"page\",\n operator: \"includingRegex\",\n expression: params.pageRegex.trim(),\n });\n }\n\n const [currentResponse, previousResponse] = await Promise.all([\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.currentStartDate,\n endDate: params.currentEndDate,\n dimensions: [\"page\"],\n searchType: params.searchType,\n dimensionFilters,\n rowLimit: 250,\n })\n ),\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.previousStartDate,\n endDate: params.previousEndDate,\n dimensions: [\"page\"],\n searchType: params.searchType,\n dimensionFilters,\n rowLimit: 250,\n })\n ),\n ]);\n\n const currentRows = (currentResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"page\"])\n );\n const previousRows = (previousResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"page\"])\n );\n const previousMap = buildComparisonMap(previousRows, (row) => row.dimensions.page);\n\n const currentMap = buildComparisonMap(currentRows, (row) => row.dimensions.page);\n const allPages = new Set([\n ...currentRows.map((row) => row.dimensions.page),\n ...previousRows.map((row) => row.dimensions.page),\n ]);\n\n const declines = Array.from(allPages)\n .map((page) => {\n const currentRow = currentMap.get(page);\n const previousRow = previousMap.get(page);\n return {\n page,\n current_clicks: currentRow?.clicks ?? 0,\n previous_clicks: previousRow?.clicks ?? 0,\n current_impressions: currentRow?.impressions ?? 0,\n previous_impressions: previousRow?.impressions ?? 0,\n current_ctr_percent: currentRow?.ctr_percent ?? 0,\n previous_ctr_percent: previousRow?.ctr_percent ?? 0,\n current_position: currentRow?.position ?? 0,\n previous_position: previousRow?.position ?? 0,\n };\n })\n .filter((row) => row.previous_impressions >= minImpressions)\n .map((row) => ({\n ...row,\n clicks_change_percent: computeChangePercent(row.current_clicks, row.previous_clicks),\n impressions_change_percent: computeChangePercent(\n row.current_impressions,\n row.previous_impressions\n ),\n ctr_change_percent: computeChangePercent(row.current_ctr_percent, row.previous_ctr_percent),\n position_change: row.current_position - row.previous_position,\n }))\n .filter(\n (row) =>\n (row.clicks_change_percent ?? 0) < 0 ||\n (row.impressions_change_percent ?? 0) < 0 ||\n row.position_change > 0\n )\n .sort((left, right) => (left.clicks_change_percent ?? 0) - (right.clicks_change_percent ?? 0));\n\n return object(\n stripNulls({\n site_url: siteUrl,\n comparison: {\n current_period: {\n start_date: params.currentStartDate,\n end_date: params.currentEndDate,\n },\n previous_period: {\n start_date: params.previousStartDate,\n end_date: params.previousEndDate,\n },\n },\n filters: {\n entity_type: entityType,\n page_contains: params.pageContains,\n page_regex: params.pageRegex,\n min_impressions: minImpressions,\n },\n declines,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to detect Search Console visibility declines\"\n );\n }\n}\n"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { querySearchConsolePerformance } from \"../../services/search-console/search-console-client.js\";\nimport {\n buildComparisonMap,\n buildSearchConsoleQueryBody,\n computeChangePercent,\n currentEndDateSchemaField,\n currentStartDateSchemaField,\n previousEndDateSchemaField,\n previousStartDateSchemaField,\n profileIdSchemaField,\n resolveSearchConsoleSiteUrl,\n searchTypeSchemaField,\n siteUrlSchemaField,\n normalizeSearchConsoleRow,\n} from \"../../services/search-console/search-console-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const searchConsoleVisibilityDeclinesSchema = z.object({\n currentStartDate: currentStartDateSchemaField,\n currentEndDate: currentEndDateSchemaField,\n previousStartDate: previousStartDateSchemaField,\n previousEndDate: previousEndDateSchemaField,\n siteUrl: siteUrlSchemaField,\n profileId: profileIdSchemaField,\n searchType: searchTypeSchemaField,\n entityType: z\n .enum([\"page\", \"pattern\"])\n .optional()\n .describe(\"Analyze individual pages or a filtered page pattern.\"),\n pageContains: z\n .string()\n .optional()\n .describe(\"Optional page substring filter to focus the visibility decline analysis.\"),\n pageRegex: z\n .string()\n .optional()\n .describe(\"Optional regex page filter to focus the decline analysis.\"),\n minImpressions: z\n .number()\n .min(1)\n .optional()\n .describe(\"Minimum previous-period impressions required to include an entity in the decline analysis.\"),\n});\n\nexport async function searchConsoleVisibilityDeclinesHandler(\n params: z.infer<typeof searchConsoleVisibilityDeclinesSchema>\n) {\n try {\n const siteUrl = resolveSearchConsoleSiteUrl(params.siteUrl, params.profileId);\n const entityType = params.entityType ?? \"page\";\n const minImpressions = params.minImpressions ?? 50;\n const dimensionFilters = [];\n\n if (params.pageContains?.trim()) {\n dimensionFilters.push({\n dimension: \"page\",\n operator: \"contains\",\n expression: params.pageContains.trim(),\n });\n }\n\n if (params.pageRegex?.trim()) {\n dimensionFilters.push({\n dimension: \"page\",\n operator: \"includingRegex\",\n expression: params.pageRegex.trim(),\n });\n }\n\n const [currentResponse, previousResponse] = await Promise.all([\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.currentStartDate,\n endDate: params.currentEndDate,\n dimensions: [\"page\"],\n searchType: params.searchType,\n dimensionFilters,\n rowLimit: 250,\n })\n ),\n querySearchConsolePerformance(\n siteUrl,\n buildSearchConsoleQueryBody({\n startDate: params.previousStartDate,\n endDate: params.previousEndDate,\n dimensions: [\"page\"],\n searchType: params.searchType,\n dimensionFilters,\n rowLimit: 250,\n })\n ),\n ]);\n\n const currentRows = (currentResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"page\"])\n );\n const previousRows = (previousResponse.rows ?? []).map((row) =>\n normalizeSearchConsoleRow(row, [\"page\"])\n );\n const previousMap = buildComparisonMap(previousRows, (row) => row.dimensions.page);\n\n const currentMap = buildComparisonMap(currentRows, (row) => row.dimensions.page);\n const allPages = new Set([\n ...currentRows.map((row) => row.dimensions.page),\n ...previousRows.map((row) => row.dimensions.page),\n ]);\n\n const declines = Array.from(allPages)\n .map((page) => {\n const currentRow = currentMap.get(page);\n const previousRow = previousMap.get(page);\n return {\n page,\n current_clicks: currentRow?.clicks ?? 0,\n previous_clicks: previousRow?.clicks ?? 0,\n current_impressions: currentRow?.impressions ?? 0,\n previous_impressions: previousRow?.impressions ?? 0,\n current_ctr_percent: currentRow?.ctr_percent ?? 0,\n previous_ctr_percent: previousRow?.ctr_percent ?? 0,\n current_position: currentRow?.position ?? 0,\n previous_position: previousRow?.position ?? 0,\n };\n })\n .filter((row) => row.previous_impressions >= minImpressions)\n .map((row) => ({\n ...row,\n clicks_change_percent: computeChangePercent(row.current_clicks, row.previous_clicks),\n impressions_change_percent: computeChangePercent(\n row.current_impressions,\n row.previous_impressions\n ),\n ctr_change_percent: computeChangePercent(row.current_ctr_percent, row.previous_ctr_percent),\n position_change: row.current_position - row.previous_position,\n }))\n .filter(\n (row) =>\n (row.clicks_change_percent ?? 0) < 0 ||\n (row.impressions_change_percent ?? 0) < 0 ||\n row.position_change > 0\n )\n .sort((left, right) => (left.clicks_change_percent ?? 0) - (right.clicks_change_percent ?? 0));\n\n return object(\n stripNulls({\n site_url: siteUrl,\n comparison: {\n current_period: {\n start_date: params.currentStartDate,\n end_date: params.currentEndDate,\n },\n previous_period: {\n start_date: params.previousStartDate,\n end_date: params.previousEndDate,\n },\n },\n filters: {\n entity_type: entityType,\n page_contains: params.pageContains,\n page_regex: params.pageRegex,\n min_impressions: minImpressions,\n },\n declines,\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to detect Search Console visibility declines\"\n );\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ import {
3
+ buildSkuUpdatePayload,
4
+ getSku,
5
+ updateSku
6
+ } from "../../services/vtex/vtex-catalog-write.js";
7
+ import {
8
+ buildWriteSuccessResponse,
9
+ handleVtexWriteError,
10
+ resolveVtexWriteProfile,
11
+ vtexProfileIdSchemaField
12
+ } from "./write-helpers.js";
13
+ const activateSkuSchema = z.object({
14
+ profileId: vtexProfileIdSchemaField,
15
+ skuId: z.string().min(1).describe("VTEX SKU identifier to activate.")
16
+ });
17
+ async function activateSkuHandler({
18
+ profileId,
19
+ skuId
20
+ }) {
21
+ try {
22
+ const profileResolution = await resolveVtexWriteProfile(profileId);
23
+ if (!profileResolution.ok) {
24
+ return profileResolution.response;
25
+ }
26
+ const resolvedProfileId = profileResolution.value.profileId;
27
+ const beforeSku = await getSku(resolvedProfileId, skuId);
28
+ const afterSku = await updateSku(
29
+ resolvedProfileId,
30
+ skuId,
31
+ buildSkuUpdatePayload(beforeSku, { isActive: true })
32
+ );
33
+ return buildWriteSuccessResponse({
34
+ profileId: resolvedProfileId,
35
+ operation: "activate_sku",
36
+ resourceId: skuId,
37
+ riskLevel: "low",
38
+ message: "SKU activated successfully.",
39
+ before: beforeSku,
40
+ after: afterSku,
41
+ details: {
42
+ sku_id: skuId
43
+ }
44
+ });
45
+ } catch (err) {
46
+ return handleVtexWriteError(err, `Failed to activate SKU ${skuId}`);
47
+ }
48
+ }
49
+ export {
50
+ activateSkuHandler,
51
+ activateSkuSchema
52
+ };
53
+ //# sourceMappingURL=activate-sku.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/vtex/activate-sku.ts"],
4
+ "sourcesContent": ["import { z } from \"zod\";\n\nimport {\n buildSkuUpdatePayload,\n getSku,\n updateSku,\n} from \"../../services/vtex/vtex-catalog-write.js\";\nimport {\n buildWriteSuccessResponse,\n handleVtexWriteError,\n resolveVtexWriteProfile,\n vtexProfileIdSchemaField,\n} from \"./write-helpers.js\";\n\nexport const activateSkuSchema = z.object({\n profileId: vtexProfileIdSchemaField,\n skuId: z.string().min(1).describe(\"VTEX SKU identifier to activate.\"),\n});\n\nexport async function activateSkuHandler({\n profileId,\n skuId,\n}: z.infer<typeof activateSkuSchema>) {\n try {\n const profileResolution = await resolveVtexWriteProfile(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const beforeSku = await getSku(resolvedProfileId, skuId);\n const afterSku = await updateSku(\n resolvedProfileId,\n skuId,\n buildSkuUpdatePayload(beforeSku, { isActive: true })\n );\n\n return buildWriteSuccessResponse({\n profileId: resolvedProfileId,\n operation: \"activate_sku\",\n resourceId: skuId,\n riskLevel: \"low\",\n message: \"SKU activated successfully.\",\n before: beforeSku,\n after: afterSku,\n details: {\n sku_id: skuId,\n },\n });\n } catch (err) {\n return handleVtexWriteError(err, `Failed to activate SKU ${skuId}`);\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,WAAW;AAAA,EACX,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,kCAAkC;AACtE,CAAC;AAED,eAAsB,mBAAmB;AAAA,EACvC;AAAA,EACA;AACF,GAAsC;AACpC,MAAI;AACF,UAAM,oBAAoB,MAAM,wBAAwB,SAAS;AACjE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,YAAY,MAAM,OAAO,mBAAmB,KAAK;AACvD,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA,sBAAsB,WAAW,EAAE,UAAU,KAAK,CAAC;AAAA,IACrD;AAEA,WAAO,0BAA0B;AAAA,MAC/B,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,qBAAqB,KAAK,0BAA0B,KAAK,EAAE;AAAA,EACpE;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+ import {
3
+ getOrderStateSnapshot,
4
+ updateOrderTrackingStatus,
5
+ updatePartialInvoiceTracking,
6
+ validateOrderForTracking
7
+ } from "../../services/vtex/vtex-orders-write.js";
8
+ import {
9
+ buildWriteSuccessResponse,
10
+ confirmationNoteSchemaField,
11
+ confirmationSchemaField,
12
+ handleVtexWriteError,
13
+ requireExplicitConfirmation,
14
+ resolveVtexWriteProfile,
15
+ vtexProfileIdSchemaField
16
+ } from "./write-helpers.js";
17
+ const trackingEventSchema = z.object({
18
+ city: z.string().min(1).describe("Tracking event city."),
19
+ state: z.string().min(1).describe("Tracking event state."),
20
+ description: z.string().min(1).describe("Tracking event description."),
21
+ date: z.string().min(1).describe("Tracking event date string.")
22
+ });
23
+ const addOrderTrackingSchema = z.object({
24
+ profileId: vtexProfileIdSchemaField,
25
+ orderId: z.string().min(1).describe("VTEX order identifier."),
26
+ invoiceNumber: z.string().min(1).describe("Invoice number that will receive tracking data."),
27
+ confirmed: confirmationSchemaField,
28
+ confirmationNote: confirmationNoteSchemaField,
29
+ trackingNumber: z.string().min(1).describe("Tracking number."),
30
+ trackingUrl: z.string().url().optional().describe("Tracking URL."),
31
+ courier: z.string().optional().describe("Carrier name."),
32
+ dispatchedDate: z.string().min(1).describe("Dispatch timestamp."),
33
+ isDelivered: z.boolean().optional().describe("Optional delivery status to send to VTEX tracking timeline."),
34
+ deliveredDate: z.string().optional().describe("Optional delivered date in `yyyy-mm-dd hh:mm` format."),
35
+ events: z.array(trackingEventSchema).optional().describe("Optional tracking events timeline.")
36
+ });
37
+ async function addOrderTrackingHandler({
38
+ profileId,
39
+ orderId,
40
+ invoiceNumber,
41
+ confirmed,
42
+ confirmationNote,
43
+ trackingNumber,
44
+ trackingUrl,
45
+ courier,
46
+ dispatchedDate,
47
+ isDelivered,
48
+ deliveredDate,
49
+ events
50
+ }) {
51
+ const confirmationResponse = requireExplicitConfirmation(confirmed, "add_order_tracking", {
52
+ order_id: orderId,
53
+ invoice_number: invoiceNumber
54
+ });
55
+ if (confirmationResponse) {
56
+ return confirmationResponse;
57
+ }
58
+ try {
59
+ const profileResolution = await resolveVtexWriteProfile(profileId);
60
+ if (!profileResolution.ok) {
61
+ return profileResolution.response;
62
+ }
63
+ const resolvedProfileId = profileResolution.value.profileId;
64
+ const beforeOrder = await validateOrderForTracking(resolvedProfileId, orderId, invoiceNumber);
65
+ await updatePartialInvoiceTracking(resolvedProfileId, orderId, invoiceNumber, {
66
+ trackingNumber,
67
+ trackingUrl,
68
+ courier,
69
+ dispatchedDate
70
+ });
71
+ if (events?.length || isDelivered !== void 0) {
72
+ await updateOrderTrackingStatus(resolvedProfileId, orderId, invoiceNumber, {
73
+ isDelivered: isDelivered ?? false,
74
+ deliveredDate: deliveredDate ?? null,
75
+ events: events ?? []
76
+ });
77
+ }
78
+ const afterOrder = await getOrderStateSnapshot(resolvedProfileId, orderId);
79
+ return buildWriteSuccessResponse({
80
+ profileId: resolvedProfileId,
81
+ operation: "add_order_tracking",
82
+ resourceId: orderId,
83
+ riskLevel: "high",
84
+ confirmed: true,
85
+ confirmationNote,
86
+ message: "Order tracking updated successfully.",
87
+ before: beforeOrder,
88
+ after: afterOrder,
89
+ details: {
90
+ order_id: orderId,
91
+ invoice_number: invoiceNumber,
92
+ tracking_number: trackingNumber
93
+ }
94
+ });
95
+ } catch (err) {
96
+ return handleVtexWriteError(err, `Failed to update tracking for order ${orderId}`);
97
+ }
98
+ }
99
+ export {
100
+ addOrderTrackingHandler,
101
+ addOrderTrackingSchema
102
+ };
103
+ //# sourceMappingURL=add-order-tracking.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/vtex/add-order-tracking.ts"],
4
+ "sourcesContent": ["import { z } from \"zod\";\n\nimport {\n getOrderStateSnapshot,\n updateOrderTrackingStatus,\n updatePartialInvoiceTracking,\n validateOrderForTracking,\n} from \"../../services/vtex/vtex-orders-write.js\";\nimport {\n buildWriteSuccessResponse,\n confirmationNoteSchemaField,\n confirmationSchemaField,\n handleVtexWriteError,\n requireExplicitConfirmation,\n resolveVtexWriteProfile,\n vtexProfileIdSchemaField,\n} from \"./write-helpers.js\";\n\nconst trackingEventSchema = z.object({\n city: z.string().min(1).describe(\"Tracking event city.\"),\n state: z.string().min(1).describe(\"Tracking event state.\"),\n description: z.string().min(1).describe(\"Tracking event description.\"),\n date: z.string().min(1).describe(\"Tracking event date string.\"),\n});\n\nexport const addOrderTrackingSchema = z.object({\n profileId: vtexProfileIdSchemaField,\n orderId: z.string().min(1).describe(\"VTEX order identifier.\"),\n invoiceNumber: z.string().min(1).describe(\"Invoice number that will receive tracking data.\"),\n confirmed: confirmationSchemaField,\n confirmationNote: confirmationNoteSchemaField,\n trackingNumber: z.string().min(1).describe(\"Tracking number.\"),\n trackingUrl: z.string().url().optional().describe(\"Tracking URL.\"),\n courier: z.string().optional().describe(\"Carrier name.\"),\n dispatchedDate: z.string().min(1).describe(\"Dispatch timestamp.\"),\n isDelivered: z\n .boolean()\n .optional()\n .describe(\"Optional delivery status to send to VTEX tracking timeline.\"),\n deliveredDate: z\n .string()\n .optional()\n .describe(\"Optional delivered date in `yyyy-mm-dd hh:mm` format.\"),\n events: z.array(trackingEventSchema).optional().describe(\"Optional tracking events timeline.\"),\n});\n\nexport async function addOrderTrackingHandler({\n profileId,\n orderId,\n invoiceNumber,\n confirmed,\n confirmationNote,\n trackingNumber,\n trackingUrl,\n courier,\n dispatchedDate,\n isDelivered,\n deliveredDate,\n events,\n}: z.infer<typeof addOrderTrackingSchema>) {\n const confirmationResponse = requireExplicitConfirmation(confirmed, \"add_order_tracking\", {\n order_id: orderId,\n invoice_number: invoiceNumber,\n });\n if (confirmationResponse) {\n return confirmationResponse;\n }\n\n try {\n const profileResolution = await resolveVtexWriteProfile(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const beforeOrder = await validateOrderForTracking(resolvedProfileId, orderId, invoiceNumber);\n\n await updatePartialInvoiceTracking(resolvedProfileId, orderId, invoiceNumber, {\n trackingNumber,\n trackingUrl,\n courier,\n dispatchedDate,\n });\n\n if (events?.length || isDelivered !== undefined) {\n await updateOrderTrackingStatus(resolvedProfileId, orderId, invoiceNumber, {\n isDelivered: isDelivered ?? false,\n deliveredDate: deliveredDate ?? null,\n events: events ?? [],\n });\n }\n\n const afterOrder = await getOrderStateSnapshot(resolvedProfileId, orderId);\n\n return buildWriteSuccessResponse({\n profileId: resolvedProfileId,\n operation: \"add_order_tracking\",\n resourceId: orderId,\n riskLevel: \"high\",\n confirmed: true,\n confirmationNote,\n message: \"Order tracking updated successfully.\",\n before: beforeOrder as unknown as Record<string, unknown>,\n after: afterOrder as unknown as Record<string, unknown>,\n details: {\n order_id: orderId,\n invoice_number: invoiceNumber,\n tracking_number: trackingNumber,\n },\n });\n } catch (err) {\n return handleVtexWriteError(err, `Failed to update tracking for order ${orderId}`);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import {
3
+ associateProductSpecification,
4
+ associateSkuSpecification
5
+ } from "../../services/vtex/vtex-catalog-write.js";
6
+ import {
7
+ buildWriteSuccessResponse,
8
+ handleVtexWriteError,
9
+ resolveVtexWriteProfile,
10
+ vtexProfileIdSchemaField
11
+ } from "./write-helpers.js";
12
+ const associateSpecificationSchema = z.object({
13
+ profileId: vtexProfileIdSchemaField,
14
+ entityType: z.enum(["product", "sku"]).describe("Whether the specification should be associated to a product or an SKU."),
15
+ resourceId: z.string().min(1).describe("Product ID or SKU ID depending on entityType."),
16
+ fieldId: z.number().int().positive().describe("Specification field ID."),
17
+ fieldValueId: z.number().int().positive().optional().describe("Specification value ID. Required for combo, radio, and checkbox fields."),
18
+ text: z.string().optional().describe("Raw text value. Use for free text specifications instead of fieldValueId.")
19
+ });
20
+ async function associateSpecificationHandler({
21
+ profileId,
22
+ entityType,
23
+ resourceId,
24
+ fieldId,
25
+ fieldValueId,
26
+ text
27
+ }) {
28
+ try {
29
+ const profileResolution = await resolveVtexWriteProfile(profileId);
30
+ if (!profileResolution.ok) {
31
+ return profileResolution.response;
32
+ }
33
+ const resolvedProfileId = profileResolution.value.profileId;
34
+ const payload = {
35
+ FieldId: fieldId
36
+ };
37
+ if (fieldValueId !== void 0) payload.FieldValueId = fieldValueId;
38
+ if (text !== void 0) payload.Text = text;
39
+ const association = entityType === "product" ? await associateProductSpecification(resolvedProfileId, resourceId, payload) : await associateSkuSpecification(resolvedProfileId, resourceId, payload);
40
+ return buildWriteSuccessResponse({
41
+ profileId: resolvedProfileId,
42
+ operation: "associate_specification",
43
+ resourceId,
44
+ riskLevel: "low",
45
+ message: "Specification associated successfully.",
46
+ before: null,
47
+ after: association,
48
+ details: {
49
+ entity_type: entityType
50
+ }
51
+ });
52
+ } catch (err) {
53
+ return handleVtexWriteError(err, `Failed to associate specification to ${entityType} ${resourceId}`);
54
+ }
55
+ }
56
+ export {
57
+ associateSpecificationHandler,
58
+ associateSpecificationSchema
59
+ };
60
+ //# sourceMappingURL=associate-specification.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/vtex/associate-specification.ts"],
4
+ "sourcesContent": ["import { z } from \"zod\";\n\nimport {\n associateProductSpecification,\n associateSkuSpecification,\n} from \"../../services/vtex/vtex-catalog-write.js\";\nimport {\n buildWriteSuccessResponse,\n handleVtexWriteError,\n resolveVtexWriteProfile,\n vtexProfileIdSchemaField,\n} from \"./write-helpers.js\";\n\nexport const associateSpecificationSchema = z.object({\n profileId: vtexProfileIdSchemaField,\n entityType: z.enum([\"product\", \"sku\"]).describe(\"Whether the specification should be associated to a product or an SKU.\"),\n resourceId: z.string().min(1).describe(\"Product ID or SKU ID depending on entityType.\"),\n fieldId: z.number().int().positive().describe(\"Specification field ID.\"),\n fieldValueId: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\"Specification value ID. Required for combo, radio, and checkbox fields.\"),\n text: z\n .string()\n .optional()\n .describe(\"Raw text value. Use for free text specifications instead of fieldValueId.\"),\n});\n\nexport async function associateSpecificationHandler({\n profileId,\n entityType,\n resourceId,\n fieldId,\n fieldValueId,\n text,\n}: z.infer<typeof associateSpecificationSchema>) {\n try {\n const profileResolution = await resolveVtexWriteProfile(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const payload: Record<string, unknown> = {\n FieldId: fieldId,\n };\n if (fieldValueId !== undefined) payload.FieldValueId = fieldValueId;\n if (text !== undefined) payload.Text = text;\n\n const association =\n entityType === \"product\"\n ? await associateProductSpecification(resolvedProfileId, resourceId, payload)\n : await associateSkuSpecification(resolvedProfileId, resourceId, payload);\n\n return buildWriteSuccessResponse({\n profileId: resolvedProfileId,\n operation: \"associate_specification\",\n resourceId,\n riskLevel: \"low\",\n message: \"Specification associated successfully.\",\n before: null,\n after: association,\n details: {\n entity_type: entityType,\n },\n });\n } catch (err) {\n return handleVtexWriteError(err, `Failed to associate specification to ${entityType} ${resourceId}`);\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,+BAA+B,EAAE,OAAO;AAAA,EACnD,WAAW;AAAA,EACX,YAAY,EAAE,KAAK,CAAC,WAAW,KAAK,CAAC,EAAE,SAAS,wEAAwE;AAAA,EACxH,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,+CAA+C;AAAA,EACtF,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,EACvE,cAAc,EACX,OAAO,EACP,IAAI,EACJ,SAAS,EACT,SAAS,EACT,SAAS,yEAAyE;AAAA,EACrF,MAAM,EACH,OAAO,EACP,SAAS,EACT,SAAS,2EAA2E;AACzF,CAAC;AAED,eAAsB,8BAA8B;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiD;AAC/C,MAAI;AACF,UAAM,oBAAoB,MAAM,wBAAwB,SAAS;AACjE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,UAAmC;AAAA,MACvC,SAAS;AAAA,IACX;AACA,QAAI,iBAAiB,OAAW,SAAQ,eAAe;AACvD,QAAI,SAAS,OAAW,SAAQ,OAAO;AAEvC,UAAM,cACJ,eAAe,YACX,MAAM,8BAA8B,mBAAmB,YAAY,OAAO,IAC1E,MAAM,0BAA0B,mBAAmB,YAAY,OAAO;AAE5E,WAAO,0BAA0B;AAAA,MAC/B,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,MACA,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,qBAAqB,KAAK,wCAAwC,UAAU,IAAI,UAAU,EAAE;AAAA,EACrG;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,63 @@
1
+ import { z } from "zod";
2
+ import { createSkuFile } from "../../services/vtex/vtex-catalog-write.js";
3
+ import {
4
+ buildWriteSuccessResponse,
5
+ handleVtexWriteError,
6
+ resolveVtexWriteProfile,
7
+ vtexProfileIdSchemaField
8
+ } from "./write-helpers.js";
9
+ const attachCatalogImageSchema = z.object({
10
+ profileId: vtexProfileIdSchemaField,
11
+ skuId: z.string().min(1).describe("SKU identifier that will receive the image."),
12
+ name: z.string().min(1).describe("Image name."),
13
+ url: z.string().url().describe("Public image URL. VTEX expects http(s) and a valid image extension."),
14
+ isMain: z.boolean().optional().describe("Whether this image should be the main image."),
15
+ label: z.string().optional().describe("Optional image label."),
16
+ text: z.string().optional().describe("Optional image text."),
17
+ position: z.number().int().nonnegative().optional().describe("Image position in storefront.")
18
+ });
19
+ async function attachCatalogImageHandler({
20
+ profileId,
21
+ skuId,
22
+ name,
23
+ url,
24
+ isMain,
25
+ label,
26
+ text,
27
+ position
28
+ }) {
29
+ try {
30
+ const profileResolution = await resolveVtexWriteProfile(profileId);
31
+ if (!profileResolution.ok) {
32
+ return profileResolution.response;
33
+ }
34
+ const resolvedProfileId = profileResolution.value.profileId;
35
+ const createdImage = await createSkuFile(resolvedProfileId, skuId, {
36
+ Name: name,
37
+ Url: url,
38
+ IsMain: isMain,
39
+ Label: label,
40
+ Text: text,
41
+ Position: position
42
+ });
43
+ return buildWriteSuccessResponse({
44
+ profileId: resolvedProfileId,
45
+ operation: "attach_catalog_image",
46
+ resourceId: skuId,
47
+ riskLevel: "low",
48
+ message: "Catalog image attached successfully.",
49
+ before: null,
50
+ after: createdImage,
51
+ details: {
52
+ sku_id: skuId
53
+ }
54
+ });
55
+ } catch (err) {
56
+ return handleVtexWriteError(err, `Failed to attach image to SKU ${skuId}`);
57
+ }
58
+ }
59
+ export {
60
+ attachCatalogImageHandler,
61
+ attachCatalogImageSchema
62
+ };
63
+ //# sourceMappingURL=attach-catalog-image.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/vtex/attach-catalog-image.ts"],
4
+ "sourcesContent": ["import { z } from \"zod\";\n\nimport { createSkuFile } from \"../../services/vtex/vtex-catalog-write.js\";\nimport {\n buildWriteSuccessResponse,\n handleVtexWriteError,\n resolveVtexWriteProfile,\n vtexProfileIdSchemaField,\n} from \"./write-helpers.js\";\n\nexport const attachCatalogImageSchema = z.object({\n profileId: vtexProfileIdSchemaField,\n skuId: z.string().min(1).describe(\"SKU identifier that will receive the image.\"),\n name: z.string().min(1).describe(\"Image name.\"),\n url: z\n .string()\n .url()\n .describe(\"Public image URL. VTEX expects http(s) and a valid image extension.\"),\n isMain: z.boolean().optional().describe(\"Whether this image should be the main image.\"),\n label: z.string().optional().describe(\"Optional image label.\"),\n text: z.string().optional().describe(\"Optional image text.\"),\n position: z.number().int().nonnegative().optional().describe(\"Image position in storefront.\"),\n});\n\nexport async function attachCatalogImageHandler({\n profileId,\n skuId,\n name,\n url,\n isMain,\n label,\n text,\n position,\n}: z.infer<typeof attachCatalogImageSchema>) {\n try {\n const profileResolution = await resolveVtexWriteProfile(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const createdImage = await createSkuFile(resolvedProfileId, skuId, {\n Name: name,\n Url: url,\n IsMain: isMain,\n Label: label,\n Text: text,\n Position: position,\n });\n\n return buildWriteSuccessResponse({\n profileId: resolvedProfileId,\n operation: \"attach_catalog_image\",\n resourceId: skuId,\n riskLevel: \"low\",\n message: \"Catalog image attached successfully.\",\n before: null,\n after: createdImage,\n details: {\n sku_id: skuId,\n },\n });\n } catch (err) {\n return handleVtexWriteError(err, `Failed to attach image to SKU ${skuId}`);\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAElB,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,WAAW;AAAA,EACX,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,6CAA6C;AAAA,EAC/E,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,aAAa;AAAA,EAC9C,KAAK,EACF,OAAO,EACP,IAAI,EACJ,SAAS,qEAAqE;AAAA,EACjF,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,8CAA8C;AAAA,EACtF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uBAAuB;AAAA,EAC7D,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,EAC3D,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,+BAA+B;AAC9F,CAAC;AAED,eAAsB,0BAA0B;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6C;AAC3C,MAAI;AACF,UAAM,oBAAoB,MAAM,wBAAwB,SAAS;AACjE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,eAAe,MAAM,cAAc,mBAAmB,OAAO;AAAA,MACjE,MAAM;AAAA,MACN,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC;AAED,WAAO,0BAA0B;AAAA,MAC/B,WAAW;AAAA,MACX,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,qBAAqB,KAAK,iCAAiC,KAAK,EAAE;AAAA,EAC3E;AACF;",
6
+ "names": []
7
+ }