@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.
- package/README.md +1 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/mcp-use.json +2 -2
- package/dist/src/analytics/ga4-report-utils.js +20 -47
- package/dist/src/analytics/ga4-report-utils.js.map +2 -2
- package/dist/src/config/google-store.js +96 -0
- package/dist/src/config/google-store.js.map +7 -0
- package/dist/src/config/google.js +4 -15
- package/dist/src/config/google.js.map +2 -2
- package/dist/src/services/analytics/oauth.js +20 -7
- package/dist/src/services/analytics/oauth.js.map +2 -2
- package/dist/src/services/search-console/search-console-utils.js +49 -170
- package/dist/src/services/search-console/search-console-utils.js.map +2 -2
- package/dist/src/tools/analytics/attribution-gaps.js +3 -2
- package/dist/src/tools/analytics/attribution-gaps.js.map +2 -2
- package/dist/src/tools/analytics/channel-mix.js +3 -2
- package/dist/src/tools/analytics/channel-mix.js.map +2 -2
- package/dist/src/tools/analytics/ecommerce-tracking-health.js +3 -2
- package/dist/src/tools/analytics/ecommerce-tracking-health.js.map +2 -2
- package/dist/src/tools/analytics/engagement-overview.js +3 -2
- package/dist/src/tools/analytics/engagement-overview.js.map +2 -2
- package/dist/src/tools/analytics/property-info.js +3 -2
- package/dist/src/tools/analytics/property-info.js.map +2 -2
- package/dist/src/tools/analytics/revenue-by-channel.js +3 -2
- package/dist/src/tools/analytics/revenue-by-channel.js.map +2 -2
- package/dist/src/tools/analytics/revenue-overview.js +3 -2
- package/dist/src/tools/analytics/revenue-overview.js.map +2 -2
- package/dist/src/tools/analytics/revenue-trend.js +3 -2
- package/dist/src/tools/analytics/revenue-trend.js.map +2 -2
- package/dist/src/tools/analytics/source-medium-breakdown.js +3 -2
- package/dist/src/tools/analytics/source-medium-breakdown.js.map +2 -2
- package/dist/src/tools/analytics/top-landing-pages.js +3 -2
- package/dist/src/tools/analytics/top-landing-pages.js.map +2 -2
- package/dist/src/tools/config/list-profiles.js +23 -8
- package/dist/src/tools/config/list-profiles.js.map +2 -2
- package/dist/src/tools/google-ads/account-overview.js +3 -2
- package/dist/src/tools/google-ads/account-overview.js.map +2 -2
- package/dist/src/tools/google-ads/account-risks.js +3 -2
- package/dist/src/tools/google-ads/account-risks.js.map +2 -2
- package/dist/src/tools/google-ads/break-even-analysis.js +3 -2
- package/dist/src/tools/google-ads/break-even-analysis.js.map +2 -2
- package/dist/src/tools/google-ads/campaign-performance.js +3 -2
- package/dist/src/tools/google-ads/campaign-performance.js.map +2 -2
- package/dist/src/tools/google-ads/channel-mix.js +3 -2
- package/dist/src/tools/google-ads/channel-mix.js.map +2 -2
- package/dist/src/tools/google-ads/compare-accounts.js +1 -1
- package/dist/src/tools/google-ads/compare-accounts.js.map +2 -2
- package/dist/src/tools/google-ads/customer-clients.js +3 -2
- package/dist/src/tools/google-ads/customer-clients.js.map +2 -2
- package/dist/src/tools/google-ads/customer-info.js +3 -2
- package/dist/src/tools/google-ads/customer-info.js.map +2 -2
- package/dist/src/tools/google-ads/scaling-health.js +3 -2
- package/dist/src/tools/google-ads/scaling-health.js.map +2 -2
- package/dist/src/tools/google-ads/search-terms-summary.js +3 -2
- package/dist/src/tools/google-ads/search-terms-summary.js.map +2 -2
- package/dist/src/tools/google-ads/time-series.js +3 -2
- package/dist/src/tools/google-ads/time-series.js.map +2 -2
- package/dist/src/tools/search-console/country-breakdown.js +1 -1
- package/dist/src/tools/search-console/country-breakdown.js.map +2 -2
- package/dist/src/tools/search-console/device-breakdown.js +1 -1
- package/dist/src/tools/search-console/device-breakdown.js.map +2 -2
- package/dist/src/tools/search-console/high-impression-low-click-queries.js +1 -1
- package/dist/src/tools/search-console/high-impression-low-click-queries.js.map +2 -2
- package/dist/src/tools/search-console/low-ctr-opportunities.js +1 -1
- package/dist/src/tools/search-console/low-ctr-opportunities.js.map +2 -2
- package/dist/src/tools/search-console/page-performance.js +1 -1
- package/dist/src/tools/search-console/page-performance.js.map +2 -2
- package/dist/src/tools/search-console/product-demand-low-capture-queries.js +1 -1
- package/dist/src/tools/search-console/product-demand-low-capture-queries.js.map +2 -2
- package/dist/src/tools/search-console/query-page-matrix.js +1 -1
- package/dist/src/tools/search-console/query-page-matrix.js.map +2 -2
- package/dist/src/tools/search-console/query-performance.js +1 -1
- package/dist/src/tools/search-console/query-performance.js.map +2 -2
- package/dist/src/tools/search-console/quick-win-opportunities.js +1 -1
- package/dist/src/tools/search-console/quick-win-opportunities.js.map +2 -2
- package/dist/src/tools/search-console/rising-non-brand-queries.js +1 -1
- package/dist/src/tools/search-console/rising-non-brand-queries.js.map +2 -2
- package/dist/src/tools/search-console/search-performance.js +1 -1
- package/dist/src/tools/search-console/search-performance.js.map +2 -2
- package/dist/src/tools/search-console/site-context.js +2 -2
- package/dist/src/tools/search-console/site-context.js.map +2 -2
- package/dist/src/tools/search-console/visibility-declines.js +1 -1
- package/dist/src/tools/search-console/visibility-declines.js.map +2 -2
- package/dist/src/utils/google-ads.js +15 -26
- package/dist/src/utils/google-ads.js.map +2 -2
- package/package.json +1 -1
package/dist/mcp-use.json
CHANGED
|
@@ -1,76 +1,58 @@
|
|
|
1
1
|
import { getDefaultGa4PropertyId } from "../config/google.js";
|
|
2
|
-
|
|
2
|
+
import { getProfileGoogleServiceMapping } from "../config/google-store.js";
|
|
3
|
+
async function resolveGa4PropertyId(propertyId, profileId) {
|
|
3
4
|
const explicitPropertyId = propertyId?.trim();
|
|
4
|
-
if (explicitPropertyId)
|
|
5
|
-
|
|
5
|
+
if (explicitPropertyId) return explicitPropertyId;
|
|
6
|
+
const explicitProfileId = profileId?.trim();
|
|
7
|
+
if (explicitProfileId) {
|
|
8
|
+
const mapping = await getProfileGoogleServiceMapping(explicitProfileId);
|
|
9
|
+
if (mapping?.ga4PropertyId) return mapping.ga4PropertyId;
|
|
6
10
|
}
|
|
7
11
|
const defaultPropertyId = getDefaultGa4PropertyId();
|
|
8
|
-
if (defaultPropertyId)
|
|
9
|
-
return defaultPropertyId;
|
|
10
|
-
}
|
|
12
|
+
if (defaultPropertyId) return defaultPropertyId;
|
|
11
13
|
throw new Error(
|
|
12
|
-
"Missing GA4 property ID. Provide propertyId,
|
|
14
|
+
explicitProfileId ? `Missing GA4 property ID. profileId "${explicitProfileId}" has no active GA4 mapping, and GA4_PROPERTY_ID is not configured.` : "Missing GA4 property ID. Provide propertyId, pass profileId with a configured mapping, or configure GA4_PROPERTY_ID."
|
|
13
15
|
);
|
|
14
16
|
}
|
|
15
17
|
function parseMetricValue(value) {
|
|
16
|
-
if (!value)
|
|
17
|
-
return 0;
|
|
18
|
-
}
|
|
18
|
+
if (!value) return 0;
|
|
19
19
|
const parsedValue = Number(value);
|
|
20
20
|
return Number.isFinite(parsedValue) ? parsedValue : 0;
|
|
21
21
|
}
|
|
22
22
|
function getMetricValueByName(row, metricHeaders, metricName) {
|
|
23
23
|
const metricIndex = metricHeaders?.findIndex((metric) => metric.name === metricName) ?? -1;
|
|
24
|
-
if (metricIndex < 0)
|
|
25
|
-
return 0;
|
|
26
|
-
}
|
|
24
|
+
if (metricIndex < 0) return 0;
|
|
27
25
|
return parseMetricValue(row.metricValues?.[metricIndex]?.value);
|
|
28
26
|
}
|
|
29
27
|
function getDimensionValue(row, index = 0) {
|
|
30
28
|
return row.dimensionValues?.[index]?.value ?? "";
|
|
31
29
|
}
|
|
32
30
|
function toPercent(numerator, denominator) {
|
|
33
|
-
if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0)
|
|
34
|
-
return 0;
|
|
35
|
-
}
|
|
31
|
+
if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0;
|
|
36
32
|
return numerator / denominator * 100;
|
|
37
33
|
}
|
|
38
34
|
function round(value, decimals = 2) {
|
|
39
|
-
if (!Number.isFinite(value))
|
|
40
|
-
return 0;
|
|
41
|
-
}
|
|
35
|
+
if (!Number.isFinite(value)) return 0;
|
|
42
36
|
const factor = 10 ** decimals;
|
|
43
37
|
return Math.round(value * factor) / factor;
|
|
44
38
|
}
|
|
45
39
|
function formatGa4Date(value) {
|
|
46
|
-
if (!/^\d{8}$/.test(value))
|
|
47
|
-
return value;
|
|
48
|
-
}
|
|
40
|
+
if (!/^\d{8}$/.test(value)) return value;
|
|
49
41
|
return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`;
|
|
50
42
|
}
|
|
51
43
|
function findPropertySummary(accountSummaries, propertyId) {
|
|
52
44
|
for (const account of accountSummaries) {
|
|
53
45
|
for (const property of account.propertySummaries ?? []) {
|
|
54
46
|
if (property.property === `properties/${propertyId}`) {
|
|
55
|
-
return {
|
|
56
|
-
accountId: account.account.replace("accounts/", ""),
|
|
57
|
-
accountName: account.displayName,
|
|
58
|
-
propertyId,
|
|
59
|
-
propertyName: property.displayName,
|
|
60
|
-
propertyType: property.propertyType
|
|
61
|
-
};
|
|
47
|
+
return { accountId: account.account.replace("accounts/", ""), accountName: account.displayName, propertyId, propertyName: property.displayName, propertyType: property.propertyType };
|
|
62
48
|
}
|
|
63
49
|
}
|
|
64
50
|
}
|
|
65
51
|
return void 0;
|
|
66
52
|
}
|
|
67
53
|
function detectSeverity(sharePercent) {
|
|
68
|
-
if (sharePercent >= 10)
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
if (sharePercent >= 3) {
|
|
72
|
-
return "medium";
|
|
73
|
-
}
|
|
54
|
+
if (sharePercent >= 10) return "high";
|
|
55
|
+
if (sharePercent >= 3) return "medium";
|
|
74
56
|
return "low";
|
|
75
57
|
}
|
|
76
58
|
function isProblematicAttributionValue(value) {
|
|
@@ -78,21 +60,12 @@ function isProblematicAttributionValue(value) {
|
|
|
78
60
|
return normalizedValue.includes("(not set)") || normalizedValue.includes("(data not available)") || normalizedValue.includes("unassigned");
|
|
79
61
|
}
|
|
80
62
|
function sumMetricValues(rows, metricHeaders, metricName) {
|
|
81
|
-
return (rows ?? []).reduce((total, row) =>
|
|
82
|
-
return total + getMetricValueByName(row, metricHeaders, metricName);
|
|
83
|
-
}, 0);
|
|
63
|
+
return (rows ?? []).reduce((total, row) => total + getMetricValueByName(row, metricHeaders, metricName), 0);
|
|
84
64
|
}
|
|
85
65
|
function extractQuotaSnapshot(report) {
|
|
86
66
|
const quota = report.propertyQuota;
|
|
87
|
-
if (!quota)
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
return {
|
|
91
|
-
tokens_per_day_remaining: quota.tokensPerDay?.remaining ?? 0,
|
|
92
|
-
tokens_per_hour_remaining: quota.tokensPerHour?.remaining ?? 0,
|
|
93
|
-
concurrent_requests_remaining: quota.concurrentRequests?.remaining ?? 0,
|
|
94
|
-
tokens_per_project_per_hour_remaining: quota.tokensPerProjectPerHour?.remaining ?? 0
|
|
95
|
-
};
|
|
67
|
+
if (!quota) return void 0;
|
|
68
|
+
return { tokens_per_day_remaining: quota.tokensPerDay?.remaining ?? 0, tokens_per_hour_remaining: quota.tokensPerHour?.remaining ?? 0, concurrent_requests_remaining: quota.concurrentRequests?.remaining ?? 0, tokens_per_project_per_hour_remaining: quota.tokensPerProjectPerHour?.remaining ?? 0 };
|
|
96
69
|
}
|
|
97
70
|
function findMetricHeader(metricHeaders, metricName) {
|
|
98
71
|
return metricHeaders?.find((metric) => metric.name === metricName);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/analytics/ga4-report-utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { getDefaultGa4PropertyId } from
|
|
5
|
-
"mappings": "AAAA,SAAS,+BAA+B;
|
|
4
|
+
"sourcesContent": ["import { getDefaultGa4PropertyId } from '../config/google.js';\nimport { getProfileGoogleServiceMapping } from '../config/google-store.js';\nimport type { Ga4AccountSummary, Ga4MetricHeader, Ga4MetricValue, Ga4ReportResponse, Ga4ReportRow } from '../services/analytics/ga4-client.js';\n\nexport async function resolveGa4PropertyId(propertyId?: string, profileId?: string): Promise<string> {\n const explicitPropertyId = propertyId?.trim();\n if (explicitPropertyId) return explicitPropertyId;\n\n const explicitProfileId = profileId?.trim();\n if (explicitProfileId) {\n const mapping = await getProfileGoogleServiceMapping(explicitProfileId);\n if (mapping?.ga4PropertyId) return mapping.ga4PropertyId;\n }\n\n const defaultPropertyId = getDefaultGa4PropertyId();\n if (defaultPropertyId) return defaultPropertyId;\n\n throw new Error(\n explicitProfileId\n ? `Missing GA4 property ID. profileId \"${explicitProfileId}\" has no active GA4 mapping, and GA4_PROPERTY_ID is not configured.`\n : 'Missing GA4 property ID. Provide propertyId, pass profileId with a configured mapping, or configure GA4_PROPERTY_ID.'\n );\n}\n\nexport function parseMetricValue(value: string | undefined): number { if (!value) return 0; const parsedValue = Number(value); return Number.isFinite(parsedValue) ? parsedValue : 0; }\nexport function getMetricValueByName(row: Ga4ReportRow, metricHeaders: Ga4MetricHeader[] | undefined, metricName: string): number { const metricIndex = metricHeaders?.findIndex((metric) => metric.name === metricName) ?? -1; if (metricIndex < 0) return 0; return parseMetricValue(row.metricValues?.[metricIndex]?.value); }\nexport function getDimensionValue(row: Ga4ReportRow, index = 0): string { return row.dimensionValues?.[index]?.value ?? ''; }\nexport function toPercent(numerator: number, denominator: number): number { if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) return 0; return (numerator / denominator) * 100; }\nexport function round(value: number, decimals = 2): number { if (!Number.isFinite(value)) return 0; const factor = 10 ** decimals; return Math.round(value * factor) / factor; }\nexport function formatGa4Date(value: string): string { if (!/^\\d{8}$/.test(value)) return value; return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`; }\nexport function findPropertySummary(accountSummaries: Ga4AccountSummary[], propertyId: string) { for (const account of accountSummaries) { for (const property of account.propertySummaries ?? []) { if (property.property === `properties/${propertyId}`) { return { accountId: account.account.replace('accounts/', ''), accountName: account.displayName, propertyId, propertyName: property.displayName, propertyType: property.propertyType }; } } } return undefined; }\nexport function detectSeverity(sharePercent: number): 'low' | 'medium' | 'high' { if (sharePercent >= 10) return 'high'; if (sharePercent >= 3) return 'medium'; return 'low'; }\nexport function isProblematicAttributionValue(value: string): boolean { const normalizedValue = value.toLowerCase(); return normalizedValue.includes('(not set)') || normalizedValue.includes('(data not available)') || normalizedValue.includes('unassigned'); }\nexport function sumMetricValues(rows: Ga4ReportRow[] | undefined, metricHeaders: Ga4MetricHeader[] | undefined, metricName: string): number { return (rows ?? []).reduce((total, row) => total + getMetricValueByName(row, metricHeaders, metricName), 0); }\nexport function extractQuotaSnapshot(report: Ga4ReportResponse): Record<string, number> | undefined { const quota = report.propertyQuota; if (!quota) return undefined; return { tokens_per_day_remaining: quota.tokensPerDay?.remaining ?? 0, tokens_per_hour_remaining: quota.tokensPerHour?.remaining ?? 0, concurrent_requests_remaining: quota.concurrentRequests?.remaining ?? 0, tokens_per_project_per_hour_remaining: quota.tokensPerProjectPerHour?.remaining ?? 0 }; }\nexport function findMetricHeader(metricHeaders: Ga4MetricHeader[] | undefined, metricName: string): Ga4MetricHeader | undefined { return metricHeaders?.find((metric) => metric.name === metricName); }\nexport function getFirstMetricValue(metricValues: Ga4MetricValue[] | undefined, index: number): number { return parseMetricValue(metricValues?.[index]?.value); }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { getDb } from "../db/client.js";
|
|
2
|
+
import { decryptSecret } from "./vtex-crypto.js";
|
|
3
|
+
function isMissingRelationError(error) {
|
|
4
|
+
return error instanceof Error && /does not exist/i.test(error.message);
|
|
5
|
+
}
|
|
6
|
+
function mapConnection(row) {
|
|
7
|
+
return {
|
|
8
|
+
id: row.id,
|
|
9
|
+
encryptedRefreshToken: row.encrypted_refresh_token,
|
|
10
|
+
scopes: Array.isArray(row.scopes) ? row.scopes : [],
|
|
11
|
+
status: row.status,
|
|
12
|
+
googleAccountEmail: row.google_account_email,
|
|
13
|
+
lastValidatedAt: row.last_validated_at,
|
|
14
|
+
lastError: row.last_error
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function mapMapping(row) {
|
|
18
|
+
return {
|
|
19
|
+
profileId: row.profile_id,
|
|
20
|
+
googleAdsCustomerId: row.google_ads_customer_id,
|
|
21
|
+
googleAdsLabel: row.google_ads_label,
|
|
22
|
+
googleAdsStatus: row.google_ads_status,
|
|
23
|
+
googleAdsLastValidatedAt: row.google_ads_last_validated_at,
|
|
24
|
+
googleAdsLastError: row.google_ads_last_error,
|
|
25
|
+
ga4PropertyId: row.ga4_property_id,
|
|
26
|
+
ga4PropertyLabel: row.ga4_property_label,
|
|
27
|
+
ga4Status: row.ga4_status,
|
|
28
|
+
ga4LastValidatedAt: row.ga4_last_validated_at,
|
|
29
|
+
ga4LastError: row.ga4_last_error,
|
|
30
|
+
searchConsoleSiteUrl: row.search_console_site_url,
|
|
31
|
+
searchConsoleLabel: row.search_console_label,
|
|
32
|
+
searchConsoleStatus: row.search_console_status,
|
|
33
|
+
searchConsoleLastValidatedAt: row.search_console_last_validated_at,
|
|
34
|
+
searchConsoleLastError: row.search_console_last_error,
|
|
35
|
+
updatedAt: row.updated_at
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function getGoogleOAuthConnection() {
|
|
39
|
+
try {
|
|
40
|
+
const result = await getDb().query(
|
|
41
|
+
`select id, encrypted_refresh_token, scopes, status, google_account_email, last_validated_at, last_error
|
|
42
|
+
from google_oauth_connections
|
|
43
|
+
where id = 'global'`
|
|
44
|
+
);
|
|
45
|
+
const row = result.rows[0];
|
|
46
|
+
return row ? mapConnection(row) : null;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (isMissingRelationError(error)) return null;
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function getActiveGoogleRefreshTokenFromStore() {
|
|
53
|
+
const connection = await getGoogleOAuthConnection();
|
|
54
|
+
if (!connection || connection.status !== "active" || !connection.encryptedRefreshToken) return null;
|
|
55
|
+
return decryptSecret(connection.encryptedRefreshToken);
|
|
56
|
+
}
|
|
57
|
+
async function getProfileGoogleServiceMapping(profileId) {
|
|
58
|
+
try {
|
|
59
|
+
const result = await getDb().query(
|
|
60
|
+
`select profile_id, google_ads_customer_id, google_ads_label, google_ads_status, google_ads_last_validated_at, google_ads_last_error,
|
|
61
|
+
ga4_property_id, ga4_property_label, ga4_status, ga4_last_validated_at, ga4_last_error,
|
|
62
|
+
search_console_site_url, search_console_label, search_console_status, search_console_last_validated_at, search_console_last_error,
|
|
63
|
+
updated_at
|
|
64
|
+
from profile_google_service_mappings
|
|
65
|
+
where profile_id = $1`,
|
|
66
|
+
[profileId]
|
|
67
|
+
);
|
|
68
|
+
const row = result.rows[0];
|
|
69
|
+
return row ? mapMapping(row) : null;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (isMissingRelationError(error)) return null;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function listProfileGoogleServiceMappings() {
|
|
76
|
+
try {
|
|
77
|
+
const result = await getDb().query(
|
|
78
|
+
`select profile_id, google_ads_customer_id, google_ads_label, google_ads_status, google_ads_last_validated_at, google_ads_last_error,
|
|
79
|
+
ga4_property_id, ga4_property_label, ga4_status, ga4_last_validated_at, ga4_last_error,
|
|
80
|
+
search_console_site_url, search_console_label, search_console_status, search_console_last_validated_at, search_console_last_error,
|
|
81
|
+
updated_at
|
|
82
|
+
from profile_google_service_mappings`
|
|
83
|
+
);
|
|
84
|
+
return result.rows.map(mapMapping);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (isMissingRelationError(error)) return [];
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
getActiveGoogleRefreshTokenFromStore,
|
|
92
|
+
getGoogleOAuthConnection,
|
|
93
|
+
getProfileGoogleServiceMapping,
|
|
94
|
+
listProfileGoogleServiceMappings
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=google-store.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/config/google-store.ts"],
|
|
4
|
+
"sourcesContent": ["import { getDb } from '../db/client.js';\nimport { decryptSecret } from './vtex-crypto.js';\n\nexport type GoogleServiceStatus = 'active' | 'disabled' | 'expired' | 'error' | 'pending';\n\nexport interface GoogleOAuthConnectionRecord {\n id: string;\n encryptedRefreshToken: string | null;\n scopes: string[];\n status: GoogleServiceStatus;\n googleAccountEmail: string | null;\n lastValidatedAt: Date | null;\n lastError: string | null;\n}\n\nexport interface ProfileGoogleServiceMappingRecord {\n profileId: string;\n googleAdsCustomerId: string | null;\n googleAdsLabel: string | null;\n googleAdsStatus: GoogleServiceStatus;\n googleAdsLastValidatedAt: Date | null;\n googleAdsLastError: string | null;\n ga4PropertyId: string | null;\n ga4PropertyLabel: string | null;\n ga4Status: GoogleServiceStatus;\n ga4LastValidatedAt: Date | null;\n ga4LastError: string | null;\n searchConsoleSiteUrl: string | null;\n searchConsoleLabel: string | null;\n searchConsoleStatus: GoogleServiceStatus;\n searchConsoleLastValidatedAt: Date | null;\n searchConsoleLastError: string | null;\n updatedAt: Date | null;\n}\n\ninterface GoogleOAuthConnectionRow {\n id: string;\n encrypted_refresh_token: string | null;\n scopes: string[] | null;\n status: GoogleServiceStatus;\n google_account_email: string | null;\n last_validated_at: Date | null;\n last_error: string | null;\n}\n\ninterface ProfileGoogleServiceMappingRow {\n profile_id: string;\n google_ads_customer_id: string | null;\n google_ads_label: string | null;\n google_ads_status: GoogleServiceStatus;\n google_ads_last_validated_at: Date | null;\n google_ads_last_error: string | null;\n ga4_property_id: string | null;\n ga4_property_label: string | null;\n ga4_status: GoogleServiceStatus;\n ga4_last_validated_at: Date | null;\n ga4_last_error: string | null;\n search_console_site_url: string | null;\n search_console_label: string | null;\n search_console_status: GoogleServiceStatus;\n search_console_last_validated_at: Date | null;\n search_console_last_error: string | null;\n updated_at: Date | null;\n}\n\nfunction isMissingRelationError(error: unknown): boolean {\n return error instanceof Error && /does not exist/i.test(error.message);\n}\n\nfunction mapConnection(row: GoogleOAuthConnectionRow): GoogleOAuthConnectionRecord {\n return {\n id: row.id,\n encryptedRefreshToken: row.encrypted_refresh_token,\n scopes: Array.isArray(row.scopes) ? row.scopes : [],\n status: row.status,\n googleAccountEmail: row.google_account_email,\n lastValidatedAt: row.last_validated_at,\n lastError: row.last_error,\n };\n}\n\nfunction mapMapping(row: ProfileGoogleServiceMappingRow): ProfileGoogleServiceMappingRecord {\n return {\n profileId: row.profile_id,\n googleAdsCustomerId: row.google_ads_customer_id,\n googleAdsLabel: row.google_ads_label,\n googleAdsStatus: row.google_ads_status,\n googleAdsLastValidatedAt: row.google_ads_last_validated_at,\n googleAdsLastError: row.google_ads_last_error,\n ga4PropertyId: row.ga4_property_id,\n ga4PropertyLabel: row.ga4_property_label,\n ga4Status: row.ga4_status,\n ga4LastValidatedAt: row.ga4_last_validated_at,\n ga4LastError: row.ga4_last_error,\n searchConsoleSiteUrl: row.search_console_site_url,\n searchConsoleLabel: row.search_console_label,\n searchConsoleStatus: row.search_console_status,\n searchConsoleLastValidatedAt: row.search_console_last_validated_at,\n searchConsoleLastError: row.search_console_last_error,\n updatedAt: row.updated_at,\n };\n}\n\nexport async function getGoogleOAuthConnection(): Promise<GoogleOAuthConnectionRecord | null> {\n try {\n const result = await getDb().query<GoogleOAuthConnectionRow>(\n `select id, encrypted_refresh_token, scopes, status, google_account_email, last_validated_at, last_error\n from google_oauth_connections\n where id = 'global'`\n );\n const row = result.rows[0];\n return row ? mapConnection(row) : null;\n } catch (error) {\n if (isMissingRelationError(error)) return null;\n throw error;\n }\n}\n\nexport async function getActiveGoogleRefreshTokenFromStore(): Promise<string | null> {\n const connection = await getGoogleOAuthConnection();\n if (!connection || connection.status !== 'active' || !connection.encryptedRefreshToken) return null;\n return decryptSecret(connection.encryptedRefreshToken);\n}\n\nexport async function getProfileGoogleServiceMapping(profileId: string): Promise<ProfileGoogleServiceMappingRecord | null> {\n try {\n const result = await getDb().query<ProfileGoogleServiceMappingRow>(\n `select profile_id, google_ads_customer_id, google_ads_label, google_ads_status, google_ads_last_validated_at, google_ads_last_error,\n ga4_property_id, ga4_property_label, ga4_status, ga4_last_validated_at, ga4_last_error,\n search_console_site_url, search_console_label, search_console_status, search_console_last_validated_at, search_console_last_error,\n updated_at\n from profile_google_service_mappings\n where profile_id = $1`,\n [profileId]\n );\n const row = result.rows[0];\n return row ? mapMapping(row) : null;\n } catch (error) {\n if (isMissingRelationError(error)) return null;\n throw error;\n }\n}\n\nexport async function listProfileGoogleServiceMappings(): Promise<ProfileGoogleServiceMappingRecord[]> {\n try {\n const result = await getDb().query<ProfileGoogleServiceMappingRow>(\n `select profile_id, google_ads_customer_id, google_ads_label, google_ads_status, google_ads_last_validated_at, google_ads_last_error,\n ga4_property_id, ga4_property_label, ga4_status, ga4_last_validated_at, ga4_last_error,\n search_console_site_url, search_console_label, search_console_status, search_console_last_validated_at, search_console_last_error,\n updated_at\n from profile_google_service_mappings`\n );\n return result.rows.map(mapMapping);\n } catch (error) {\n if (isMissingRelationError(error)) return [];\n throw error;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,aAAa;AACtB,SAAS,qBAAqB;AAgE9B,SAAS,uBAAuB,OAAyB;AACvD,SAAO,iBAAiB,SAAS,kBAAkB,KAAK,MAAM,OAAO;AACvE;AAEA,SAAS,cAAc,KAA4D;AACjF,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,uBAAuB,IAAI;AAAA,IAC3B,QAAQ,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,SAAS,CAAC;AAAA,IAClD,QAAQ,IAAI;AAAA,IACZ,oBAAoB,IAAI;AAAA,IACxB,iBAAiB,IAAI;AAAA,IACrB,WAAW,IAAI;AAAA,EACjB;AACF;AAEA,SAAS,WAAW,KAAwE;AAC1F,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,qBAAqB,IAAI;AAAA,IACzB,gBAAgB,IAAI;AAAA,IACpB,iBAAiB,IAAI;AAAA,IACrB,0BAA0B,IAAI;AAAA,IAC9B,oBAAoB,IAAI;AAAA,IACxB,eAAe,IAAI;AAAA,IACnB,kBAAkB,IAAI;AAAA,IACtB,WAAW,IAAI;AAAA,IACf,oBAAoB,IAAI;AAAA,IACxB,cAAc,IAAI;AAAA,IAClB,sBAAsB,IAAI;AAAA,IAC1B,oBAAoB,IAAI;AAAA,IACxB,qBAAqB,IAAI;AAAA,IACzB,8BAA8B,IAAI;AAAA,IAClC,wBAAwB,IAAI;AAAA,IAC5B,WAAW,IAAI;AAAA,EACjB;AACF;AAEA,eAAsB,2BAAwE;AAC5F,MAAI;AACF,UAAM,SAAS,MAAM,MAAM,EAAE;AAAA,MAC3B;AAAA;AAAA;AAAA,IAGF;AACA,UAAM,MAAM,OAAO,KAAK,CAAC;AACzB,WAAO,MAAM,cAAc,GAAG,IAAI;AAAA,EACpC,SAAS,OAAO;AACd,QAAI,uBAAuB,KAAK,EAAG,QAAO;AAC1C,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,uCAA+D;AACnF,QAAM,aAAa,MAAM,yBAAyB;AAClD,MAAI,CAAC,cAAc,WAAW,WAAW,YAAY,CAAC,WAAW,sBAAuB,QAAO;AAC/F,SAAO,cAAc,WAAW,qBAAqB;AACvD;AAEA,eAAsB,+BAA+B,WAAsE;AACzH,MAAI;AACF,UAAM,SAAS,MAAM,MAAM,EAAE;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,CAAC,SAAS;AAAA,IACZ;AACA,UAAM,MAAM,OAAO,KAAK,CAAC;AACzB,WAAO,MAAM,WAAW,GAAG,IAAI;AAAA,EACjC,SAAS,OAAO;AACd,QAAI,uBAAuB,KAAK,EAAG,QAAO;AAC1C,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,mCAAiF;AACrG,MAAI;AACF,UAAM,SAAS,MAAM,MAAM,EAAE;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,IAKF;AACA,WAAO,OAAO,KAAK,IAAI,UAAU;AAAA,EACnC,SAAS,OAAO;AACd,QAAI,uBAAuB,KAAK,EAAG,QAAO,CAAC;AAC3C,UAAM;AAAA,EACR;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
const REQUIRED_ENV_VARS = [
|
|
2
|
-
"GOOGLE_OAUTH_CLIENT_ID",
|
|
3
|
-
"GOOGLE_OAUTH_CLIENT_SECRET",
|
|
4
|
-
"GOOGLE_OAUTH_REFRESH_TOKEN"
|
|
5
|
-
];
|
|
1
|
+
const REQUIRED_ENV_VARS = ["GOOGLE_OAUTH_CLIENT_ID", "GOOGLE_OAUTH_CLIENT_SECRET"];
|
|
6
2
|
function requireEnv(name) {
|
|
7
3
|
const value = process.env[name]?.trim();
|
|
8
|
-
if (!value) {
|
|
9
|
-
throw new Error(`Missing required environment variable: ${name}`);
|
|
10
|
-
}
|
|
4
|
+
if (!value) throw new Error(`Missing required environment variable: ${name}`);
|
|
11
5
|
return value;
|
|
12
6
|
}
|
|
13
7
|
const googleOAuthConfig = {
|
|
14
8
|
clientId: requireEnv("GOOGLE_OAUTH_CLIENT_ID"),
|
|
15
|
-
clientSecret: requireEnv("GOOGLE_OAUTH_CLIENT_SECRET")
|
|
16
|
-
refreshToken: requireEnv("GOOGLE_OAUTH_REFRESH_TOKEN")
|
|
9
|
+
clientSecret: requireEnv("GOOGLE_OAUTH_CLIENT_SECRET")
|
|
17
10
|
};
|
|
18
11
|
function getDefaultGa4PropertyId() {
|
|
19
12
|
const value = process.env.GA4_PROPERTY_ID?.trim();
|
|
@@ -21,11 +14,7 @@ function getDefaultGa4PropertyId() {
|
|
|
21
14
|
}
|
|
22
15
|
function getGoogleAdsDeveloperToken() {
|
|
23
16
|
const value = process.env.GOOGLE_ADS_DEVELOPER_TOKEN?.trim();
|
|
24
|
-
if (!value)
|
|
25
|
-
throw new Error(
|
|
26
|
-
"Missing Google Ads developer token. Configure GOOGLE_ADS_DEVELOPER_TOKEN."
|
|
27
|
-
);
|
|
28
|
-
}
|
|
17
|
+
if (!value) throw new Error("Missing Google Ads developer token. Configure GOOGLE_ADS_DEVELOPER_TOKEN.");
|
|
29
18
|
return value;
|
|
30
19
|
}
|
|
31
20
|
function getDefaultGoogleAdsLoginCustomerId() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/config/google.ts"],
|
|
4
|
-
"sourcesContent": ["const REQUIRED_ENV_VARS = [
|
|
5
|
-
"mappings": "AAAA,MAAM,oBAAoB
|
|
4
|
+
"sourcesContent": ["const REQUIRED_ENV_VARS = ['GOOGLE_OAUTH_CLIENT_ID', 'GOOGLE_OAUTH_CLIENT_SECRET'] as const;\n\ntype RequiredEnvVar = (typeof REQUIRED_ENV_VARS)[number];\n\nfunction requireEnv(name: RequiredEnvVar): string {\n const value = process.env[name]?.trim();\n if (!value) throw new Error(`Missing required environment variable: ${name}`);\n return value;\n}\n\nexport interface GoogleOAuthClientConfig {\n clientId: string;\n clientSecret: string;\n}\n\nexport const googleOAuthConfig: GoogleOAuthClientConfig = {\n clientId: requireEnv('GOOGLE_OAUTH_CLIENT_ID'),\n clientSecret: requireEnv('GOOGLE_OAUTH_CLIENT_SECRET'),\n};\n\n\nexport function getDefaultGa4PropertyId(): string | undefined {\n const value = process.env.GA4_PROPERTY_ID?.trim();\n return value ? value : undefined;\n}\n\nexport function getGoogleAdsDeveloperToken(): string {\n const value = process.env.GOOGLE_ADS_DEVELOPER_TOKEN?.trim();\n if (!value) throw new Error('Missing Google Ads developer token. Configure GOOGLE_ADS_DEVELOPER_TOKEN.');\n return value;\n}\n\nexport function getDefaultGoogleAdsLoginCustomerId(): string | undefined {\n const value = process.env.GOOGLE_ADS_LOGIN_CUSTOMER_ID?.trim();\n return value ? value.replace(/-/g, '') : undefined;\n}\n"],
|
|
5
|
+
"mappings": "AAAA,MAAM,oBAAoB,CAAC,0BAA0B,4BAA4B;AAIjF,SAAS,WAAW,MAA8B;AAChD,QAAM,QAAQ,QAAQ,IAAI,IAAI,GAAG,KAAK;AACtC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,0CAA0C,IAAI,EAAE;AAC5E,SAAO;AACT;AAOO,MAAM,oBAA6C;AAAA,EACxD,UAAU,WAAW,wBAAwB;AAAA,EAC7C,cAAc,WAAW,4BAA4B;AACvD;AAGO,SAAS,0BAA8C;AAC5D,QAAM,QAAQ,QAAQ,IAAI,iBAAiB,KAAK;AAChD,SAAO,QAAQ,QAAQ;AACzB;AAEO,SAAS,6BAAqC;AACnD,QAAM,QAAQ,QAAQ,IAAI,4BAA4B,KAAK;AAC3D,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,2EAA2E;AACvG,SAAO;AACT;AAEO,SAAS,qCAAyD;AACvE,QAAM,QAAQ,QAAQ,IAAI,8BAA8B,KAAK;AAC7D,SAAO,QAAQ,MAAM,QAAQ,MAAM,EAAE,IAAI;AAC3C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { googleOAuthConfig } from "../../config/google.js";
|
|
2
|
-
|
|
2
|
+
import { getActiveGoogleRefreshTokenFromStore } from "../../config/google-store.js";
|
|
3
|
+
async function resolveGoogleOAuthCredentials() {
|
|
4
|
+
const refreshToken = await getActiveGoogleRefreshTokenFromStore();
|
|
5
|
+
if (!refreshToken) {
|
|
6
|
+
throw new Error(
|
|
7
|
+
"Missing Google OAuth refresh token. Connect Google in the dashboard and ensure the stored connection is active."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
clientId: googleOAuthConfig.clientId,
|
|
12
|
+
clientSecret: googleOAuthConfig.clientSecret,
|
|
13
|
+
refreshToken
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function refreshGoogleAccessToken(credentials) {
|
|
17
|
+
const resolved = credentials ?? await resolveGoogleOAuthCredentials();
|
|
3
18
|
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
4
19
|
method: "POST",
|
|
5
|
-
headers: {
|
|
6
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
7
|
-
},
|
|
20
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
8
21
|
body: new URLSearchParams({
|
|
9
|
-
client_id:
|
|
10
|
-
client_secret:
|
|
11
|
-
refresh_token:
|
|
22
|
+
client_id: resolved.clientId,
|
|
23
|
+
client_secret: resolved.clientSecret,
|
|
24
|
+
refresh_token: resolved.refreshToken,
|
|
12
25
|
grant_type: "refresh_token"
|
|
13
26
|
})
|
|
14
27
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/services/analytics/oauth.ts"],
|
|
4
|
-
"sourcesContent": ["import { googleOAuthConfig, type
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { googleOAuthConfig, type GoogleOAuthClientConfig } from '../../config/google.js';\nimport { getActiveGoogleRefreshTokenFromStore } from '../../config/google-store.js';\n\nexport interface GoogleAccessTokenResponse {\n accessToken: string;\n expiresIn: number;\n tokenType: string;\n scope?: string;\n}\n\nexport interface GoogleOAuthRefreshCredentials extends GoogleOAuthClientConfig {\n refreshToken: string;\n}\n\ninterface GoogleTokenApiResponse {\n access_token?: string;\n expires_in?: number;\n token_type?: string;\n scope?: string;\n error?: string;\n error_description?: string;\n}\n\nasync function resolveGoogleOAuthCredentials(): Promise<GoogleOAuthRefreshCredentials> {\n const refreshToken = await getActiveGoogleRefreshTokenFromStore();\n if (!refreshToken) {\n throw new Error(\n 'Missing Google OAuth refresh token. Connect Google in the dashboard and ensure the stored connection is active.'\n );\n }\n\n return {\n clientId: googleOAuthConfig.clientId,\n clientSecret: googleOAuthConfig.clientSecret,\n refreshToken,\n };\n}\n\nexport async function refreshGoogleAccessToken(\n credentials?: GoogleOAuthRefreshCredentials\n): Promise<GoogleAccessTokenResponse> {\n const resolved = credentials ?? (await resolveGoogleOAuthCredentials());\n const response = await fetch('https://oauth2.googleapis.com/token', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n client_id: resolved.clientId,\n client_secret: resolved.clientSecret,\n refresh_token: resolved.refreshToken,\n grant_type: 'refresh_token',\n }),\n });\n\n const payload = (await response.json()) as GoogleTokenApiResponse;\n\n if (!response.ok || !payload.access_token || !payload.expires_in || !payload.token_type) {\n const errorMessage = payload.error_description ?? payload.error ?? `Unexpected Google OAuth response (${response.status})`;\n throw new Error(`Failed to refresh Google access token: ${errorMessage}`);\n }\n\n return {\n accessToken: payload.access_token,\n expiresIn: payload.expires_in,\n tokenType: payload.token_type,\n scope: payload.scope,\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,yBAAuD;AAChE,SAAS,4CAA4C;AAsBrD,eAAe,gCAAwE;AACrF,QAAM,eAAe,MAAM,qCAAqC;AAChE,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,kBAAkB;AAAA,IAC5B,cAAc,kBAAkB;AAAA,IAChC;AAAA,EACF;AACF;AAEA,eAAsB,yBACpB,aACoC;AACpC,QAAM,WAAW,eAAgB,MAAM,8BAA8B;AACrE,QAAM,WAAW,MAAM,MAAM,uCAAuC;AAAA,IAClE,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,IAC/D,MAAM,IAAI,gBAAgB;AAAA,MACxB,WAAW,SAAS;AAAA,MACpB,eAAe,SAAS;AAAA,MACxB,eAAe,SAAS;AAAA,MACxB,YAAY;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AAED,QAAM,UAAW,MAAM,SAAS,KAAK;AAErC,MAAI,CAAC,SAAS,MAAM,CAAC,QAAQ,gBAAgB,CAAC,QAAQ,cAAc,CAAC,QAAQ,YAAY;AACvF,UAAM,eAAe,QAAQ,qBAAqB,QAAQ,SAAS,qCAAqC,SAAS,MAAM;AACvH,UAAM,IAAI,MAAM,0CAA0C,YAAY,EAAE;AAAA,EAC1E;AAEA,SAAO;AAAA,IACL,aAAa,QAAQ;AAAA,IACrB,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,IACnB,OAAO,QAAQ;AAAA,EACjB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|