@houtini/better-search-console 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +189 -0
- package/README.md +334 -0
- package/better-search-console.jpg +0 -0
- package/dist/core/DataRetention.d.ts +49 -0
- package/dist/core/DataRetention.d.ts.map +1 -0
- package/dist/core/DataRetention.js +165 -0
- package/dist/core/DataRetention.js.map +1 -0
- package/dist/core/DataSync.d.ts +24 -0
- package/dist/core/DataSync.d.ts.map +1 -0
- package/dist/core/DataSync.js +247 -0
- package/dist/core/DataSync.js.map +1 -0
- package/dist/core/Database.d.ts +29 -0
- package/dist/core/Database.d.ts.map +1 -0
- package/dist/core/Database.js +205 -0
- package/dist/core/Database.js.map +1 -0
- package/dist/core/GscClient.d.ts +23 -0
- package/dist/core/GscClient.d.ts.map +1 -0
- package/dist/core/GscClient.js +92 -0
- package/dist/core/GscClient.js.map +1 -0
- package/dist/core/SyncManager.d.ts +66 -0
- package/dist/core/SyncManager.d.ts.map +1 -0
- package/dist/core/SyncManager.js +368 -0
- package/dist/core/SyncManager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/overview/src/ui/overview.html +185 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +441 -0
- package/dist/server.js.map +1 -0
- package/dist/src/ui/dashboard.html +437 -0
- package/dist/sync-progress/src/ui/sync-progress.html +147 -0
- package/dist/tools/compare-periods.d.ts +3 -0
- package/dist/tools/compare-periods.d.ts.map +1 -0
- package/dist/tools/compare-periods.js +127 -0
- package/dist/tools/compare-periods.js.map +1 -0
- package/dist/tools/get-dashboard.d.ts +10 -0
- package/dist/tools/get-dashboard.d.ts.map +1 -0
- package/dist/tools/get-dashboard.js +310 -0
- package/dist/tools/get-dashboard.js.map +1 -0
- package/dist/tools/get-insights.d.ts +3 -0
- package/dist/tools/get-insights.d.ts.map +1 -0
- package/dist/tools/get-insights.js +509 -0
- package/dist/tools/get-insights.js.map +1 -0
- package/dist/tools/get-overview.d.ts +36 -0
- package/dist/tools/get-overview.d.ts.map +1 -0
- package/dist/tools/get-overview.js +111 -0
- package/dist/tools/get-overview.js.map +1 -0
- package/dist/tools/helpers.d.ts +67 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +239 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/list-properties.d.ts +4 -0
- package/dist/tools/list-properties.d.ts.map +1 -0
- package/dist/tools/list-properties.js +35 -0
- package/dist/tools/list-properties.js.map +1 -0
- package/dist/tools/query-data.d.ts +12 -0
- package/dist/tools/query-data.d.ts.map +1 -0
- package/dist/tools/query-data.js +20 -0
- package/dist/tools/query-data.js.map +1 -0
- package/dist/tools/sync-data.d.ts +11 -0
- package/dist/tools/sync-data.d.ts.map +1 -0
- package/dist/tools/sync-data.js +62 -0
- package/dist/tools/sync-data.js.map +1 -0
- package/dist/types/index.d.ts +101 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { Database } from '../core/Database.js';
|
|
4
|
+
import { sanitizeSiteUrl, getDataDir, getPeriodDates } from './helpers.js';
|
|
5
|
+
export async function getOverviewData(gscClient, params) {
|
|
6
|
+
const { dateRange = '28d', sortBy = 'alpha', search } = params;
|
|
7
|
+
const { current, prior } = getPeriodDates(dateRange);
|
|
8
|
+
const dataDir = getDataDir();
|
|
9
|
+
// Get all properties from GSC API
|
|
10
|
+
const allProperties = await gscClient.listProperties();
|
|
11
|
+
const properties = [];
|
|
12
|
+
const pctChange = (curr, prev) => prev === 0 ? null : Math.round(((curr - prev) / prev) * 1000) / 10;
|
|
13
|
+
for (const prop of allProperties) {
|
|
14
|
+
const dbFilename = sanitizeSiteUrl(prop.siteUrl) + '.db';
|
|
15
|
+
const dbPath = join(dataDir, dbFilename);
|
|
16
|
+
// Skip properties without synced data
|
|
17
|
+
if (!existsSync(dbPath))
|
|
18
|
+
continue;
|
|
19
|
+
// Extract clean domain
|
|
20
|
+
let domain = prop.siteUrl
|
|
21
|
+
.replace(/^sc-domain:/, '')
|
|
22
|
+
.replace(/^https?:\/\//, '')
|
|
23
|
+
.replace(/\/+$/, '');
|
|
24
|
+
// Filter by search substring
|
|
25
|
+
if (search && !domain.toLowerCase().includes(search.toLowerCase()))
|
|
26
|
+
continue;
|
|
27
|
+
const db = new Database(dbPath);
|
|
28
|
+
try {
|
|
29
|
+
// Summary for current period
|
|
30
|
+
const currentSummary = db.queryOne(`
|
|
31
|
+
SELECT
|
|
32
|
+
COALESCE(SUM(clicks), 0) as clicks,
|
|
33
|
+
COALESCE(SUM(impressions), 0) as impressions,
|
|
34
|
+
ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
|
|
35
|
+
ROUND(AVG(position), 1) as avg_position
|
|
36
|
+
FROM search_analytics
|
|
37
|
+
WHERE date BETWEEN ? AND ?
|
|
38
|
+
`, [current.startDate, current.endDate]);
|
|
39
|
+
// Summary for prior period
|
|
40
|
+
const priorSummary = db.queryOne(`
|
|
41
|
+
SELECT
|
|
42
|
+
COALESCE(SUM(clicks), 0) as clicks,
|
|
43
|
+
COALESCE(SUM(impressions), 0) as impressions,
|
|
44
|
+
ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
|
|
45
|
+
ROUND(AVG(position), 1) as avg_position
|
|
46
|
+
FROM search_analytics
|
|
47
|
+
WHERE date BETWEEN ? AND ?
|
|
48
|
+
`, [prior.startDate, prior.endDate]);
|
|
49
|
+
// Skip if no data at all
|
|
50
|
+
if (currentSummary.clicks === 0 && currentSummary.impressions === 0 &&
|
|
51
|
+
priorSummary.clicks === 0 && priorSummary.impressions === 0)
|
|
52
|
+
continue;
|
|
53
|
+
// Daily sparkline data
|
|
54
|
+
const sparkline = db.query(`
|
|
55
|
+
SELECT date,
|
|
56
|
+
SUM(clicks) as clicks,
|
|
57
|
+
SUM(impressions) as impressions
|
|
58
|
+
FROM search_analytics
|
|
59
|
+
WHERE date BETWEEN ? AND ?
|
|
60
|
+
GROUP BY date
|
|
61
|
+
ORDER BY date ASC
|
|
62
|
+
`, [current.startDate, current.endDate]);
|
|
63
|
+
// Last synced
|
|
64
|
+
const meta = db.getPropertyMeta(prop.siteUrl);
|
|
65
|
+
properties.push({
|
|
66
|
+
siteUrl: prop.siteUrl,
|
|
67
|
+
domain,
|
|
68
|
+
lastSyncedAt: meta?.lastSyncedAt ?? null,
|
|
69
|
+
current: {
|
|
70
|
+
clicks: currentSummary.clicks,
|
|
71
|
+
impressions: currentSummary.impressions,
|
|
72
|
+
ctr: currentSummary.ctr ?? 0,
|
|
73
|
+
avgPosition: currentSummary.avg_position ?? null,
|
|
74
|
+
},
|
|
75
|
+
changes: {
|
|
76
|
+
clicksPct: pctChange(currentSummary.clicks, priorSummary.clicks),
|
|
77
|
+
impressionsPct: pctChange(currentSummary.impressions, priorSummary.impressions),
|
|
78
|
+
ctrPct: pctChange(currentSummary.ctr ?? 0, priorSummary.ctr ?? 0),
|
|
79
|
+
avgPositionPct: (currentSummary.avg_position != null && priorSummary.avg_position != null)
|
|
80
|
+
? pctChange(currentSummary.avg_position, priorSummary.avg_position)
|
|
81
|
+
: null,
|
|
82
|
+
},
|
|
83
|
+
sparkline,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
db.close();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Sort
|
|
91
|
+
switch (sortBy) {
|
|
92
|
+
case 'clicks':
|
|
93
|
+
properties.sort((a, b) => b.current.clicks - a.current.clicks);
|
|
94
|
+
break;
|
|
95
|
+
case 'impressions':
|
|
96
|
+
properties.sort((a, b) => b.current.impressions - a.current.impressions);
|
|
97
|
+
break;
|
|
98
|
+
case 'ctr':
|
|
99
|
+
properties.sort((a, b) => b.current.ctr - a.current.ctr);
|
|
100
|
+
break;
|
|
101
|
+
case 'position':
|
|
102
|
+
properties.sort((a, b) => (a.current.avgPosition ?? 999) - (b.current.avgPosition ?? 999)); // lower is better, null sorts last
|
|
103
|
+
break;
|
|
104
|
+
case 'alpha':
|
|
105
|
+
default:
|
|
106
|
+
properties.sort((a, b) => a.domain.localeCompare(b.domain));
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
return { dateRange, sortBy, properties };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=get-overview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-overview.js","sourceRoot":"","sources":["../../src/tools/get-overview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize a GSC site URL into a safe filename.
|
|
3
|
+
* e.g. "sc-domain:simracingcockpit.gg" → "simracingcockpit.gg"
|
|
4
|
+
* e.g. "https://www.example.com/" → "www.example.com"
|
|
5
|
+
*/
|
|
6
|
+
export declare function sanitizeSiteUrl(siteUrl: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Get the data directory for SQLite databases.
|
|
9
|
+
* Priority: BSC_DATA_DIR env var > cross-platform home directory fallback.
|
|
10
|
+
*
|
|
11
|
+
* Defaults:
|
|
12
|
+
* Windows: C:\seo-audits\better-search-console
|
|
13
|
+
* macOS: ~/seo-audits/better-search-console
|
|
14
|
+
* Linux: ~/seo-audits/better-search-console
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDataDir(): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get the database path for a given site URL.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getDbPath(siteUrl: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Parse a date range shorthand into start/end dates.
|
|
23
|
+
* Supports: "7d", "14d", "28d", "3m", "6m", "8m", "12m", "16m",
|
|
24
|
+
* plus named presets: "1d", "lw", "tm", "lm", "tq", "lq", "ytd"
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseDateRange(range: string, referenceDate?: Date): {
|
|
27
|
+
startDate: string;
|
|
28
|
+
endDate: string;
|
|
29
|
+
};
|
|
30
|
+
export type ComparisonMode = 'previous_period' | 'year_over_year' | 'previous_month' | 'disabled';
|
|
31
|
+
/**
|
|
32
|
+
* Get current + prior period date ranges from a date range shorthand.
|
|
33
|
+
* Supports multiple comparison modes.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getPeriodDates(range: string, referenceDate?: Date, comparisonMode?: ComparisonMode, matchWeekdays?: boolean): {
|
|
36
|
+
current: {
|
|
37
|
+
startDate: string;
|
|
38
|
+
endDate: string;
|
|
39
|
+
};
|
|
40
|
+
prior: {
|
|
41
|
+
startDate: string;
|
|
42
|
+
endDate: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Default start date: 3 months ago for fast initial sync.
|
|
47
|
+
* Users can pass startDate explicitly for longer ranges (up to 16 months).
|
|
48
|
+
*/
|
|
49
|
+
export declare function defaultStartDate(): string;
|
|
50
|
+
/**
|
|
51
|
+
* Default end date: today.
|
|
52
|
+
*/
|
|
53
|
+
export declare function defaultEndDate(): string;
|
|
54
|
+
/**
|
|
55
|
+
* Render an ASCII sparkline from an array of numbers.
|
|
56
|
+
* Uses Unicode block characters for a compact visual trend.
|
|
57
|
+
*/
|
|
58
|
+
export declare function asciiSparkline(data: number[]): string;
|
|
59
|
+
/**
|
|
60
|
+
* Format a number with k/M suffixes for compact display.
|
|
61
|
+
*/
|
|
62
|
+
export declare function formatCompact(n: number): string;
|
|
63
|
+
/**
|
|
64
|
+
* Format a percentage change with sign and arrow.
|
|
65
|
+
*/
|
|
66
|
+
export declare function formatChange(pct: number | null): string;
|
|
67
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAOnC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAMD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,IAAI,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAuD1G;AAED,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,UAAU,CAAC;AAElG;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,IAAI,EACpB,cAAc,GAAE,cAAkC,EAClD,aAAa,GAAE,OAAe,GAC7B;IACD,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,CAmFA;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAGD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAOrD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIvD"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Sanitize a GSC site URL into a safe filename.
|
|
6
|
+
* e.g. "sc-domain:simracingcockpit.gg" → "simracingcockpit.gg"
|
|
7
|
+
* e.g. "https://www.example.com/" → "www.example.com"
|
|
8
|
+
*/
|
|
9
|
+
export function sanitizeSiteUrl(siteUrl) {
|
|
10
|
+
let name = siteUrl;
|
|
11
|
+
// Remove sc-domain: prefix
|
|
12
|
+
name = name.replace(/^sc-domain:/, '');
|
|
13
|
+
// Remove protocol
|
|
14
|
+
name = name.replace(/^https?:\/\//, '');
|
|
15
|
+
// Remove trailing slash
|
|
16
|
+
name = name.replace(/\/+$/, '');
|
|
17
|
+
// Replace unsafe chars
|
|
18
|
+
name = name.replace(/[^a-zA-Z0-9.-]/g, '_');
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the data directory for SQLite databases.
|
|
23
|
+
* Priority: BSC_DATA_DIR env var > cross-platform home directory fallback.
|
|
24
|
+
*
|
|
25
|
+
* Defaults:
|
|
26
|
+
* Windows: C:\seo-audits\better-search-console
|
|
27
|
+
* macOS: ~/seo-audits/better-search-console
|
|
28
|
+
* Linux: ~/seo-audits/better-search-console
|
|
29
|
+
*/
|
|
30
|
+
export function getDataDir() {
|
|
31
|
+
const dataDir = process.env.BSC_DATA_DIR
|
|
32
|
+
|| join(homedir(), 'seo-audits', 'better-search-console');
|
|
33
|
+
if (!existsSync(dataDir)) {
|
|
34
|
+
mkdirSync(dataDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
return dataDir;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the database path for a given site URL.
|
|
40
|
+
*/
|
|
41
|
+
export function getDbPath(siteUrl) {
|
|
42
|
+
return join(getDataDir(), sanitizeSiteUrl(siteUrl) + '.db');
|
|
43
|
+
}
|
|
44
|
+
function formatDate(d) {
|
|
45
|
+
return d.toISOString().split('T')[0];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse a date range shorthand into start/end dates.
|
|
49
|
+
* Supports: "7d", "14d", "28d", "3m", "6m", "8m", "12m", "16m",
|
|
50
|
+
* plus named presets: "1d", "lw", "tm", "lm", "tq", "lq", "ytd"
|
|
51
|
+
*/
|
|
52
|
+
export function parseDateRange(range, referenceDate) {
|
|
53
|
+
const now = referenceDate || new Date();
|
|
54
|
+
const today = formatDate(now);
|
|
55
|
+
// Named presets
|
|
56
|
+
switch (range) {
|
|
57
|
+
case 'lw': { // Last Week (Mon-Sun)
|
|
58
|
+
const d = new Date(now);
|
|
59
|
+
const day = d.getDay() || 7; // convert Sunday=0 to 7
|
|
60
|
+
d.setDate(d.getDate() - day - 6); // Monday of last week
|
|
61
|
+
const start = formatDate(d);
|
|
62
|
+
d.setDate(d.getDate() + 6); // Sunday of last week
|
|
63
|
+
return { startDate: start, endDate: formatDate(d) };
|
|
64
|
+
}
|
|
65
|
+
case 'tm': { // This Month
|
|
66
|
+
const d = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
67
|
+
return { startDate: formatDate(d), endDate: today };
|
|
68
|
+
}
|
|
69
|
+
case 'lm': { // Last Month
|
|
70
|
+
const start = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
71
|
+
const end = new Date(now.getFullYear(), now.getMonth(), 0); // last day of prev month
|
|
72
|
+
return { startDate: formatDate(start), endDate: formatDate(end) };
|
|
73
|
+
}
|
|
74
|
+
case 'tq': { // This Quarter
|
|
75
|
+
const qStart = new Date(now.getFullYear(), Math.floor(now.getMonth() / 3) * 3, 1);
|
|
76
|
+
return { startDate: formatDate(qStart), endDate: today };
|
|
77
|
+
}
|
|
78
|
+
case 'lq': { // Last Quarter
|
|
79
|
+
const qm = Math.floor(now.getMonth() / 3) * 3;
|
|
80
|
+
const start = new Date(now.getFullYear(), qm - 3, 1);
|
|
81
|
+
const end = new Date(now.getFullYear(), qm, 0);
|
|
82
|
+
return { startDate: formatDate(start), endDate: formatDate(end) };
|
|
83
|
+
}
|
|
84
|
+
case 'ytd': { // Year to Date
|
|
85
|
+
const start = new Date(now.getFullYear(), 0, 1);
|
|
86
|
+
return { startDate: formatDate(start), endDate: today };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Numeric presets: "7d", "3m", etc.
|
|
90
|
+
const match = range.match(/^(\d+)(d|m)$/);
|
|
91
|
+
if (!match) {
|
|
92
|
+
throw new Error(`Invalid date range: "${range}". Use format like "7d", "28d", "3m", "6m", "12m", "16m", or named presets: "lw", "tm", "lm", "tq", "lq", "ytd".`);
|
|
93
|
+
}
|
|
94
|
+
const amount = parseInt(match[1], 10);
|
|
95
|
+
const unit = match[2];
|
|
96
|
+
const start = new Date(now);
|
|
97
|
+
if (unit === 'd') {
|
|
98
|
+
start.setDate(start.getDate() - amount);
|
|
99
|
+
}
|
|
100
|
+
else if (unit === 'm') {
|
|
101
|
+
start.setMonth(start.getMonth() - amount);
|
|
102
|
+
}
|
|
103
|
+
return { startDate: formatDate(start), endDate: today };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get current + prior period date ranges from a date range shorthand.
|
|
107
|
+
* Supports multiple comparison modes.
|
|
108
|
+
*/
|
|
109
|
+
export function getPeriodDates(range, referenceDate, comparisonMode = 'previous_period', matchWeekdays = false) {
|
|
110
|
+
const current = parseDateRange(range, referenceDate);
|
|
111
|
+
if (comparisonMode === 'disabled') {
|
|
112
|
+
// Return empty prior period — callers should check for this
|
|
113
|
+
return {
|
|
114
|
+
current,
|
|
115
|
+
prior: { startDate: current.startDate, endDate: current.startDate },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const startMs = new Date(current.startDate).getTime();
|
|
119
|
+
const endMs = new Date(current.endDate).getTime();
|
|
120
|
+
const DAY = 24 * 60 * 60 * 1000;
|
|
121
|
+
const durationMs = endMs - startMs;
|
|
122
|
+
let priorStart;
|
|
123
|
+
let priorEnd;
|
|
124
|
+
switch (comparisonMode) {
|
|
125
|
+
case 'year_over_year': {
|
|
126
|
+
const s = new Date(current.startDate);
|
|
127
|
+
const e = new Date(current.endDate);
|
|
128
|
+
const sDay = s.getDate();
|
|
129
|
+
const eDay = e.getDate();
|
|
130
|
+
s.setFullYear(s.getFullYear() - 1);
|
|
131
|
+
// Handle leap year: Feb 29 → Feb 28 (setFullYear may roll to Mar 1)
|
|
132
|
+
if (s.getDate() !== sDay)
|
|
133
|
+
s.setDate(0); // last day of previous month
|
|
134
|
+
e.setFullYear(e.getFullYear() - 1);
|
|
135
|
+
if (e.getDate() !== eDay)
|
|
136
|
+
e.setDate(0);
|
|
137
|
+
priorStart = s;
|
|
138
|
+
priorEnd = e;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case 'previous_month': {
|
|
142
|
+
const s = new Date(current.startDate);
|
|
143
|
+
const e = new Date(current.endDate);
|
|
144
|
+
const sMonth = (s.getMonth() - 1 + 12) % 12;
|
|
145
|
+
const eMonth = (e.getMonth() - 1 + 12) % 12;
|
|
146
|
+
s.setMonth(s.getMonth() - 1);
|
|
147
|
+
// Handle day overflow: e.g. Mar 31 → setMonth(-1) → "Feb 31" → Mar 3
|
|
148
|
+
if (s.getMonth() !== sMonth)
|
|
149
|
+
s.setDate(0); // last day of intended month
|
|
150
|
+
e.setMonth(e.getMonth() - 1);
|
|
151
|
+
if (e.getMonth() !== eMonth)
|
|
152
|
+
e.setDate(0);
|
|
153
|
+
priorStart = s;
|
|
154
|
+
priorEnd = e;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'previous_period':
|
|
158
|
+
default: {
|
|
159
|
+
priorEnd = new Date(startMs - DAY);
|
|
160
|
+
priorStart = new Date(priorEnd.getTime() - durationMs);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Match weekdays: shift prior period so that the start day-of-week matches
|
|
165
|
+
if (matchWeekdays) {
|
|
166
|
+
const currentStartDay = new Date(current.startDate).getDay();
|
|
167
|
+
const priorStartDay = priorStart.getDay();
|
|
168
|
+
let diff = currentStartDay - priorStartDay;
|
|
169
|
+
// Find the closest shift that aligns weekdays (within ±3 days)
|
|
170
|
+
if (diff > 3)
|
|
171
|
+
diff -= 7;
|
|
172
|
+
if (diff < -3)
|
|
173
|
+
diff += 7;
|
|
174
|
+
priorStart = new Date(priorStart.getTime() + diff * DAY);
|
|
175
|
+
priorEnd = new Date(priorEnd.getTime() + diff * DAY);
|
|
176
|
+
// Safety: ensure prior period never overlaps with current period
|
|
177
|
+
const currentStartMs = new Date(current.startDate).getTime();
|
|
178
|
+
if (priorEnd.getTime() >= currentStartMs) {
|
|
179
|
+
const overshoot = priorEnd.getTime() - currentStartMs + DAY;
|
|
180
|
+
priorStart = new Date(priorStart.getTime() - overshoot);
|
|
181
|
+
priorEnd = new Date(priorEnd.getTime() - overshoot);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
current,
|
|
186
|
+
prior: {
|
|
187
|
+
startDate: formatDate(priorStart),
|
|
188
|
+
endDate: formatDate(priorEnd),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Default start date: 3 months ago for fast initial sync.
|
|
194
|
+
* Users can pass startDate explicitly for longer ranges (up to 16 months).
|
|
195
|
+
*/
|
|
196
|
+
export function defaultStartDate() {
|
|
197
|
+
const d = new Date();
|
|
198
|
+
d.setMonth(d.getMonth() - 3);
|
|
199
|
+
return formatDate(d);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Default end date: today.
|
|
203
|
+
*/
|
|
204
|
+
export function defaultEndDate() {
|
|
205
|
+
return formatDate(new Date());
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Render an ASCII sparkline from an array of numbers.
|
|
209
|
+
* Uses Unicode block characters for a compact visual trend.
|
|
210
|
+
*/
|
|
211
|
+
export function asciiSparkline(data) {
|
|
212
|
+
if (data.length === 0)
|
|
213
|
+
return '';
|
|
214
|
+
const min = Math.min(...data);
|
|
215
|
+
const max = Math.max(...data);
|
|
216
|
+
const range = max - min || 1;
|
|
217
|
+
const blocks = ' \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588';
|
|
218
|
+
return data.map(v => blocks[Math.round(((v - min) / range) * 8)]).join('');
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Format a number with k/M suffixes for compact display.
|
|
222
|
+
*/
|
|
223
|
+
export function formatCompact(n) {
|
|
224
|
+
if (n >= 1_000_000)
|
|
225
|
+
return (n / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M';
|
|
226
|
+
if (n >= 1_000)
|
|
227
|
+
return (n / 1_000).toFixed(1).replace(/\.0$/, '') + 'k';
|
|
228
|
+
return String(n);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Format a percentage change with sign and arrow.
|
|
232
|
+
*/
|
|
233
|
+
export function formatChange(pct) {
|
|
234
|
+
if (pct === null)
|
|
235
|
+
return 'n/a';
|
|
236
|
+
const sign = pct > 0 ? '+' : '';
|
|
237
|
+
return `${sign}${pct}%`;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-properties.d.ts","sourceRoot":"","sources":["../../src/tools/list-properties.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,wBAAsB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAgCpF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { Database } from '../core/Database.js';
|
|
4
|
+
import { sanitizeSiteUrl, getDataDir } from './helpers.js';
|
|
5
|
+
export async function listProperties(gscClient) {
|
|
6
|
+
const properties = await gscClient.listProperties();
|
|
7
|
+
const dataDir = getDataDir();
|
|
8
|
+
const results = [];
|
|
9
|
+
for (const prop of properties) {
|
|
10
|
+
const dbFilename = sanitizeSiteUrl(prop.siteUrl) + '.db';
|
|
11
|
+
const dbPath = join(dataDir, dbFilename);
|
|
12
|
+
let lastSyncedAt = null;
|
|
13
|
+
let rowCount = null;
|
|
14
|
+
if (existsSync(dbPath)) {
|
|
15
|
+
const db = new Database(dbPath);
|
|
16
|
+
try {
|
|
17
|
+
const meta = db.getPropertyMeta(prop.siteUrl);
|
|
18
|
+
lastSyncedAt = meta?.lastSyncedAt || null;
|
|
19
|
+
rowCount = db.getRowCount();
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
db.close();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
results.push({
|
|
26
|
+
siteUrl: prop.siteUrl,
|
|
27
|
+
permissionLevel: prop.permissionLevel,
|
|
28
|
+
lastSyncedAt,
|
|
29
|
+
rowCount,
|
|
30
|
+
dbPath: existsSync(dbPath) ? dbPath : null,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=list-properties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-properties.js","sourceRoot":"","sources":["../../src/tools/list-properties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,SAAoB;IACvD,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,cAAc,EAAE,CAAC;IACpD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACzC,IAAI,YAAY,GAAkB,IAAI,CAAC;QACvC,IAAI,QAAQ,GAAkB,IAAI,CAAC;QAEnC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC9C,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,IAAI,CAAC;gBAC1C,QAAQ,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;YAC9B,CAAC;oBAAS,CAAC;gBACT,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,YAAY;YACZ,QAAQ;YACR,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface QueryDataArgs {
|
|
2
|
+
siteUrl: string;
|
|
3
|
+
sql: string;
|
|
4
|
+
params?: any[];
|
|
5
|
+
}
|
|
6
|
+
export interface QueryDataResult {
|
|
7
|
+
columns: string[];
|
|
8
|
+
rows: any[];
|
|
9
|
+
rowCount: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function queryData(args: QueryDataArgs): QueryDataResult;
|
|
12
|
+
//# sourceMappingURL=query-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-data.d.ts","sourceRoot":"","sources":["../../src/tools/query-data.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,eAAe,CAgB9D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { Database } from '../core/Database.js';
|
|
3
|
+
import { getDbPath } from './helpers.js';
|
|
4
|
+
export function queryData(args) {
|
|
5
|
+
const { siteUrl, sql, params = [] } = args;
|
|
6
|
+
const dbPath = getDbPath(siteUrl);
|
|
7
|
+
if (!existsSync(dbPath)) {
|
|
8
|
+
throw new Error(`No database found for "${siteUrl}". Run sync_gsc_data first.`);
|
|
9
|
+
}
|
|
10
|
+
const db = new Database(dbPath);
|
|
11
|
+
try {
|
|
12
|
+
const rows = db.executeReadOnlyQuery(sql, params);
|
|
13
|
+
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
14
|
+
return { columns, rows, rowCount: rows.length };
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
db.close();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=query-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-data.js","sourceRoot":"","sources":["../../src/tools/query-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAczC,MAAM,UAAU,SAAS,CAAC,IAAmB;IAC3C,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;IAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAElC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,6BAA6B,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAClD,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GscClient } from '../core/GscClient.js';
|
|
2
|
+
import type { SyncResult } from '../types/index.js';
|
|
3
|
+
export interface SyncDataArgs {
|
|
4
|
+
siteUrl: string;
|
|
5
|
+
startDate?: string;
|
|
6
|
+
endDate?: string;
|
|
7
|
+
dimensions?: string[];
|
|
8
|
+
searchType?: 'web' | 'discover' | 'googleNews' | 'image' | 'video';
|
|
9
|
+
}
|
|
10
|
+
export declare function syncData(gscClient: GscClient, args: SyncDataArgs, signal?: AbortSignal): Promise<SyncResult>;
|
|
11
|
+
//# sourceMappingURL=sync-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-data.d.ts","sourceRoot":"","sources":["../../src/tools/sync-data.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;CACpE;AAKD,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,YAAY,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAiErB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Database } from '../core/Database.js';
|
|
2
|
+
import { DataSync } from '../core/DataSync.js';
|
|
3
|
+
import { getDbPath, defaultStartDate, defaultEndDate } from './helpers.js';
|
|
4
|
+
// Track active syncs to prevent duplicate concurrent syncs
|
|
5
|
+
const activeSyncs = new Set();
|
|
6
|
+
export async function syncData(gscClient, args, signal) {
|
|
7
|
+
const { siteUrl, endDate = defaultEndDate(), dimensions, } = args;
|
|
8
|
+
let { startDate } = args;
|
|
9
|
+
// Prevent duplicate syncs for the same property
|
|
10
|
+
if (activeSyncs.has(siteUrl)) {
|
|
11
|
+
return {
|
|
12
|
+
siteUrl,
|
|
13
|
+
dateFrom: startDate || '',
|
|
14
|
+
dateTo: endDate,
|
|
15
|
+
rowsFetched: 0,
|
|
16
|
+
rowsInserted: 0,
|
|
17
|
+
durationMs: 0,
|
|
18
|
+
status: 'error',
|
|
19
|
+
error: `A sync is already running for ${siteUrl}. Wait for it to complete or restart Claude Desktop to cancel it.`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const dbPath = getDbPath(siteUrl);
|
|
23
|
+
const db = new Database(dbPath);
|
|
24
|
+
activeSyncs.add(siteUrl);
|
|
25
|
+
try {
|
|
26
|
+
// Incremental sync: if no explicit start date, resume from last synced date
|
|
27
|
+
if (!startDate) {
|
|
28
|
+
const lastDate = db.getLastSyncDate(siteUrl);
|
|
29
|
+
if (lastDate) {
|
|
30
|
+
const d = new Date(lastDate);
|
|
31
|
+
d.setDate(d.getDate() + 1);
|
|
32
|
+
const nextDay = d.toISOString().slice(0, 10);
|
|
33
|
+
if (nextDay <= endDate) {
|
|
34
|
+
startDate = nextDay;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return {
|
|
38
|
+
siteUrl,
|
|
39
|
+
dateFrom: lastDate,
|
|
40
|
+
dateTo: endDate,
|
|
41
|
+
rowsFetched: 0,
|
|
42
|
+
rowsInserted: 0,
|
|
43
|
+
durationMs: 0,
|
|
44
|
+
status: 'already_current',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
startDate = defaultStartDate();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
db.upsertPropertyMeta(siteUrl, 'syncing');
|
|
53
|
+
const sync = new DataSync(db, gscClient);
|
|
54
|
+
const result = await sync.syncProperty(siteUrl, startDate, endDate, dimensions, args.searchType, signal);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
activeSyncs.delete(siteUrl);
|
|
59
|
+
db.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=sync-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-data.js","sourceRoot":"","sources":["../../src/tools/sync-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAU3E,2DAA2D;AAC3D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAoB,EACpB,IAAkB,EAClB,MAAoB;IAEpB,MAAM,EACJ,OAAO,EACP,OAAO,GAAG,cAAc,EAAE,EAC1B,UAAU,GACX,GAAG,IAAI,CAAC;IAET,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAEzB,gDAAgD;IAChD,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,OAAO;YACP,QAAQ,EAAE,SAAS,IAAI,EAAE;YACzB,MAAM,EAAE,OAAO;YACf,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,UAAU,EAAE,CAAC;YACb,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,iCAAiC,OAAO,mEAAmE;SACnH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAEzB,IAAI,CAAC;QACH,4EAA4E;QAC5E,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC3B,MAAM,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;oBACvB,SAAS,GAAG,OAAO,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBACN,OAAO;wBACL,OAAO;wBACP,QAAQ,EAAE,QAAQ;wBAClB,MAAM,EAAE,OAAO;wBACf,WAAW,EAAE,CAAC;wBACd,YAAY,EAAE,CAAC;wBACf,UAAU,EAAE,CAAC;wBACb,MAAM,EAAE,iBAAiB;qBAC1B,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,SAAS,GAAG,gBAAgB,EAAE,CAAC;YACjC,CAAC;QACH,CAAC;QAED,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAE1C,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CACpC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CACjE,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|