@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.
Files changed (71) hide show
  1. package/LICENSE +189 -0
  2. package/README.md +334 -0
  3. package/better-search-console.jpg +0 -0
  4. package/dist/core/DataRetention.d.ts +49 -0
  5. package/dist/core/DataRetention.d.ts.map +1 -0
  6. package/dist/core/DataRetention.js +165 -0
  7. package/dist/core/DataRetention.js.map +1 -0
  8. package/dist/core/DataSync.d.ts +24 -0
  9. package/dist/core/DataSync.d.ts.map +1 -0
  10. package/dist/core/DataSync.js +247 -0
  11. package/dist/core/DataSync.js.map +1 -0
  12. package/dist/core/Database.d.ts +29 -0
  13. package/dist/core/Database.d.ts.map +1 -0
  14. package/dist/core/Database.js +205 -0
  15. package/dist/core/Database.js.map +1 -0
  16. package/dist/core/GscClient.d.ts +23 -0
  17. package/dist/core/GscClient.d.ts.map +1 -0
  18. package/dist/core/GscClient.js +92 -0
  19. package/dist/core/GscClient.js.map +1 -0
  20. package/dist/core/SyncManager.d.ts +66 -0
  21. package/dist/core/SyncManager.d.ts.map +1 -0
  22. package/dist/core/SyncManager.js +368 -0
  23. package/dist/core/SyncManager.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +14 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/overview/src/ui/overview.html +185 -0
  29. package/dist/server.d.ts +6 -0
  30. package/dist/server.d.ts.map +1 -0
  31. package/dist/server.js +441 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/src/ui/dashboard.html +437 -0
  34. package/dist/sync-progress/src/ui/sync-progress.html +147 -0
  35. package/dist/tools/compare-periods.d.ts +3 -0
  36. package/dist/tools/compare-periods.d.ts.map +1 -0
  37. package/dist/tools/compare-periods.js +127 -0
  38. package/dist/tools/compare-periods.js.map +1 -0
  39. package/dist/tools/get-dashboard.d.ts +10 -0
  40. package/dist/tools/get-dashboard.d.ts.map +1 -0
  41. package/dist/tools/get-dashboard.js +310 -0
  42. package/dist/tools/get-dashboard.js.map +1 -0
  43. package/dist/tools/get-insights.d.ts +3 -0
  44. package/dist/tools/get-insights.d.ts.map +1 -0
  45. package/dist/tools/get-insights.js +509 -0
  46. package/dist/tools/get-insights.js.map +1 -0
  47. package/dist/tools/get-overview.d.ts +36 -0
  48. package/dist/tools/get-overview.d.ts.map +1 -0
  49. package/dist/tools/get-overview.js +111 -0
  50. package/dist/tools/get-overview.js.map +1 -0
  51. package/dist/tools/helpers.d.ts +67 -0
  52. package/dist/tools/helpers.d.ts.map +1 -0
  53. package/dist/tools/helpers.js +239 -0
  54. package/dist/tools/helpers.js.map +1 -0
  55. package/dist/tools/list-properties.d.ts +4 -0
  56. package/dist/tools/list-properties.d.ts.map +1 -0
  57. package/dist/tools/list-properties.js +35 -0
  58. package/dist/tools/list-properties.js.map +1 -0
  59. package/dist/tools/query-data.d.ts +12 -0
  60. package/dist/tools/query-data.d.ts.map +1 -0
  61. package/dist/tools/query-data.js +20 -0
  62. package/dist/tools/query-data.js.map +1 -0
  63. package/dist/tools/sync-data.d.ts +11 -0
  64. package/dist/tools/sync-data.d.ts.map +1 -0
  65. package/dist/tools/sync-data.js +62 -0
  66. package/dist/tools/sync-data.js.map +1 -0
  67. package/dist/types/index.d.ts +101 -0
  68. package/dist/types/index.d.ts.map +1 -0
  69. package/dist/types/index.js +3 -0
  70. package/dist/types/index.js.map +1 -0
  71. package/package.json +57 -0
