@yoryoboy/bi-mcp 1.5.0 → 1.5.2

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 (86) hide show
  1. package/README.md +1 -2
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/mcp-use.json +2 -2
  4. package/dist/src/analytics/ga4-report-utils.js +20 -47
  5. package/dist/src/analytics/ga4-report-utils.js.map +2 -2
  6. package/dist/src/config/google-store.js +96 -0
  7. package/dist/src/config/google-store.js.map +7 -0
  8. package/dist/src/config/google.js +4 -15
  9. package/dist/src/config/google.js.map +2 -2
  10. package/dist/src/services/analytics/oauth.js +20 -7
  11. package/dist/src/services/analytics/oauth.js.map +2 -2
  12. package/dist/src/services/search-console/search-console-utils.js +49 -170
  13. package/dist/src/services/search-console/search-console-utils.js.map +2 -2
  14. package/dist/src/tools/analytics/attribution-gaps.js +3 -2
  15. package/dist/src/tools/analytics/attribution-gaps.js.map +2 -2
  16. package/dist/src/tools/analytics/channel-mix.js +3 -2
  17. package/dist/src/tools/analytics/channel-mix.js.map +2 -2
  18. package/dist/src/tools/analytics/ecommerce-tracking-health.js +3 -2
  19. package/dist/src/tools/analytics/ecommerce-tracking-health.js.map +2 -2
  20. package/dist/src/tools/analytics/engagement-overview.js +3 -2
  21. package/dist/src/tools/analytics/engagement-overview.js.map +2 -2
  22. package/dist/src/tools/analytics/property-info.js +3 -2
  23. package/dist/src/tools/analytics/property-info.js.map +2 -2
  24. package/dist/src/tools/analytics/revenue-by-channel.js +3 -2
  25. package/dist/src/tools/analytics/revenue-by-channel.js.map +2 -2
  26. package/dist/src/tools/analytics/revenue-overview.js +3 -2
  27. package/dist/src/tools/analytics/revenue-overview.js.map +2 -2
  28. package/dist/src/tools/analytics/revenue-trend.js +3 -2
  29. package/dist/src/tools/analytics/revenue-trend.js.map +2 -2
  30. package/dist/src/tools/analytics/source-medium-breakdown.js +3 -2
  31. package/dist/src/tools/analytics/source-medium-breakdown.js.map +2 -2
  32. package/dist/src/tools/analytics/top-landing-pages.js +3 -2
  33. package/dist/src/tools/analytics/top-landing-pages.js.map +2 -2
  34. package/dist/src/tools/config/list-profiles.js +23 -8
  35. package/dist/src/tools/config/list-profiles.js.map +2 -2
  36. package/dist/src/tools/google-ads/account-overview.js +3 -2
  37. package/dist/src/tools/google-ads/account-overview.js.map +2 -2
  38. package/dist/src/tools/google-ads/account-risks.js +3 -2
  39. package/dist/src/tools/google-ads/account-risks.js.map +2 -2
  40. package/dist/src/tools/google-ads/break-even-analysis.js +3 -2
  41. package/dist/src/tools/google-ads/break-even-analysis.js.map +2 -2
  42. package/dist/src/tools/google-ads/campaign-performance.js +3 -2
  43. package/dist/src/tools/google-ads/campaign-performance.js.map +2 -2
  44. package/dist/src/tools/google-ads/channel-mix.js +3 -2
  45. package/dist/src/tools/google-ads/channel-mix.js.map +2 -2
  46. package/dist/src/tools/google-ads/compare-accounts.js +1 -1
  47. package/dist/src/tools/google-ads/compare-accounts.js.map +2 -2
  48. package/dist/src/tools/google-ads/customer-clients.js +3 -2
  49. package/dist/src/tools/google-ads/customer-clients.js.map +2 -2
  50. package/dist/src/tools/google-ads/customer-info.js +3 -2
  51. package/dist/src/tools/google-ads/customer-info.js.map +2 -2
  52. package/dist/src/tools/google-ads/scaling-health.js +3 -2
  53. package/dist/src/tools/google-ads/scaling-health.js.map +2 -2
  54. package/dist/src/tools/google-ads/search-terms-summary.js +3 -2
  55. package/dist/src/tools/google-ads/search-terms-summary.js.map +2 -2
  56. package/dist/src/tools/google-ads/time-series.js +3 -2
  57. package/dist/src/tools/google-ads/time-series.js.map +2 -2
  58. package/dist/src/tools/search-console/country-breakdown.js +1 -1
  59. package/dist/src/tools/search-console/country-breakdown.js.map +2 -2
  60. package/dist/src/tools/search-console/device-breakdown.js +1 -1
  61. package/dist/src/tools/search-console/device-breakdown.js.map +2 -2
  62. package/dist/src/tools/search-console/high-impression-low-click-queries.js +1 -1
  63. package/dist/src/tools/search-console/high-impression-low-click-queries.js.map +2 -2
  64. package/dist/src/tools/search-console/low-ctr-opportunities.js +1 -1
  65. package/dist/src/tools/search-console/low-ctr-opportunities.js.map +2 -2
  66. package/dist/src/tools/search-console/page-performance.js +1 -1
  67. package/dist/src/tools/search-console/page-performance.js.map +2 -2
  68. package/dist/src/tools/search-console/product-demand-low-capture-queries.js +1 -1
  69. package/dist/src/tools/search-console/product-demand-low-capture-queries.js.map +2 -2
  70. package/dist/src/tools/search-console/query-page-matrix.js +1 -1
  71. package/dist/src/tools/search-console/query-page-matrix.js.map +2 -2
  72. package/dist/src/tools/search-console/query-performance.js +1 -1
  73. package/dist/src/tools/search-console/query-performance.js.map +2 -2
  74. package/dist/src/tools/search-console/quick-win-opportunities.js +1 -1
  75. package/dist/src/tools/search-console/quick-win-opportunities.js.map +2 -2
  76. package/dist/src/tools/search-console/rising-non-brand-queries.js +1 -1
  77. package/dist/src/tools/search-console/rising-non-brand-queries.js.map +2 -2
  78. package/dist/src/tools/search-console/search-performance.js +1 -1
  79. package/dist/src/tools/search-console/search-performance.js.map +2 -2
  80. package/dist/src/tools/search-console/site-context.js +2 -2
  81. package/dist/src/tools/search-console/site-context.js.map +2 -2
  82. package/dist/src/tools/search-console/visibility-declines.js +1 -1
  83. package/dist/src/tools/search-console/visibility-declines.js.map +2 -2
  84. package/dist/src/utils/google-ads.js +15 -26
  85. package/dist/src/utils/google-ads.js.map +2 -2
  86. package/package.json +1 -1
