@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,509 @@
1
+ import { existsSync } from 'fs';
2
+ import { Database } from '../core/Database.js';
3
+ import { getDbPath, getPeriodDates } from './helpers.js';
4
+ export function getInsights(params) {
5
+ const { siteUrl, insight, dateRange = '28d' } = 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 handler = insightHandlers[insight];
11
+ if (!handler) {
12
+ throw new Error(`Unknown insight type: "${insight}". Valid types: ${Object.keys(insightHandlers).join(', ')}`);
13
+ }
14
+ const { current, prior } = getPeriodDates(dateRange);
15
+ const db = new Database(dbPath);
16
+ try {
17
+ return handler(db, params, current, prior);
18
+ }
19
+ finally {
20
+ db.close();
21
+ }
22
+ }
23
+ /** Build WHERE clause fragments from common filter params */
24
+ function buildFilters(params) {
25
+ const clauses = [];
26
+ const values = [];
27
+ if (params.pageFilter) {
28
+ clauses.push('page LIKE ?');
29
+ values.push(`%${params.pageFilter}%`);
30
+ }
31
+ if (params.queryFilter) {
32
+ clauses.push('query LIKE ?');
33
+ values.push(`%${params.queryFilter}%`);
34
+ }
35
+ if (params.device) {
36
+ clauses.push('device = ?');
37
+ values.push(params.device);
38
+ }
39
+ if (params.country) {
40
+ clauses.push('country = ?');
41
+ values.push(params.country);
42
+ }
43
+ return { clauses, values };
44
+ }
45
+ function filterSQL(params) {
46
+ const { clauses } = buildFilters(params);
47
+ return clauses.length > 0 ? ' AND ' + clauses.join(' AND ') : '';
48
+ }
49
+ function filterValues(params) {
50
+ return buildFilters(params).values;
51
+ }
52
+ // --- Insight Handlers ---
53
+ const insightHandlers = {
54
+ summary: (db, params, current, prior) => {
55
+ const f = filterSQL(params);
56
+ const fv = filterValues(params);
57
+ const currentRow = db.queryOne(`
58
+ SELECT
59
+ COALESCE(SUM(clicks), 0) as clicks,
60
+ COALESCE(SUM(impressions), 0) as impressions,
61
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
62
+ ROUND(AVG(position), 1) as avg_position
63
+ FROM search_analytics
64
+ WHERE date BETWEEN ? AND ?${f}
65
+ `, [current.startDate, current.endDate, ...fv]);
66
+ const priorRow = db.queryOne(`
67
+ SELECT
68
+ COALESCE(SUM(clicks), 0) as clicks,
69
+ COALESCE(SUM(impressions), 0) as impressions,
70
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
71
+ ROUND(AVG(position), 1) as avg_position
72
+ FROM search_analytics
73
+ WHERE date BETWEEN ? AND ?${f}
74
+ `, [prior.startDate, prior.endDate, ...fv]);
75
+ const pctChange = (curr, prev) => prev === 0 ? null : Math.round(((curr - prev) / prev) * 1000) / 10;
76
+ return {
77
+ insight: 'summary',
78
+ dateRange: { current, prior },
79
+ current: {
80
+ clicks: currentRow.clicks,
81
+ impressions: currentRow.impressions,
82
+ ctr: currentRow.ctr,
83
+ avgPosition: currentRow.avg_position,
84
+ },
85
+ prior: {
86
+ clicks: priorRow.clicks,
87
+ impressions: priorRow.impressions,
88
+ ctr: priorRow.ctr,
89
+ avgPosition: priorRow.avg_position,
90
+ },
91
+ changes: {
92
+ clicks: currentRow.clicks - priorRow.clicks,
93
+ clicksPct: pctChange(currentRow.clicks, priorRow.clicks),
94
+ impressions: currentRow.impressions - priorRow.impressions,
95
+ impressionsPct: pctChange(currentRow.impressions, priorRow.impressions),
96
+ ctr: currentRow.ctr !== null && priorRow.ctr !== null
97
+ ? Math.round((currentRow.ctr - priorRow.ctr) * 10000) / 10000
98
+ : null,
99
+ ctrPct: currentRow.ctr !== null && priorRow.ctr !== null
100
+ ? pctChange(currentRow.ctr, priorRow.ctr)
101
+ : null,
102
+ avgPosition: currentRow.avg_position !== null && priorRow.avg_position !== null
103
+ ? Math.round((currentRow.avg_position - priorRow.avg_position) * 10) / 10
104
+ : null,
105
+ avgPositionPct: currentRow.avg_position !== null && priorRow.avg_position !== null
106
+ ? pctChange(currentRow.avg_position, priorRow.avg_position)
107
+ : null,
108
+ },
109
+ };
110
+ },
111
+ top_queries: (db, params, current, _prior) => {
112
+ const limit = params.limit || 50;
113
+ const f = filterSQL(params);
114
+ const fv = filterValues(params);
115
+ const rows = db.query(`
116
+ SELECT query,
117
+ SUM(clicks) as clicks,
118
+ SUM(impressions) as impressions,
119
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
120
+ ROUND(AVG(position), 1) as avg_position
121
+ FROM search_analytics
122
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL${f}
123
+ GROUP BY query
124
+ ORDER BY clicks DESC
125
+ LIMIT ?
126
+ `, [current.startDate, current.endDate, ...fv, limit]);
127
+ return { insight: 'top_queries', dateRange: current, rows };
128
+ },
129
+ top_pages: (db, params, current, _prior) => {
130
+ const limit = params.limit || 50;
131
+ const f = filterSQL(params);
132
+ const fv = filterValues(params);
133
+ const rows = db.query(`
134
+ SELECT page,
135
+ SUM(clicks) as clicks,
136
+ SUM(impressions) as impressions,
137
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
138
+ ROUND(AVG(position), 1) as avg_position
139
+ FROM search_analytics
140
+ WHERE date BETWEEN ? AND ? AND page IS NOT NULL${f}
141
+ GROUP BY page
142
+ ORDER BY clicks DESC
143
+ LIMIT ?
144
+ `, [current.startDate, current.endDate, ...fv, limit]);
145
+ return { insight: 'top_pages', dateRange: current, rows };
146
+ },
147
+ growing_queries: (db, params, current, prior) => {
148
+ const limit = params.limit || 50;
149
+ const f = filterSQL(params);
150
+ const fv = filterValues(params);
151
+ const rows = db.query(`
152
+ SELECT query,
153
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as current_clicks,
154
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
155
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
156
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as click_change,
157
+ ROUND(
158
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
159
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
160
+ * 100.0
161
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
162
+ 1
163
+ ) as pct_change,
164
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as current_impressions,
165
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as prior_impressions
166
+ FROM search_analytics
167
+ WHERE query IS NOT NULL
168
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)${f}
169
+ GROUP BY query
170
+ HAVING current_clicks > 0
171
+ ORDER BY click_change DESC
172
+ LIMIT ?
173
+ `, [
174
+ current.startDate, current.endDate,
175
+ prior.startDate, prior.endDate,
176
+ current.startDate, current.endDate,
177
+ prior.startDate, prior.endDate,
178
+ current.startDate, current.endDate,
179
+ prior.startDate, prior.endDate,
180
+ prior.startDate, prior.endDate,
181
+ current.startDate, current.endDate,
182
+ prior.startDate, prior.endDate,
183
+ current.startDate, current.endDate,
184
+ prior.startDate, prior.endDate,
185
+ ...fv,
186
+ limit,
187
+ ]);
188
+ return { insight: 'growing_queries', dateRange: { current, prior }, rows };
189
+ },
190
+ declining_queries: (db, params, current, prior) => {
191
+ const limit = params.limit || 50;
192
+ const f = filterSQL(params);
193
+ const fv = filterValues(params);
194
+ const rows = db.query(`
195
+ SELECT query,
196
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as current_clicks,
197
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
198
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
199
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as click_change,
200
+ ROUND(
201
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
202
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
203
+ * 100.0
204
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
205
+ 1
206
+ ) as pct_change,
207
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as current_impressions,
208
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN impressions ELSE 0 END) as prior_impressions
209
+ FROM search_analytics
210
+ WHERE query IS NOT NULL
211
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)${f}
212
+ GROUP BY query
213
+ HAVING prior_clicks > 0
214
+ ORDER BY click_change ASC
215
+ LIMIT ?
216
+ `, [
217
+ current.startDate, current.endDate,
218
+ prior.startDate, prior.endDate,
219
+ current.startDate, current.endDate,
220
+ prior.startDate, prior.endDate,
221
+ current.startDate, current.endDate,
222
+ prior.startDate, prior.endDate,
223
+ prior.startDate, prior.endDate,
224
+ current.startDate, current.endDate,
225
+ prior.startDate, prior.endDate,
226
+ current.startDate, current.endDate,
227
+ prior.startDate, prior.endDate,
228
+ ...fv,
229
+ limit,
230
+ ]);
231
+ return { insight: 'declining_queries', dateRange: { current, prior }, rows };
232
+ },
233
+ growing_pages: (db, params, current, prior) => {
234
+ const limit = params.limit || 50;
235
+ const f = filterSQL(params);
236
+ const fv = filterValues(params);
237
+ const rows = db.query(`
238
+ SELECT page,
239
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as current_clicks,
240
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
241
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
242
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as click_change,
243
+ ROUND(
244
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
245
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
246
+ * 100.0
247
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
248
+ 1
249
+ ) as pct_change
250
+ FROM search_analytics
251
+ WHERE page IS NOT NULL
252
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)${f}
253
+ GROUP BY page
254
+ HAVING current_clicks > 0
255
+ ORDER BY click_change DESC
256
+ LIMIT ?
257
+ `, [
258
+ current.startDate, current.endDate,
259
+ prior.startDate, prior.endDate,
260
+ current.startDate, current.endDate,
261
+ prior.startDate, prior.endDate,
262
+ current.startDate, current.endDate,
263
+ prior.startDate, prior.endDate,
264
+ prior.startDate, prior.endDate,
265
+ current.startDate, current.endDate,
266
+ prior.startDate, prior.endDate,
267
+ ...fv,
268
+ limit,
269
+ ]);
270
+ return { insight: 'growing_pages', dateRange: { current, prior }, rows };
271
+ },
272
+ declining_pages: (db, params, current, prior) => {
273
+ const limit = params.limit || 50;
274
+ const f = filterSQL(params);
275
+ const fv = filterValues(params);
276
+ const rows = db.query(`
277
+ SELECT page,
278
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as current_clicks,
279
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as prior_clicks,
280
+ SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
281
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END) as click_change,
282
+ ROUND(
283
+ (SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END)
284
+ - SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END))
285
+ * 100.0
286
+ / NULLIF(SUM(CASE WHEN date BETWEEN ? AND ? THEN clicks ELSE 0 END), 0),
287
+ 1
288
+ ) as pct_change
289
+ FROM search_analytics
290
+ WHERE page IS NOT NULL
291
+ AND (date BETWEEN ? AND ? OR date BETWEEN ? AND ?)${f}
292
+ GROUP BY page
293
+ HAVING prior_clicks > 0
294
+ ORDER BY click_change ASC
295
+ LIMIT ?
296
+ `, [
297
+ current.startDate, current.endDate,
298
+ prior.startDate, prior.endDate,
299
+ current.startDate, current.endDate,
300
+ prior.startDate, prior.endDate,
301
+ current.startDate, current.endDate,
302
+ prior.startDate, prior.endDate,
303
+ prior.startDate, prior.endDate,
304
+ current.startDate, current.endDate,
305
+ prior.startDate, prior.endDate,
306
+ ...fv,
307
+ limit,
308
+ ]);
309
+ return { insight: 'declining_pages', dateRange: { current, prior }, rows };
310
+ },
311
+ opportunities: (db, params, current, _prior) => {
312
+ const limit = params.limit || 50;
313
+ const minImpressions = params.minImpressions || 100;
314
+ const f = filterSQL(params);
315
+ const fv = filterValues(params);
316
+ const rows = db.query(`
317
+ SELECT query,
318
+ SUM(clicks) as clicks,
319
+ SUM(impressions) as impressions,
320
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
321
+ ROUND(AVG(position), 1) as avg_position
322
+ FROM search_analytics
323
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL${f}
324
+ GROUP BY query
325
+ HAVING avg_position BETWEEN 4 AND 20
326
+ AND impressions > ?
327
+ ORDER BY impressions DESC
328
+ LIMIT ?
329
+ `, [current.startDate, current.endDate, ...fv, minImpressions, limit]);
330
+ return { insight: 'opportunities', dateRange: current, rows };
331
+ },
332
+ device_breakdown: (db, params, current, _prior) => {
333
+ const f = filterSQL(params);
334
+ const fv = filterValues(params);
335
+ const rows = db.query(`
336
+ SELECT device,
337
+ SUM(clicks) as clicks,
338
+ SUM(impressions) as impressions,
339
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
340
+ ROUND(AVG(position), 1) as avg_position
341
+ FROM search_analytics
342
+ WHERE date BETWEEN ? AND ?${f}
343
+ GROUP BY device
344
+ ORDER BY clicks DESC
345
+ `, [current.startDate, current.endDate, ...fv]);
346
+ return { insight: 'device_breakdown', dateRange: current, rows };
347
+ },
348
+ country_breakdown: (db, params, current, _prior) => {
349
+ const limit = params.limit || 50;
350
+ const f = filterSQL(params);
351
+ const fv = filterValues(params);
352
+ const rows = db.query(`
353
+ SELECT country,
354
+ SUM(clicks) as clicks,
355
+ SUM(impressions) as impressions,
356
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
357
+ ROUND(AVG(position), 1) as avg_position
358
+ FROM search_analytics
359
+ WHERE date BETWEEN ? AND ?${f}
360
+ GROUP BY country
361
+ ORDER BY clicks DESC
362
+ LIMIT ?
363
+ `, [current.startDate, current.endDate, ...fv, limit]);
364
+ return { insight: 'country_breakdown', dateRange: current, rows };
365
+ },
366
+ page_queries: (db, params, current, _prior) => {
367
+ const limit = params.limit || 50;
368
+ if (!params.pageFilter) {
369
+ throw new Error('page_queries insight requires the "pageFilter" parameter.');
370
+ }
371
+ const fv = [];
372
+ let extraFilter = '';
373
+ if (params.device) {
374
+ extraFilter += ' AND device = ?';
375
+ fv.push(params.device);
376
+ }
377
+ if (params.country) {
378
+ extraFilter += ' AND country = ?';
379
+ fv.push(params.country);
380
+ }
381
+ const rows = db.query(`
382
+ SELECT query,
383
+ SUM(clicks) as clicks,
384
+ SUM(impressions) as impressions,
385
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
386
+ ROUND(AVG(position), 1) as avg_position
387
+ FROM search_analytics
388
+ WHERE page LIKE ? AND date BETWEEN ? AND ? AND query IS NOT NULL${extraFilter}
389
+ GROUP BY query
390
+ ORDER BY clicks DESC
391
+ LIMIT ?
392
+ `, [`%${params.pageFilter}%`, current.startDate, current.endDate, ...fv, limit]);
393
+ return { insight: 'page_queries', dateRange: current, pageFilter: params.pageFilter, rows };
394
+ },
395
+ query_pages: (db, params, current, _prior) => {
396
+ const limit = params.limit || 50;
397
+ if (!params.queryFilter) {
398
+ throw new Error('query_pages insight requires the "queryFilter" parameter.');
399
+ }
400
+ const fv = [];
401
+ let extraFilter = '';
402
+ if (params.device) {
403
+ extraFilter += ' AND device = ?';
404
+ fv.push(params.device);
405
+ }
406
+ if (params.country) {
407
+ extraFilter += ' AND country = ?';
408
+ fv.push(params.country);
409
+ }
410
+ const rows = db.query(`
411
+ SELECT page,
412
+ SUM(clicks) as clicks,
413
+ SUM(impressions) as impressions,
414
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
415
+ ROUND(AVG(position), 1) as avg_position
416
+ FROM search_analytics
417
+ WHERE query = ? AND date BETWEEN ? AND ? AND page IS NOT NULL${extraFilter}
418
+ GROUP BY page
419
+ ORDER BY avg_position ASC
420
+ LIMIT ?
421
+ `, [params.queryFilter, current.startDate, current.endDate, ...fv, limit]);
422
+ return { insight: 'query_pages', dateRange: current, queryFilter: params.queryFilter, rows };
423
+ },
424
+ daily_trend: (db, params, current, _prior) => {
425
+ const f = filterSQL(params);
426
+ const fv = filterValues(params);
427
+ const rows = db.query(`
428
+ SELECT date,
429
+ SUM(clicks) as clicks,
430
+ SUM(impressions) as impressions
431
+ FROM search_analytics
432
+ WHERE date BETWEEN ? AND ?${f}
433
+ GROUP BY date
434
+ ORDER BY date ASC
435
+ `, [current.startDate, current.endDate, ...fv]);
436
+ return { insight: 'daily_trend', dateRange: current, rows };
437
+ },
438
+ new_queries: (db, params, current, prior) => {
439
+ const limit = params.limit || 50;
440
+ const f = filterSQL(params);
441
+ const fv = filterValues(params);
442
+ const rows = db.query(`
443
+ SELECT query,
444
+ SUM(clicks) as clicks,
445
+ SUM(impressions) as impressions,
446
+ ROUND(AVG(position), 1) as avg_position
447
+ FROM search_analytics
448
+ WHERE date BETWEEN ? AND ?
449
+ AND query IS NOT NULL${f}
450
+ AND query IN (
451
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
452
+ EXCEPT
453
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
454
+ )
455
+ GROUP BY query
456
+ ORDER BY impressions DESC
457
+ LIMIT ?
458
+ `, [current.startDate, current.endDate, ...fv, current.startDate, current.endDate, prior.startDate, prior.endDate, limit]);
459
+ return { insight: 'new_queries', dateRange: { current, prior }, rows };
460
+ },
461
+ lost_queries: (db, params, current, prior) => {
462
+ const limit = params.limit || 50;
463
+ const f = filterSQL(params);
464
+ const fv = filterValues(params);
465
+ const rows = db.query(`
466
+ SELECT query,
467
+ SUM(clicks) as clicks,
468
+ SUM(impressions) as impressions,
469
+ ROUND(AVG(position), 1) as avg_position
470
+ FROM search_analytics
471
+ WHERE date BETWEEN ? AND ?
472
+ AND query IS NOT NULL${f}
473
+ AND query IN (
474
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
475
+ EXCEPT
476
+ SELECT query FROM search_analytics WHERE date BETWEEN ? AND ? AND query IS NOT NULL
477
+ )
478
+ GROUP BY query
479
+ ORDER BY clicks DESC
480
+ LIMIT ?
481
+ `, [prior.startDate, prior.endDate, ...fv, prior.startDate, prior.endDate, current.startDate, current.endDate, limit]);
482
+ return { insight: 'lost_queries', dateRange: { current, prior }, rows };
483
+ },
484
+ branded_split: (db, params, current, _prior) => {
485
+ if (!params.brandTerms || params.brandTerms.length === 0) {
486
+ throw new Error('branded_split insight requires the "brandTerms" parameter (array of brand terms).');
487
+ }
488
+ const f = filterSQL(params);
489
+ const fv = filterValues(params);
490
+ // Build CASE expression for brand matching
491
+ const brandConditions = params.brandTerms
492
+ .map(() => 'LOWER(query) LIKE ?')
493
+ .join(' OR ');
494
+ const brandValues = params.brandTerms.map((t) => `%${t.toLowerCase()}%`);
495
+ const rows = db.query(`
496
+ SELECT
497
+ CASE WHEN (${brandConditions}) THEN 'branded' ELSE 'non-branded' END as segment,
498
+ SUM(clicks) as clicks,
499
+ SUM(impressions) as impressions,
500
+ ROUND(CAST(SUM(clicks) AS REAL) / NULLIF(SUM(impressions), 0), 4) as ctr,
501
+ ROUND(AVG(position), 1) as avg_position
502
+ FROM search_analytics
503
+ WHERE date BETWEEN ? AND ? AND query IS NOT NULL${f}
504
+ GROUP BY segment
505
+ `, [...brandValues, current.startDate, current.endDate, ...fv]);
506
+ return { insight: 'branded_split', dateRange: current, brandTerms: params.brandTerms, rows };
507
+ },
508
+ };
509
+ //# sourceMappingURL=get-insights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-insights.js","sourceRoot":"","sources":["../../src/tools/get-insights.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { GscClient } from '../core/GscClient.js';
2
+ export interface OverviewParams {
3
+ dateRange?: string;
4
+ sortBy?: 'alpha' | 'clicks' | 'impressions' | 'ctr' | 'position';
5
+ search?: string;
6
+ }
7
+ interface PropertyOverview {
8
+ siteUrl: string;
9
+ domain: string;
10
+ lastSyncedAt: string | null;
11
+ current: {
12
+ clicks: number;
13
+ impressions: number;
14
+ ctr: number;
15
+ avgPosition: number | null;
16
+ };
17
+ changes: {
18
+ clicksPct: number | null;
19
+ impressionsPct: number | null;
20
+ ctrPct: number | null;
21
+ avgPositionPct: number | null;
22
+ };
23
+ sparkline: Array<{
24
+ date: string;
25
+ clicks: number;
26
+ impressions: number;
27
+ }>;
28
+ }
29
+ interface OverviewData {
30
+ dateRange: string;
31
+ sortBy: string;
32
+ properties: PropertyOverview[];
33
+ }
34
+ export declare function getOverviewData(gscClient: GscClient, params: OverviewParams): Promise<OverviewData>;
35
+ export {};
36
+ //# sourceMappingURL=get-overview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-overview.d.ts","sourceRoot":"","sources":["../../src/tools/get-overview.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIjD,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,KAAK,GAAG,UAAU,CAAC;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,CAAC;IACF,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzE;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,YAAY,CAAC,CAoHvB"}