@@ -0,0 +1,3 @@
1
+ import type { ComparePeriodParams } from '../types/index.js';
2
+ export declare function comparePeriods(params: ComparePeriodParams): any;
3
+ //# sourceMappingURL=compare-periods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-periods.d.ts","sourceRoot":"","sources":["../../src/tools/compare-periods.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,GAAG,CA4I/D"}
@@ -0,0 +1,127 @@
1
+ import { existsSync } from 'fs';
2
+ import { Database } from '../core/Database.js';
3
+ import { getDbPath } from './helpers.js';
4
+ export function comparePeriods(params) {
5
+ const { siteUrl, period1Start, period1End, period2Start, period2End, dimension = 'query', limit = 50, pageFilter, } = params;
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 validDimensions = ['query', 'page', 'device', 'country'];
11
+ if (!validDimensions.includes(dimension)) {
12
+ throw new Error(`Invalid dimension: "${dimension}". Valid: ${validDimensions.join(', ')}`);
13
+ }
14
+ const db = new Database(dbPath);
15
+ try {
16
+ let pageFilterClause = '';
17
+ const extraValues = [];
18
+ if (pageFilter) {
19
+ pageFilterClause = ' AND page LIKE ?';
20
+ extraValues.push(`%${pageFilter}%`);
21
+ }
22
+ // Summary totals for each period
23
+ const period1Summary = db.queryOne(`
24
+ SELECT
25
+ COALESCE(SUM(clicks), 0) as clicks,
26
+ COALESCE(SUM(impressions), 0) as impressions,
27
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
28
+ ROUND(AVG(position), 1) as avg_position
29
+ FROM search_analytics
30
+ WHERE date BETWEEN ? AND ?${pageFilterClause}
31
+ `, [period1Start, period1End, ...extraValues]);
32
+ const period2Summary = db.queryOne(`
33
+ SELECT
34
+ COALESCE(SUM(clicks), 0) as clicks,
35
+ COALESCE(SUM(impressions), 0) as impressions,
36
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
37
+ ROUND(AVG(position), 1) as avg_position
38
+ FROM search_analytics
39
+ WHERE date BETWEEN ? AND ?${pageFilterClause}
40
+ `, [period2Start, period2End, ...extraValues]);
41
+ // Dimension breakdown
42
+ const dimFilter = dimension === 'query' ? ' AND query IS NOT NULL' :
43
+ dimension === 'page' ? ' AND page IS NOT NULL' : '';
44
+ const rows = db.query(`
45
+ SELECT
46
+ ${dimension} as dimension_value,
47
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as period1_clicks,
48
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as period1_impressions,
49
+ ROUND(
50
+ CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL)
51
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4
52
+ ) as period1_ctr,
53
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as period2_clicks,
54
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as period2_impressions,
55
+ ROUND(
56
+ CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL)
57
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4
58
+ ) as period2_ctr,
59
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
60
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as click_change,
61
+ ROUND(
62
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
63
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
64
+ * 100.0
65
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
66
+ 1
67
+ ) as click_change_pct
68
+ FROM search_analytics
69
+ WHERE (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)${dimFilter}${pageFilterClause}
70
+ GROUP BY ${dimension}
71
+ HAVING period1_clicks > 0 OR period2_clicks > 0
72
+ ORDER BY period2_clicks DESC
73
+ LIMIT ?
74
+ `, [
75
+ // period1 clicks
76
+ period1Start, period1End,
77
+ // period1 impressions
78
+ period1Start, period1End,
79
+ // period1 ctr numerator
80
+ period1Start, period1End,
81
+ // period1 ctr denominator
82
+ period1Start, period1End,
83
+ // period2 clicks
84
+ period2Start, period2End,
85
+ // period2 impressions
86
+ period2Start, period2End,
87
+ // period2 ctr numerator
88
+ period2Start, period2End,
89
+ // period2 ctr denominator
90
+ period2Start, period2End,
91
+ // click_change
92
+ period2Start, period2End,
93
+ period1Start, period1End,
94
+ // click_change_pct numerator
95
+ period2Start, period2End,
96
+ period1Start, period1End,
97
+ // click_change_pct denominator
98
+ period1Start, period1End,
99
+ // WHERE date ranges
100
+ period1Start, period1End,
101
+ period2Start, period2End,
102
+ ...extraValues,
103
+ limit,
104
+ ]);
105
+ const pctChange = (curr, prev) => prev === 0 ? null : Math.round(((curr - prev) / prev) * 1000) / 10;
106
+ return {
107
+ dimension,
108
+ period1: { startDate: period1Start, endDate: period1End },
109
+ period2: { startDate: period2Start, endDate: period2End },
110
+ summary: {
111
+ period1: period1Summary,
112
+ period2: period2Summary,
113
+ changes: {
114
+ clicks: period2Summary.clicks - period1Summary.clicks,
115
+ clicksPct: pctChange(period2Summary.clicks, period1Summary.clicks),
116
+ impressions: period2Summary.impressions - period1Summary.impressions,
117
+ impressionsPct: pctChange(period2Summary.impressions, period1Summary.impressions),
118
+ },
119
+ },
120
+ rows,
121
+ };
122
+ }
123
+ finally {
124
+ db.close();
125
+ }
126
+ }
127
+ //# sourceMappingURL=compare-periods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-periods.js","sourceRoot":"","sources":["../../src/tools/compare-periods.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type ComparisonMode } from './helpers.js';
2
+ export interface DashboardParams {
3
+ siteUrl: string;
4
+ dateRange?: string;
5
+ comparisonMode?: ComparisonMode;
6
+ matchWeekdays?: boolean;
7
+ brandTerms?: string[];
8
+ }
9
+ export declare function getDashboardData(params: DashboardParams): any;
10
+ //# sourceMappingURL=get-dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-dashboard.d.ts","sourceRoot":"","sources":["../../src/tools/get-dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,GAAG,CAqU7D"}
@@ -0,0 +1,310 @@
1
+ import { existsSync } from 'fs';
2
+ import { Database } from '../core/Database.js';
3
+ import { getDbPath, getPeriodDates } from './helpers.js';
4
+ export function getDashboardData(params) {
5
+ const { siteUrl, dateRange = '3m', comparisonMode = 'previous_period', matchWeekdays = false, brandTerms } = params;
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 { current, prior } = getPeriodDates(dateRange, undefined, comparisonMode, matchWeekdays);
11
+ const comparisonDisabled = comparisonMode === 'disabled';
12
+ const db = new Database(dbPath);
13
+ try {
14
+ // 1. Summary metrics
15
+ const currentSummary = db.queryOne(`
16
+ SELECT
17
+ COALESCE(SUM(clicks), 0) as clicks,
18
+ COALESCE(SUM(impressions), 0) as impressions,
19
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
20
+ ROUND(AVG(position), 1) as avg_position
21
+ FROM search_analytics
22
+ WHERE date BETWEEN ? AND ?
23
+ `, [current.startDate, current.endDate]);
24
+ const priorSummary = db.queryOne(`
25
+ SELECT
26
+ COALESCE(SUM(clicks), 0) as clicks,
27
+ COALESCE(SUM(impressions), 0) as impressions,
28
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
29
+ ROUND(AVG(position), 1) as avg_position
30
+ FROM search_analytics
31
+ WHERE date BETWEEN ? AND ?
32
+ `, [prior.startDate, prior.endDate]);
33
+ // 2. Daily trend (with CTR and position for metric toggles)
34
+ const dailyTrend = db.query(`
35
+ SELECT date,
36
+ SUM(clicks) as clicks,
37
+ SUM(impressions) as impressions,
38
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
39
+ ROUND(AVG(position), 1) as avg_position
40
+ FROM search_analytics
41
+ WHERE date BETWEEN ? AND ?
42
+ GROUP BY date
43
+ ORDER BY date ASC
44
+ `, [current.startDate, current.endDate]);
45
+ // 2b. Prior period daily trend (for dashed overlay)
46
+ const priorDailyTrend = comparisonDisabled ? [] : db.query(`
47
+ SELECT date,
48
+ SUM(clicks) as clicks,
49
+ SUM(impressions) as impressions,
50
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
51
+ ROUND(AVG(position), 1) as avg_position
52
+ FROM search_analytics
53
+ WHERE date BETWEEN ? AND ?
54
+ GROUP BY date
55
+ ORDER BY date ASC
56
+ `, [prior.startDate, prior.endDate]);
57
+ // 3. Top queries with change + CTR + position
58
+ const topQueries = db.query(`
59
+ SELECT query,
60
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as clicks,
61
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as impressions,
62
+ ROUND(CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL) /
63
+ NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4) as ctr,
64
+ ROUND(AVG(CASE WHEN date BETWEEN ? AND ? THEN position ELSE NULL END), 1) as avg_position,
65
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
66
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as prior_impressions,
67
+ ROUND(CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL) /
68
+ NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4) as prior_ctr,
69
+ ROUND(AVG(CASE WHEN date BETWEEN ? AND ? THEN position ELSE NULL END), 1) as prior_avg_position,
70
+ ROUND(
71
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
72
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
73
+ * 100.0
74
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
75
+ 1
76
+ ) as clicks_change_pct
77
+ FROM search_analytics
78
+ WHERE query IS NOT NULL
79
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)
80
+ GROUP BY query
81
+ HAVING clicks > 0
82
+ ORDER BY clicks DESC
83
+ LIMIT 100
84
+ `, [
85
+ current.startDate, current.endDate,
86
+ current.startDate, current.endDate,
87
+ current.startDate, current.endDate,
88
+ current.startDate, current.endDate,
89
+ current.startDate, current.endDate,
90
+ prior.startDate, prior.endDate,
91
+ prior.startDate, prior.endDate,
92
+ prior.startDate, prior.endDate,
93
+ prior.startDate, prior.endDate,
94
+ prior.startDate, prior.endDate,
95
+ current.startDate, current.endDate,
96
+ prior.startDate, prior.endDate,
97
+ prior.startDate, prior.endDate,
98
+ current.startDate, current.endDate,
99
+ prior.startDate, prior.endDate,
100
+ ]);
101
+ // 4. Top pages with change + CTR + position
102
+ const topPages = db.query(`
103
+ SELECT page,
104
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as clicks,
105
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as impressions,
106
+ ROUND(CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL) /
107
+ NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4) as ctr,
108
+ ROUND(AVG(CASE WHEN date BETWEEN ? AND ? THEN position ELSE NULL END), 1) as avg_position,
109
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
110
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as prior_impressions,
111
+ ROUND(CAST(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) AS REAL) /
112
+ NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END), 0), 4) as prior_ctr,
113
+ ROUND(AVG(CASE WHEN date BETWEEN ? AND ? THEN position ELSE NULL END), 1) as prior_avg_position,
114
+ ROUND(
115
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
116
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
117
+ * 100.0
118
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
119
+ 1
120
+ ) as clicks_change_pct
121
+ FROM search_analytics
122
+ WHERE page IS NOT NULL
123
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)
124
+ GROUP BY page
125
+ HAVING clicks > 0
126
+ ORDER BY clicks DESC
127
+ LIMIT 100
128
+ `, [
129
+ current.startDate, current.endDate,
130
+ current.startDate, current.endDate,
131
+ current.startDate, current.endDate,
132
+ current.startDate, current.endDate,
133
+ current.startDate, current.endDate,
134
+ prior.startDate, prior.endDate,
135
+ prior.startDate, prior.endDate,
136
+ prior.startDate, prior.endDate,
137
+ prior.startDate, prior.endDate,
138
+ prior.startDate, prior.endDate,
139
+ current.startDate, current.endDate,
140
+ prior.startDate, prior.endDate,
141
+ prior.startDate, prior.endDate,
142
+ current.startDate, current.endDate,
143
+ prior.startDate, prior.endDate,
144
+ ]);
145
+ // 5. Country breakdown
146
+ const countries = db.query(`
147
+ SELECT country,
148
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as clicks,
149
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as impressions,
150
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
151
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as prior_impressions,
152
+ ROUND(
153
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
154
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
155
+ * 100.0
156
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
157
+ 1
158
+ ) as clicks_change_pct
159
+ FROM search_analytics
160
+ WHERE country IS NOT NULL
161
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)
162
+ GROUP BY country
163
+ HAVING clicks > 0
164
+ ORDER BY clicks DESC
165
+ LIMIT 50
166
+ `, [
167
+ current.startDate, current.endDate,
168
+ current.startDate, current.endDate,
169
+ prior.startDate, prior.endDate,
170
+ prior.startDate, prior.endDate,
171
+ current.startDate, current.endDate,
172
+ prior.startDate, prior.endDate,
173
+ prior.startDate, prior.endDate,
174
+ current.startDate, current.endDate,
175
+ prior.startDate, prior.endDate,
176
+ ]);
177
+ // 6. Ranking buckets — computed in SQL to avoid pulling millions of rows into JS
178
+ const rankingBuckets = db.query(`
179
+ SELECT
180
+ CASE
181
+ WHEN avg_pos <= 3 THEN '1-3'
182
+ WHEN avg_pos <= 10 THEN '4-10'
183
+ WHEN avg_pos <= 20 THEN '11-20'
184
+ WHEN avg_pos <= 50 THEN '21-50'
185
+ WHEN avg_pos <= 100 THEN '51-100'
186
+ ELSE '100+'
187
+ END as bucket,
188
+ COUNT(*) as count
189
+ FROM (
190
+ SELECT AVG(position) as avg_pos
191
+ FROM search_analytics
192
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL
193
+ GROUP BY query
194
+ )
195
+ GROUP BY bucket
196
+ ORDER BY MIN(avg_pos)
197
+ `, [current.startDate, current.endDate]);
198
+ // 7. New queries (in current but not in prior) — using EXCEPT for efficiency
199
+ const newQueries = comparisonDisabled ? [] : db.query(`
200
+ SELECT query, SUM(clicks) as clicks, SUM(impressions) as impressions, ROUND(AVG(position), 1) as avg_position
201
+ FROM search_analytics
202
+ WHERE date BETWEEN ? AND ?
203
+ AND query IS NOT NULL
204
+ AND query IN (
205
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
206
+ EXCEPT
207
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
208
+ )
209
+ GROUP BY query
210
+ HAVING clicks > 0
211
+ ORDER BY clicks DESC
212
+ LIMIT 50
213
+ `, [current.startDate, current.endDate, current.startDate, current.endDate, prior.startDate, prior.endDate]);
214
+ // 8. Lost queries (in prior but not in current) — using EXCEPT for efficiency
215
+ const lostQueries = comparisonDisabled ? [] : db.query(`
216
+ SELECT query, SUM(clicks) as clicks, SUM(impressions) as impressions, ROUND(AVG(position), 1) as avg_position
217
+ FROM search_analytics
218
+ WHERE date BETWEEN ? AND ?
219
+ AND query IS NOT NULL
220
+ AND query IN (
221
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
222
+ EXCEPT
223
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
224
+ )
225
+ GROUP BY query
226
+ HAVING clicks > 0
227
+ ORDER BY clicks DESC
228
+ LIMIT 50
229
+ `, [prior.startDate, prior.endDate, prior.startDate, prior.endDate, current.startDate, current.endDate]);
230
+ // 9. Branded split (if brandTerms provided)
231
+ let brandedSplit = null;
232
+ if (brandTerms && brandTerms.length > 0) {
233
+ const brandConditions = brandTerms.map(() => 'LOWER(query) LIKE ?').join(' OR ');
234
+ const brandValues = brandTerms.map(t => `%${t.toLowerCase()}%`);
235
+ const splitSummary = db.query(`
236
+ SELECT
237
+ CASE WHEN ${brandConditions} THEN 'branded' ELSE 'non-branded' END as segment,
238
+ SUM(clicks) as clicks,
239
+ SUM(impressions) as impressions
240
+ FROM search_analytics
241
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL
242
+ GROUP BY segment
243
+ `, [...brandValues, current.startDate, current.endDate]);
244
+ const priorSplitSummary = comparisonDisabled ? [] : db.query(`
245
+ SELECT
246
+ CASE WHEN ${brandConditions} THEN 'branded' ELSE 'non-branded' END as segment,
247
+ SUM(clicks) as clicks,
248
+ SUM(impressions) as impressions
249
+ FROM search_analytics
250
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL
251
+ GROUP BY segment
252
+ `, [...brandValues, prior.startDate, prior.endDate]);
253
+ const splitTrend = db.query(`
254
+ SELECT date,
255
+ CASE WHEN ${brandConditions} THEN 'branded' ELSE 'non-branded' END as segment,
256
+ SUM(clicks) as clicks
257
+ FROM search_analytics
258
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL
259
+ GROUP BY date, segment
260
+ ORDER BY date ASC
261
+ `, [...brandValues, current.startDate, current.endDate]);
262
+ brandedSplit = { summary: splitSummary, priorSummary: priorSplitSummary, trend: splitTrend };
263
+ }
264
+ // 10. Last synced timestamp
265
+ const meta = db.getPropertyMeta(siteUrl);
266
+ const lastSyncedAt = meta?.lastSyncedAt ?? null;
267
+ const pctChange = (curr, prev) => prev === 0 ? null : Math.round(((curr - prev) / prev) * 1000) / 10;
268
+ return {
269
+ siteUrl,
270
+ dateRange,
271
+ comparisonMode,
272
+ matchWeekdays,
273
+ lastSyncedAt,
274
+ period: { current, prior },
275
+ summary: {
276
+ current: {
277
+ clicks: currentSummary.clicks,
278
+ impressions: currentSummary.impressions,
279
+ ctr: currentSummary.ctr,
280
+ avgPosition: currentSummary.avg_position,
281
+ },
282
+ prior: {
283
+ clicks: priorSummary.clicks,
284
+ impressions: priorSummary.impressions,
285
+ ctr: priorSummary.ctr,
286
+ avgPosition: priorSummary.avg_position,
287
+ },
288
+ changes: {
289
+ clicksPct: pctChange(currentSummary.clicks, priorSummary.clicks),
290
+ impressionsPct: pctChange(currentSummary.impressions, priorSummary.impressions),
291
+ ctrPct: pctChange(currentSummary.ctr ?? 0, priorSummary.ctr ?? 0),
292
+ avgPositionPct: pctChange(currentSummary.avg_position ?? 0, priorSummary.avg_position ?? 0),
293
+ },
294
+ },
295
+ dailyTrend,
296
+ priorDailyTrend,
297
+ topQueries,
298
+ topPages,
299
+ countries,
300
+ rankingBuckets,
301
+ newQueries,
302
+ lostQueries,
303
+ brandedSplit,
304
+ };
305
+ }
306
+ finally {
307
+ db.close();
308
+ }
309
+ }
310
+ //# sourceMappingURL=get-dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-dashboard.js","sourceRoot":"","sources":["../../src/tools/get-dashboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { InsightParams } from '../types/index.js';
2
+ export declare function getInsights(params: InsightParams): any;
3
+ //# sourceMappingURL=get-insights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-insights.d.ts","sourceRoot":"","sources":["../../src/tools/get-insights.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvD,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,GAAG,CAoBtD"}