@@ -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 \"../../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
- "mappings": "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",
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 = await 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
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,35 +1,30 @@
1
- import {
2
- getDefaultGoogleAdsLoginCustomerId,
3
- getGoogleAdsDeveloperToken
4
- } from "../config/google.js";
1
+ import { getDefaultGoogleAdsLoginCustomerId, getGoogleAdsDeveloperToken } from "../config/google.js";
2
+ import { getProfileGoogleServiceMapping } from "../config/google-store.js";
5
3
  const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
6
4
  function normalizeCustomerId(customerId) {
7
5
  const normalized = customerId.trim().replace(/-/g, "");
8
- if (!/^\d+$/.test(normalized)) {
9
- throw new Error("Invalid Google Ads customer ID. Use digits only, with or without hyphens.");
10
- }
6
+ if (!/^\d+$/.test(normalized)) throw new Error("Invalid Google Ads customer ID. Use digits only, with or without hyphens.");
11
7
  return normalized;
12
8
  }
13
- function resolveGoogleAdsCustomerId(customerId) {
14
- if (!customerId?.trim()) {
15
- throw new Error("Missing Google Ads customer ID. Provide customerId.");
9
+ async function resolveGoogleAdsCustomerId(customerId, profileId) {
10
+ if (customerId?.trim()) return normalizeCustomerId(customerId);
11
+ if (profileId?.trim()) {
12
+ const mapping = await getProfileGoogleServiceMapping(profileId.trim());
13
+ if (mapping?.googleAdsCustomerId) return normalizeCustomerId(mapping.googleAdsCustomerId);
14
+ throw new Error(`Missing Google Ads customer ID. profileId "${profileId.trim()}" has no Google Ads mapping configured.`);
16
15
  }
17
- return normalizeCustomerId(customerId);
16
+ throw new Error("Missing Google Ads customer ID. Provide customerId explicitly or pass profileId with a configured mapping.");
18
17
  }
19
18
  function resolveGoogleAdsLoginCustomerId(loginCustomerId) {
20
19
  const explicitCustomerId = loginCustomerId?.trim();
21
- if (explicitCustomerId) {
22
- return normalizeCustomerId(explicitCustomerId);
23
- }
20
+ if (explicitCustomerId) return normalizeCustomerId(explicitCustomerId);
24
21
  return getDefaultGoogleAdsLoginCustomerId();
25
22
  }
26
23
  function resolveGoogleAdsDeveloperToken() {
27
24
  return getGoogleAdsDeveloperToken();
28
25
  }
29
26
  function parseGoogleAdsMetricValue(value) {
30
- if (typeof value === "number" && Number.isFinite(value)) {
31
- return value;
32
- }
27
+ if (typeof value === "number" && Number.isFinite(value)) return value;
33
28
  if (typeof value === "string") {
34
29
  const parsedValue = Number(value);
35
30
  return Number.isFinite(parsedValue) ? parsedValue : 0;
@@ -40,25 +35,19 @@ function microsToCurrency(value, decimals = 2) {
40
35
  return round(parseGoogleAdsMetricValue(value) / 1e6, decimals);
41
36
  }
42
37
  function round(value, decimals = 2) {
43
- if (!Number.isFinite(value)) {
44
- return 0;
45
- }
38
+ if (!Number.isFinite(value)) return 0;
46
39
  const factor = 10 ** decimals;
47
40
  return Math.round(value * factor) / factor;
48
41
  }
49
42
  function toPercent(numerator, denominator) {
50
- if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
51
- return 0;
52
- }
43
+ if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0;
53
44
  return numerator / denominator * 100;
54
45
  }
55
46
  function getFieldValue(row, path, fallback) {
56
47
  const segments = path.split(".");
57
48
  let current = row;
58
49
  for (const segment of segments) {
59
- if (!current || typeof current !== "object") {
60
- return fallback;
61
- }
50
+ if (!current || typeof current !== "object") return fallback;
62
51
  current = current[segment];
63
52
  }
64
53
  return current ?? fallback;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/google-ads.ts"],
4
- "sourcesContent": ["import {\n getDefaultGoogleAdsLoginCustomerId,\n getGoogleAdsDeveloperToken,\n} from \"../config/google.js\";\nimport type { GoogleAdsMetricValue, GoogleAdsSearchRow } from \"../services/google-ads/google-ads-client.js\";\n\nexport const dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport function normalizeCustomerId(customerId: string): string {\n const normalized = customerId.trim().replace(/-/g, \"\");\n if (!/^\\d+$/.test(normalized)) {\n throw new Error(\"Invalid Google Ads customer ID. Use digits only, with or without hyphens.\");\n }\n\n return normalized;\n}\n\nexport function resolveGoogleAdsCustomerId(customerId?: string): string {\n if (!customerId?.trim()) {\n throw new Error(\"Missing Google Ads customer ID. Provide customerId.\");\n }\n\n return normalizeCustomerId(customerId);\n}\n\nexport function resolveGoogleAdsLoginCustomerId(loginCustomerId?: string): string | undefined {\n const explicitCustomerId = loginCustomerId?.trim();\n if (explicitCustomerId) {\n return normalizeCustomerId(explicitCustomerId);\n }\n\n return getDefaultGoogleAdsLoginCustomerId();\n}\n\nexport function resolveGoogleAdsDeveloperToken(): string {\n return getGoogleAdsDeveloperToken();\n}\n\nexport function parseGoogleAdsMetricValue(value: GoogleAdsMetricValue | undefined): number {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n\n if (typeof value === \"string\") {\n const parsedValue = Number(value);\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n }\n\n return 0;\n}\n\nexport function microsToCurrency(value: GoogleAdsMetricValue | undefined, decimals = 2): number {\n return round(parseGoogleAdsMetricValue(value) / 1_000_000, decimals);\n}\n\nexport function round(value: number, decimals = 2): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\nexport function toPercent(numerator: number, denominator: number): number {\n if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {\n return 0;\n }\n\n return (numerator / denominator) * 100;\n}\n\nexport function getFieldValue<T>(row: GoogleAdsSearchRow, path: string, fallback?: T): T | undefined {\n const segments = path.split(\".\");\n let current: unknown = row;\n\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") {\n return fallback;\n }\n\n current = (current as Record<string, unknown>)[segment];\n }\n\n return (current as T | undefined) ?? fallback;\n}\n"],
5
- "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAGA,MAAM,YAAY;AAElB,SAAS,oBAAoB,YAA4B;AAC9D,QAAM,aAAa,WAAW,KAAK,EAAE,QAAQ,MAAM,EAAE;AACrD,MAAI,CAAC,QAAQ,KAAK,UAAU,GAAG;AAC7B,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC7F;AAEA,SAAO;AACT;AAEO,SAAS,2BAA2B,YAA6B;AACtE,MAAI,CAAC,YAAY,KAAK,GAAG;AACvB,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,SAAO,oBAAoB,UAAU;AACvC;AAEO,SAAS,gCAAgC,iBAA8C;AAC5F,QAAM,qBAAqB,iBAAiB,KAAK;AACjD,MAAI,oBAAoB;AACtB,WAAO,oBAAoB,kBAAkB;AAAA,EAC/C;AAEA,SAAO,mCAAmC;AAC5C;AAEO,SAAS,iCAAyC;AACvD,SAAO,2BAA2B;AACpC;AAEO,SAAS,0BAA0B,OAAiD;AACzF,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AACvD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,cAAc,OAAO,KAAK;AAChC,WAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AAAA,EACtD;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,OAAyC,WAAW,GAAW;AAC9F,SAAO,MAAM,0BAA0B,KAAK,IAAI,KAAW,QAAQ;AACrE;AAEO,SAAS,MAAM,OAAe,WAAW,GAAW;AACzD,MAAI,CAAC,OAAO,SAAS,KAAK,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,MAAM;AACrB,SAAO,KAAK,MAAM,QAAQ,MAAM,IAAI;AACtC;AAEO,SAAS,UAAU,WAAmB,aAA6B;AACxE,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,CAAC,OAAO,SAAS,WAAW,KAAK,eAAe,GAAG;AACpF,WAAO;AAAA,EACT;AAEA,SAAQ,YAAY,cAAe;AACrC;AAEO,SAAS,cAAiB,KAAyB,MAAc,UAA6B;AACnG,QAAM,WAAW,KAAK,MAAM,GAAG;AAC/B,MAAI,UAAmB;AAEvB,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,aAAO;AAAA,IACT;AAEA,cAAW,QAAoC,OAAO;AAAA,EACxD;AAEA,SAAQ,WAA6B;AACvC;",
4
+ "sourcesContent": ["import { getDefaultGoogleAdsLoginCustomerId, getGoogleAdsDeveloperToken } from '../config/google.js';\nimport { getProfileGoogleServiceMapping } from '../config/google-store.js';\nimport type { GoogleAdsMetricValue, GoogleAdsSearchRow } from '../services/google-ads/google-ads-client.js';\n\nexport const dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport function normalizeCustomerId(customerId: string): string { const normalized = customerId.trim().replace(/-/g, ''); if (!/^\\d+$/.test(normalized)) throw new Error('Invalid Google Ads customer ID. Use digits only, with or without hyphens.'); return normalized; }\nexport async function resolveGoogleAdsCustomerId(customerId?: string, profileId?: string): Promise<string> { if (customerId?.trim()) return normalizeCustomerId(customerId); if (profileId?.trim()) { const mapping = await getProfileGoogleServiceMapping(profileId.trim()); if (mapping?.googleAdsCustomerId) return normalizeCustomerId(mapping.googleAdsCustomerId); throw new Error(`Missing Google Ads customer ID. profileId \"${profileId.trim()}\" has no Google Ads mapping configured.`); } throw new Error('Missing Google Ads customer ID. Provide customerId explicitly or pass profileId with a configured mapping.'); }\nexport function resolveGoogleAdsLoginCustomerId(loginCustomerId?: string): string | undefined { const explicitCustomerId = loginCustomerId?.trim(); if (explicitCustomerId) return normalizeCustomerId(explicitCustomerId); return getDefaultGoogleAdsLoginCustomerId(); }\nexport function resolveGoogleAdsDeveloperToken(): string { return getGoogleAdsDeveloperToken(); }\nexport function parseGoogleAdsMetricValue(value: GoogleAdsMetricValue | undefined): number { if (typeof value === 'number' && Number.isFinite(value)) return value; if (typeof value === 'string') { const parsedValue = Number(value); return Number.isFinite(parsedValue) ? parsedValue : 0; } return 0; }\nexport function microsToCurrency(value: GoogleAdsMetricValue | undefined, decimals = 2): number { return round(parseGoogleAdsMetricValue(value) / 1_000_000, decimals); }\nexport function round(value: number, decimals = 2): number { if (!Number.isFinite(value)) return 0; const factor = 10 ** decimals; return Math.round(value * factor) / factor; }\nexport function toPercent(numerator: number, denominator: number): number { if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0; return (numerator / denominator) * 100; }\nexport function getFieldValue<T>(row: GoogleAdsSearchRow, path: string, fallback?: T): T | undefined { const segments = path.split('.'); let current: unknown = row; for (const segment of segments) { if (!current || typeof current !== 'object') return fallback; current = (current as Record<string, unknown>)[segment]; } return (current as T | undefined) ?? fallback; }\n"],
5
+ "mappings": "AAAA,SAAS,oCAAoC,kCAAkC;AAC/E,SAAS,sCAAsC;AAGxC,MAAM,YAAY;AAElB,SAAS,oBAAoB,YAA4B;AAAE,QAAM,aAAa,WAAW,KAAK,EAAE,QAAQ,MAAM,EAAE;AAAG,MAAI,CAAC,QAAQ,KAAK,UAAU,EAAG,OAAM,IAAI,MAAM,2EAA2E;AAAG,SAAO;AAAY;AAC1Q,eAAsB,2BAA2B,YAAqB,WAAqC;AAAE,MAAI,YAAY,KAAK,EAAG,QAAO,oBAAoB,UAAU;AAAG,MAAI,WAAW,KAAK,GAAG;AAAE,UAAM,UAAU,MAAM,+BAA+B,UAAU,KAAK,CAAC;AAAG,QAAI,SAAS,oBAAqB,QAAO,oBAAoB,QAAQ,mBAAmB;AAAG,UAAM,IAAI,MAAM,8CAA8C,UAAU,KAAK,CAAC,yCAAyC;AAAA,EAAG;AAAE,QAAM,IAAI,MAAM,4GAA4G;AAAG;AAC7lB,SAAS,gCAAgC,iBAA8C;AAAE,QAAM,qBAAqB,iBAAiB,KAAK;AAAG,MAAI,mBAAoB,QAAO,oBAAoB,kBAAkB;AAAG,SAAO,mCAAmC;AAAG;AAClQ,SAAS,iCAAyC;AAAE,SAAO,2BAA2B;AAAG;AACzF,SAAS,0BAA0B,OAAiD;AAAE,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAAO,MAAI,OAAO,UAAU,UAAU;AAAE,UAAM,cAAc,OAAO,KAAK;AAAG,WAAO,OAAO,SAAS,WAAW,IAAI,cAAc;AAAA,EAAG;AAAE,SAAO;AAAG;AACpS,SAAS,iBAAiB,OAAyC,WAAW,GAAW;AAAE,SAAO,MAAM,0BAA0B,KAAK,IAAI,KAAW,QAAQ;AAAG;AACjK,SAAS,MAAM,OAAe,WAAW,GAAW;AAAE,MAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AAAG,QAAM,SAAS,MAAM;AAAU,SAAO,KAAK,MAAM,QAAQ,MAAM,IAAI;AAAQ;AACxK,SAAS,UAAU,WAAmB,aAA6B;AAAE,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,CAAC,OAAO,SAAS,WAAW,KAAK,eAAe,EAAG,QAAO;AAAG,SAAQ,YAAY,cAAe;AAAK;AAC7M,SAAS,cAAiB,KAAyB,MAAc,UAA6B;AAAE,QAAM,WAAW,KAAK,MAAM,GAAG;AAAG,MAAI,UAAmB;AAAK,aAAW,WAAW,UAAU;AAAE,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AAAU,cAAW,QAAoC,OAAO;AAAA,EAAG;AAAE,SAAQ,WAA6B;AAAU;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yoryoboy/bi-mcp",
3
3
  "type": "module",
4
- "version": "1.5.0",
4
+ "version": "1.5.2",
5
5
  "description": "MCP server: bi-mcp",
6
6
  "author": "",
7
7
  "license": "MIT",