@houtini/seo-audit-console 0.2.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 (166) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +211 -0
  3. package/dist/audit/checks.d.ts +35 -0
  4. package/dist/audit/checks.d.ts.map +1 -0
  5. package/dist/audit/checks.js +1475 -0
  6. package/dist/audit/checks.js.map +1 -0
  7. package/dist/audit/drift.d.ts +40 -0
  8. package/dist/audit/drift.d.ts.map +1 -0
  9. package/dist/audit/drift.js +148 -0
  10. package/dist/audit/drift.js.map +1 -0
  11. package/dist/audit/engine.d.ts +33 -0
  12. package/dist/audit/engine.d.ts.map +1 -0
  13. package/dist/audit/engine.js +186 -0
  14. package/dist/audit/engine.js.map +1 -0
  15. package/dist/audit/opportunities.d.ts +23 -0
  16. package/dist/audit/opportunities.d.ts.map +1 -0
  17. package/dist/audit/opportunities.js +149 -0
  18. package/dist/audit/opportunities.js.map +1 -0
  19. package/dist/audit/report.d.ts +11 -0
  20. package/dist/audit/report.d.ts.map +1 -0
  21. package/dist/audit/report.js +59 -0
  22. package/dist/audit/report.js.map +1 -0
  23. package/dist/audit/schema-validate.d.ts +35 -0
  24. package/dist/audit/schema-validate.d.ts.map +1 -0
  25. package/dist/audit/schema-validate.js +293 -0
  26. package/dist/audit/schema-validate.js.map +1 -0
  27. package/dist/audit/templates.d.ts +43 -0
  28. package/dist/audit/templates.d.ts.map +1 -0
  29. package/dist/audit/templates.js +129 -0
  30. package/dist/audit/templates.js.map +1 -0
  31. package/dist/audit/topicGaps.d.ts +42 -0
  32. package/dist/audit/topicGaps.d.ts.map +1 -0
  33. package/dist/audit/topicGaps.js +181 -0
  34. package/dist/audit/topicGaps.js.map +1 -0
  35. package/dist/core/AuditDatabase.d.ts +33 -0
  36. package/dist/core/AuditDatabase.d.ts.map +1 -0
  37. package/dist/core/AuditDatabase.js +481 -0
  38. package/dist/core/AuditDatabase.js.map +1 -0
  39. package/dist/core/Backlinks.d.ts +33 -0
  40. package/dist/core/Backlinks.d.ts.map +1 -0
  41. package/dist/core/Backlinks.js +110 -0
  42. package/dist/core/Backlinks.js.map +1 -0
  43. package/dist/core/Crawler.d.ts +23 -0
  44. package/dist/core/Crawler.d.ts.map +1 -0
  45. package/dist/core/Crawler.js +588 -0
  46. package/dist/core/Crawler.js.map +1 -0
  47. package/dist/core/DataForSeoClient.d.ts +86 -0
  48. package/dist/core/DataForSeoClient.d.ts.map +1 -0
  49. package/dist/core/DataForSeoClient.js +232 -0
  50. package/dist/core/DataForSeoClient.js.map +1 -0
  51. package/dist/core/Entities.d.ts +23 -0
  52. package/dist/core/Entities.d.ts.map +1 -0
  53. package/dist/core/Entities.js +62 -0
  54. package/dist/core/Entities.js.map +1 -0
  55. package/dist/core/GscClient.d.ts +22 -0
  56. package/dist/core/GscClient.d.ts.map +1 -0
  57. package/dist/core/GscClient.js +93 -0
  58. package/dist/core/GscClient.js.map +1 -0
  59. package/dist/core/GscSync.d.ts +20 -0
  60. package/dist/core/GscSync.d.ts.map +1 -0
  61. package/dist/core/GscSync.js +133 -0
  62. package/dist/core/GscSync.js.map +1 -0
  63. package/dist/core/JobManager.d.ts +30 -0
  64. package/dist/core/JobManager.d.ts.map +1 -0
  65. package/dist/core/JobManager.js +68 -0
  66. package/dist/core/JobManager.js.map +1 -0
  67. package/dist/core/RankTracker.d.ts +25 -0
  68. package/dist/core/RankTracker.d.ts.map +1 -0
  69. package/dist/core/RankTracker.js +78 -0
  70. package/dist/core/RankTracker.js.map +1 -0
  71. package/dist/core/Refresh.d.ts +32 -0
  72. package/dist/core/Refresh.d.ts.map +1 -0
  73. package/dist/core/Refresh.js +73 -0
  74. package/dist/core/Refresh.js.map +1 -0
  75. package/dist/core/UrlInspector.d.ts +22 -0
  76. package/dist/core/UrlInspector.d.ts.map +1 -0
  77. package/dist/core/UrlInspector.js +92 -0
  78. package/dist/core/UrlInspector.js.map +1 -0
  79. package/dist/core/WikidataClient.d.ts +19 -0
  80. package/dist/core/WikidataClient.d.ts.map +1 -0
  81. package/dist/core/WikidataClient.js +59 -0
  82. package/dist/core/WikidataClient.js.map +1 -0
  83. package/dist/core/agentReadiness.d.ts +34 -0
  84. package/dist/core/agentReadiness.d.ts.map +1 -0
  85. package/dist/core/agentReadiness.js +119 -0
  86. package/dist/core/agentReadiness.js.map +1 -0
  87. package/dist/core/ctrModel.d.ts +2 -0
  88. package/dist/core/ctrModel.d.ts.map +1 -0
  89. package/dist/core/ctrModel.js +6 -0
  90. package/dist/core/ctrModel.js.map +1 -0
  91. package/dist/core/dashboardData.d.ts +312 -0
  92. package/dist/core/dashboardData.d.ts.map +1 -0
  93. package/dist/core/dashboardData.js +550 -0
  94. package/dist/core/dashboardData.js.map +1 -0
  95. package/dist/core/dataStorage.d.ts +42 -0
  96. package/dist/core/dataStorage.d.ts.map +1 -0
  97. package/dist/core/dataStorage.js +193 -0
  98. package/dist/core/dataStorage.js.map +1 -0
  99. package/dist/core/draftBrief.d.ts +27 -0
  100. package/dist/core/draftBrief.d.ts.map +1 -0
  101. package/dist/core/draftBrief.js +69 -0
  102. package/dist/core/draftBrief.js.map +1 -0
  103. package/dist/core/extract.d.ts +67 -0
  104. package/dist/core/extract.d.ts.map +1 -0
  105. package/dist/core/extract.js +262 -0
  106. package/dist/core/extract.js.map +1 -0
  107. package/dist/core/gscFreshness.d.ts +18 -0
  108. package/dist/core/gscFreshness.d.ts.map +1 -0
  109. package/dist/core/gscFreshness.js +32 -0
  110. package/dist/core/gscFreshness.js.map +1 -0
  111. package/dist/core/linkGraph.d.ts +19 -0
  112. package/dist/core/linkGraph.d.ts.map +1 -0
  113. package/dist/core/linkGraph.js +125 -0
  114. package/dist/core/linkGraph.js.map +1 -0
  115. package/dist/core/passageScore.d.ts +19 -0
  116. package/dist/core/passageScore.d.ts.map +1 -0
  117. package/dist/core/passageScore.js +59 -0
  118. package/dist/core/passageScore.js.map +1 -0
  119. package/dist/core/paths.d.ts +5 -0
  120. package/dist/core/paths.d.ts.map +1 -0
  121. package/dist/core/paths.js +15 -0
  122. package/dist/core/paths.js.map +1 -0
  123. package/dist/core/queryData.d.ts +35 -0
  124. package/dist/core/queryData.d.ts.map +1 -0
  125. package/dist/core/queryData.js +200 -0
  126. package/dist/core/queryData.js.map +1 -0
  127. package/dist/core/reranker.d.ts +8 -0
  128. package/dist/core/reranker.d.ts.map +1 -0
  129. package/dist/core/reranker.js +68 -0
  130. package/dist/core/reranker.js.map +1 -0
  131. package/dist/core/robots.d.ts +11 -0
  132. package/dist/core/robots.d.ts.map +1 -0
  133. package/dist/core/robots.js +76 -0
  134. package/dist/core/robots.js.map +1 -0
  135. package/dist/core/sitemap.d.ts +15 -0
  136. package/dist/core/sitemap.d.ts.map +1 -0
  137. package/dist/core/sitemap.js +100 -0
  138. package/dist/core/sitemap.js.map +1 -0
  139. package/dist/core/sql.d.ts +6 -0
  140. package/dist/core/sql.d.ts.map +1 -0
  141. package/dist/core/sql.js +6 -0
  142. package/dist/core/sql.js.map +1 -0
  143. package/dist/core/types.d.ts +22 -0
  144. package/dist/core/types.d.ts.map +1 -0
  145. package/dist/core/types.js +2 -0
  146. package/dist/core/types.js.map +1 -0
  147. package/dist/core/url-key.d.ts +39 -0
  148. package/dist/core/url-key.d.ts.map +1 -0
  149. package/dist/core/url-key.js +106 -0
  150. package/dist/core/url-key.js.map +1 -0
  151. package/dist/generators/index.d.ts +45 -0
  152. package/dist/generators/index.d.ts.map +1 -0
  153. package/dist/generators/index.js +184 -0
  154. package/dist/generators/index.js.map +1 -0
  155. package/dist/index.d.ts +3 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +10 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/server.d.ts +7 -0
  160. package/dist/server.d.ts.map +1 -0
  161. package/dist/server.js +1387 -0
  162. package/dist/server.js.map +1 -0
  163. package/dist/src/ui/dashboard.html +347 -0
  164. package/dist/src/ui/sync-progress.html +104 -0
  165. package/package.json +101 -0
  166. package/server.json +57 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-validate.js","sourceRoot":"","sources":["../../src/audit/schema-validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type Database from 'better-sqlite3';
2
+ /**
3
+ * Template detection (Phase 6b). Clusters a site's pages into templates so a single
4
+ * template-level fix can be reasoned about as fixing N pages at once.
5
+ *
6
+ * Tripartite key (from the "how SEOs audit" conversation): URL morphology + JSON-LD
7
+ * root @type + DOM-skeleton similarity. The first two are computable from data we
8
+ * already store (pages.url, pages.json_ld) — that's what we cluster on here. The
9
+ * DOM-skeleton LSH is a future refinement (needs a structural signature captured at
10
+ * crawl time); url-morphology + @type already separates most real templates cleanly.
11
+ */
12
+ export interface TemplateCluster {
13
+ templateKey: string;
14
+ morphology: string;
15
+ schemaType: string;
16
+ count: number;
17
+ exemplarUrlKey: string;
18
+ exemplarUrl: string;
19
+ memberKeys: string[];
20
+ }
21
+ /** URL → structural morphology: numerics→[NUM], identifier slugs→[SLUG] (extension kept), section names literal, param keys sorted, values dropped. */
22
+ export declare function urlMorphology(rawUrl: string): string;
23
+ /**
24
+ * Parse the stored `json_ld` column into JSON-LD node objects. The column is a JSON array of
25
+ * RAW BLOCK STRINGS (one per <script type=application/ld+json>, see extract.ts) — so we parse
26
+ * the array, then parse each string, flattening @graph. Tolerates an array of already-parsed
27
+ * objects too (defensive). Returns [] on anything unparseable.
28
+ */
29
+ export declare function parseJsonLdNodes(col: string | null): any[];
30
+ /** First concrete @type of a node (handles @type-as-array). */
31
+ export declare function nodeType(node: any): string | null;
32
+ /** Raw JSON-LD column → root @type, else 'None'. */
33
+ export declare function jsonLdType(jsonLd: string | null): string;
34
+ /**
35
+ * Detect templates. minMembers (default 4) filters singletons (home/about/contact) to
36
+ * per-URL analysis. The exemplar is the MEDIAN-word-count healthy (200 + indexable +
37
+ * linked) page so per-template analysis runs on a representative, not an edge case.
38
+ */
39
+ export declare function detectTemplates(db: Database.Database, opts?: {
40
+ minMembers?: number;
41
+ memberCap?: number;
42
+ }): TemplateCluster[];
43
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/audit/templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AASD,uJAAuJ;AACvJ,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgBpD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,GAAG,EAAE,CAiB1D;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAGjD;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGxD;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,eAAe,EAAE,CAoChI"}
@@ -0,0 +1,129 @@
1
+ // A segment is a variable IDENTIFIER (→ [SLUG]) if it looks like a slug/id rather than a
2
+ // stable section name: contains a hyphen or digit, or is unusually long. Short clean words
3
+ // (product, blog, category, en) stay literal so /product/[SLUG] ≠ /blog/[SLUG].
4
+ // (Limitation: single-word slugs with no hyphen/digit stay literal and can fragment a cluster;
5
+ // positional-variability analysis is the future refinement.)
6
+ const isIdentifier = (name) => /[-_]/.test(name) || /\d/.test(name) || name.length > 24;
7
+ /** URL → structural morphology: numerics→[NUM], identifier slugs→[SLUG] (extension kept), section names literal, param keys sorted, values dropped. */
8
+ export function urlMorphology(rawUrl) {
9
+ let u;
10
+ try {
11
+ u = new URL(rawUrl);
12
+ }
13
+ catch {
14
+ return rawUrl;
15
+ }
16
+ const segs = u.pathname.split('/').filter(Boolean).map(seg => {
17
+ if (/^\d+$/.test(seg))
18
+ return '[NUM]';
19
+ const dot = seg.lastIndexOf('.');
20
+ if (dot > 0 && dot < seg.length - 1) {
21
+ const ext = seg.slice(dot + 1).toLowerCase();
22
+ const name = seg.slice(0, dot);
23
+ if (/^[a-z0-9]{1,5}$/.test(ext))
24
+ return isIdentifier(name) ? `[SLUG].${ext}` : seg;
25
+ }
26
+ return isIdentifier(seg) ? '[SLUG]' : seg;
27
+ });
28
+ const path = '/' + segs.join('/');
29
+ const params = [...new Set([...u.searchParams.keys()].map(k => k.toLowerCase()))].sort();
30
+ return path + (params.length ? '?' + params.join('&') : '');
31
+ }
32
+ /**
33
+ * Parse the stored `json_ld` column into JSON-LD node objects. The column is a JSON array of
34
+ * RAW BLOCK STRINGS (one per <script type=application/ld+json>, see extract.ts) — so we parse
35
+ * the array, then parse each string, flattening @graph. Tolerates an array of already-parsed
36
+ * objects too (defensive). Returns [] on anything unparseable.
37
+ */
38
+ export function parseJsonLdNodes(col) {
39
+ if (!col)
40
+ return [];
41
+ let blocks;
42
+ try {
43
+ blocks = JSON.parse(col);
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ const raws = Array.isArray(blocks) ? blocks : [blocks];
49
+ const nodes = [];
50
+ for (const raw of raws) {
51
+ let obj;
52
+ if (typeof raw === 'string') {
53
+ try {
54
+ obj = JSON.parse(raw);
55
+ }
56
+ catch {
57
+ continue;
58
+ }
59
+ }
60
+ else
61
+ obj = raw; // already an object (defensive)
62
+ for (const o of Array.isArray(obj) ? obj : [obj]) {
63
+ if (!o || typeof o !== 'object')
64
+ continue;
65
+ if (Array.isArray(o['@graph']))
66
+ nodes.push(...o['@graph']);
67
+ else
68
+ nodes.push(o);
69
+ }
70
+ }
71
+ return nodes;
72
+ }
73
+ /** First concrete @type of a node (handles @type-as-array). */
74
+ export function nodeType(node) {
75
+ const t = node?.['@type'];
76
+ return Array.isArray(t) ? (t[0] != null ? String(t[0]) : null) : t != null ? String(t) : null;
77
+ }
78
+ /** Raw JSON-LD column → root @type, else 'None'. */
79
+ export function jsonLdType(jsonLd) {
80
+ for (const n of parseJsonLdNodes(jsonLd)) {
81
+ const t = nodeType(n);
82
+ if (t)
83
+ return t;
84
+ }
85
+ return 'None';
86
+ }
87
+ /**
88
+ * Detect templates. minMembers (default 4) filters singletons (home/about/contact) to
89
+ * per-URL analysis. The exemplar is the MEDIAN-word-count healthy (200 + indexable +
90
+ * linked) page so per-template analysis runs on a representative, not an edge case.
91
+ */
92
+ export function detectTemplates(db, opts = {}) {
93
+ const minMembers = opts.minMembers ?? 4;
94
+ const memberCap = opts.memberCap ?? 500;
95
+ const pages = db.prepare(`SELECT url_key, url, status_code, indexable, word_count, inlink_count, json_ld FROM pages WHERE is_internal IS NOT 0`).all();
96
+ const groups = new Map();
97
+ for (const p of pages) {
98
+ const morphology = urlMorphology(p.url);
99
+ const schemaType = jsonLdType(p.json_ld);
100
+ const key = `${morphology}|${schemaType}`;
101
+ let g = groups.get(key);
102
+ if (!g) {
103
+ g = { morphology, schemaType, members: [] };
104
+ groups.set(key, g);
105
+ }
106
+ g.members.push(p);
107
+ }
108
+ const clusters = [];
109
+ for (const [key, g] of groups) {
110
+ if (g.members.length < minMembers)
111
+ continue;
112
+ // Exemplar: median word_count among healthy pages; fall back to median of all members.
113
+ const healthy = g.members.filter(m => m.status_code === 200 && m.indexable === 1 && (m.inlink_count ?? 0) > 0);
114
+ const pool = healthy.length ? healthy : g.members;
115
+ const sorted = [...pool].sort((a, b) => (a.word_count ?? 0) - (b.word_count ?? 0));
116
+ const exemplar = sorted[Math.floor(sorted.length / 2)];
117
+ clusters.push({
118
+ templateKey: key,
119
+ morphology: g.morphology,
120
+ schemaType: g.schemaType,
121
+ count: g.members.length,
122
+ exemplarUrlKey: exemplar.url_key,
123
+ exemplarUrl: exemplar.url,
124
+ memberKeys: g.members.slice(0, memberCap).map(m => m.url_key),
125
+ });
126
+ }
127
+ return clusters.sort((a, b) => b.count - a.count);
128
+ }
129
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/audit/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type Database from 'better-sqlite3';
2
+ /** One competitor keyword row (normalised from a Labs ranked_keywords item by the caller). */
3
+ export interface GapKeywordRow {
4
+ keyword: string;
5
+ searchVolume: number | null;
6
+ etv: number | null;
7
+ position: number | null;
8
+ url: string | null;
9
+ competitor: string;
10
+ }
11
+ export interface TopicCluster {
12
+ headTerm: string;
13
+ totalVolume: number;
14
+ competitorCoverage: number;
15
+ score: number;
16
+ ownedBy: string;
17
+ exampleUrl: string | null;
18
+ keywords: {
19
+ keyword: string;
20
+ searchVolume: number | null;
21
+ competitor: string;
22
+ }[];
23
+ nearestExistingPage: {
24
+ url: string;
25
+ title: string | null;
26
+ } | null;
27
+ entityNote: string | null;
28
+ why: string;
29
+ }
30
+ export interface TopicGapsResult {
31
+ clusters: TopicCluster[];
32
+ competitorKeywords: number;
33
+ ourQueryCount: number;
34
+ afterSubtraction: number;
35
+ }
36
+ interface Opts {
37
+ limit?: number;
38
+ clusterThreshold?: number;
39
+ }
40
+ export declare function computeTopicGaps(db: Database.Database, rows: GapKeywordRow[], opts?: Opts): TopicGapsResult;
41
+ export {};
42
+ //# sourceMappingURL=topicGaps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topicGaps.d.ts","sourceRoot":"","sources":["../../src/audit/topicGaps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAyB3C,8FAA8F;AAC9F,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjF,mBAAmB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAClE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,IAAI;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE;AAE5D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,IAAI,GAAE,IAAS,GAAG,eAAe,CAyI/G"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Topic-gap engine — "what related topics should this site cover to be expert in its
3
+ * space?" Competitor keyword footprints (DataForSEO Labs ranked_keywords, fetched by
4
+ * the caller — this module makes NO paid calls) minus OUR footprint:
5
+ * A. every distinct query we already earn impressions for in search_analytics, and
6
+ * B. lexical near-matches against our page titles / H1s / slugs (≥70% token cover),
7
+ * then the survivors are clustered lexically (same tokenise + greedy-Jaccard approach
8
+ * as opportunities.ts) and scored by summed search volume × competitor coverage.
9
+ * If the entity layer is populated (page_entity + entity_edge), clusters whose terms
10
+ * sit beside entities we already cover are annotated — stored edges only, no live
11
+ * Wikidata calls.
12
+ */
13
+ const STOP = new Set(['the', 'a', 'an', 'and', 'or', 'of', 'for', 'to', 'in', 'on', 'with', 'your', 'you', 'is', 'are', 'best', 'how', 'what', 'vs', 'why', 'can', 'my', 'i', 'it']);
14
+ const tokenize = (s) => (s || '').toLowerCase().replace(/[^a-z0-9 ]+/g, ' ').split(/\s+/).filter(t => t.length >= 2 && !STOP.has(t));
15
+ const jaccard = (a, b) => {
16
+ if (!a.size || !b.size)
17
+ return 0;
18
+ let inter = 0;
19
+ for (const x of a)
20
+ if (b.has(x))
21
+ inter++;
22
+ return inter / (a.size + b.size - inter);
23
+ };
24
+ export function computeTopicGaps(db, rows, opts = {}) {
25
+ const limit = opts.limit ?? 15;
26
+ const clusterT = opts.clusterThreshold ?? 0.5;
27
+ // ── OUR footprint, part A: every distinct query we already get impressions for.
28
+ const ourQueries = new Set();
29
+ for (const r of db.prepare(`SELECT DISTINCT lower(query) q FROM search_analytics WHERE query IS NOT NULL AND impressions > 0`).iterate())
30
+ ourQueries.add(r.q);
31
+ // ── OUR footprint, part B: page vocabulary (title + H1 + slug) → inverted index,
32
+ // same 70%-coverage subtraction as opportunities.ts.
33
+ const pages = db.prepare(`SELECT url_key, url, title, h1 FROM pages WHERE status_code = 200`).all();
34
+ const pageTokens = pages.map(p => {
35
+ const slug = (() => { try {
36
+ return decodeURIComponent(new URL(p.url).pathname).replace(/[-_/]+/g, ' ');
37
+ }
38
+ catch {
39
+ return '';
40
+ } })();
41
+ return { url: p.url, title: p.title, toks: new Set(tokenize(`${p.title ?? ''} ${p.h1 ?? ''} ${slug}`)) };
42
+ });
43
+ const invIndex = new Map();
44
+ pageTokens.forEach((pt, i) => { for (const t of pt.toks)
45
+ (invIndex.get(t) ?? invIndex.set(t, []).get(t)).push(i); });
46
+ const bestPageCover = (toks) => {
47
+ const hits = new Map();
48
+ for (const t of toks)
49
+ for (const i of invIndex.get(t) ?? [])
50
+ hits.set(i, (hits.get(i) ?? 0) + 1);
51
+ let cover = 0, idx = -1;
52
+ for (const [i, n] of hits) {
53
+ const c = n / Math.max(toks.length, 1);
54
+ if (c > cover) {
55
+ cover = c;
56
+ idx = i;
57
+ }
58
+ }
59
+ return { cover, idx };
60
+ };
61
+ const byKeyword = new Map();
62
+ for (const r of rows) {
63
+ const kw = r.keyword.trim().toLowerCase();
64
+ if (!kw)
65
+ continue;
66
+ let m = byKeyword.get(kw);
67
+ if (!m) {
68
+ m = { keyword: kw, toks: tokenize(kw), volume: 0, byCompetitor: new Map() };
69
+ byKeyword.set(kw, m);
70
+ }
71
+ m.volume = Math.max(m.volume, r.searchVolume ?? 0);
72
+ const prev = m.byCompetitor.get(r.competitor);
73
+ if (!prev || (r.searchVolume ?? 0) >= prev.volume)
74
+ m.byCompetitor.set(r.competitor, { volume: r.searchVolume ?? 0, url: r.url ?? prev?.url ?? null });
75
+ }
76
+ // ── Subtraction: drop what we already have (GSC query, or a page that near-covers it).
77
+ const survivors = [];
78
+ for (const m of byKeyword.values()) {
79
+ if (!m.toks.length)
80
+ continue;
81
+ if (ourQueries.has(m.keyword))
82
+ continue; // A: we already surface for it
83
+ if (bestPageCover(m.toks).cover >= 0.7)
84
+ continue; // B: an existing page near-covers it
85
+ survivors.push(m);
86
+ }
87
+ // ── Cluster survivors lexically (greedy Jaccard, volume-first so heads are the big terms).
88
+ survivors.sort((a, b) => b.volume - a.volume);
89
+ const clusters = [];
90
+ for (const s of survivors) {
91
+ const st = new Set(s.toks);
92
+ const c = clusters.find(c => jaccard(st, c.toks) >= clusterT);
93
+ if (c) {
94
+ c.members.push(s);
95
+ for (const t of s.toks)
96
+ c.toks.add(t);
97
+ }
98
+ else
99
+ clusters.push({ head: s, toks: new Set(s.toks), members: [s] });
100
+ }
101
+ // ── Entity adjacency (stored data only): our covered entities that share a parent —
102
+ // a cluster matching one of those labels slots into a topic family we already cover.
103
+ const entityLabels = [];
104
+ try {
105
+ const covered = db.prepare(`SELECT url_key, qid, label FROM page_entity WHERE label IS NOT NULL`).all();
106
+ if (covered.length) {
107
+ const coveredQids = new Set(covered.map(c => c.qid));
108
+ const edges = db.prepare(`SELECT qid, related_qid FROM entity_edge`).all();
109
+ const parentsCovered = new Set(edges.filter(e => coveredQids.has(e.qid)).map(e => e.related_qid));
110
+ const siblingQids = new Set(edges.filter(e => parentsCovered.has(e.related_qid)).map(e => e.qid));
111
+ for (const c of covered) {
112
+ if (!siblingQids.has(c.qid))
113
+ continue;
114
+ const toks = new Set(tokenize(c.label));
115
+ if (toks.size)
116
+ entityLabels.push({ label: c.label, toks, qid: c.qid });
117
+ }
118
+ }
119
+ }
120
+ catch { /* entity tables absent on old DBs — annotation simply skipped */ }
121
+ const entityNoteFor = (clusterToks) => {
122
+ let best = null;
123
+ for (const e of entityLabels) {
124
+ let inter = 0;
125
+ for (const t of e.toks)
126
+ if (clusterToks.has(t))
127
+ inter++;
128
+ const overlap = inter / e.toks.size;
129
+ if (overlap >= 0.5 && (!best || overlap > best.overlap))
130
+ best = { label: e.label, overlap };
131
+ }
132
+ return best ? `sits beside "${best.label}" in your entity graph (shared parent topic already covered)` : null;
133
+ };
134
+ // ── Score + shape the output clusters.
135
+ const out = clusters.map(c => {
136
+ const volByCompetitor = new Map();
137
+ let totalVolume = 0;
138
+ for (const m of c.members) {
139
+ totalVolume += m.volume;
140
+ for (const [comp, v] of m.byCompetitor)
141
+ volByCompetitor.set(comp, (volByCompetitor.get(comp) ?? 0) + v.volume);
142
+ }
143
+ const coverage = volByCompetitor.size;
144
+ const ownedBy = [...volByCompetitor.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';
145
+ // Example URL: the owner's URL for the head term, else the owner's highest-volume member.
146
+ const exampleUrl = c.head.byCompetitor.get(ownedBy)?.url ??
147
+ c.members.map(m => m.byCompetitor.get(ownedBy)?.url).find(u => u != null) ?? null;
148
+ const near = bestPageCover([...c.toks]);
149
+ const nearest = near.idx >= 0 && near.cover > 0
150
+ ? { url: pageTokens[near.idx].url, title: pageTokens[near.idx].title }
151
+ : null;
152
+ const keywords = c.members
153
+ .map(m => ({
154
+ keyword: m.keyword,
155
+ searchVolume: m.volume || null,
156
+ competitor: [...m.byCompetitor.entries()].sort((a, b) => b[1].volume - a[1].volume)[0]?.[0] ?? ownedBy,
157
+ }));
158
+ const why = `${ownedBy} ranks for ${c.members.length} keyword${c.members.length === 1 ? '' : 's'} here (~${totalVolume.toLocaleString('en-US')}/mo searches${coverage > 1 ? `, ${coverage} competitors present` : ''}) and you currently surface for none of them.`;
159
+ return {
160
+ headTerm: c.head.keyword,
161
+ totalVolume,
162
+ competitorCoverage: coverage,
163
+ score: totalVolume * Math.max(coverage, 1),
164
+ ownedBy,
165
+ exampleUrl,
166
+ keywords,
167
+ nearestExistingPage: nearest,
168
+ entityNote: entityNoteFor(c.toks),
169
+ why,
170
+ };
171
+ })
172
+ .sort((a, b) => b.score - a.score)
173
+ .slice(0, limit);
174
+ return {
175
+ clusters: out,
176
+ competitorKeywords: byKeyword.size,
177
+ ourQueryCount: ourQueries.size,
178
+ afterSubtraction: survivors.length,
179
+ };
180
+ }
181
+ //# sourceMappingURL=topicGaps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topicGaps.js","sourceRoot":"","sources":["../../src/audit/topicGaps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * AuditDatabase — one SQLite database per GSC property, colocating:
3
+ * - GSC history (search_analytics) ← from better-search-console
4
+ * - crawl snapshot (crawl_metadata, pages, links, errors) ← from seo-crawler-mcp
5
+ * - audit results (audit_runs, findings) ← new
6
+ *
7
+ * The join spine is the normalised URL key (`page_key` / `url_key`), written by
8
+ * url-key.ts on both the GSC and crawl write paths. See plan/architecture §2.
9
+ *
10
+ * Never console.log — MCP speaks JSON-RPC over stdio; use console.error for debug.
11
+ */
12
+ import Database from 'better-sqlite3';
13
+ export type FindingLabel = 'D' | 'N' | 'L' | 'G' | 'S';
14
+ export type Severity = 'crit' | 'high' | 'med' | 'low' | 'info';
15
+ export declare class AuditDatabase {
16
+ readonly db: Database.Database;
17
+ constructor(dbPath: string);
18
+ private initializeTables;
19
+ /** Idempotent column additions for DBs created before a column existed. */
20
+ private migrate;
21
+ upsertProperty(siteUrl: string, hostForm: string, permissionLevel?: string): void;
22
+ getProperty(siteUrl: string): {
23
+ site_url: string;
24
+ host_form: string;
25
+ last_synced_at: string | null;
26
+ } | undefined;
27
+ /** Persist the DataForSEO target location for a property (string name or numeric code). */
28
+ setDfsLocation(siteUrl: string, location: string | number): void;
29
+ /** Resolved DataForSEO location for a property: a code, a name, or undefined. */
30
+ getDfsLocation(siteUrl: string): string | number | undefined;
31
+ close(): void;
32
+ }
33
+ //# sourceMappingURL=AuditDatabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuditDatabase.d.ts","sourceRoot":"","sources":["../../src/core/AuditDatabase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,MAAM,MAAM,YAAY,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACvD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAEhE,qBAAa,aAAa;IACxB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;gBAEnB,MAAM,EAAE,MAAM;IAgB1B,OAAO,CAAC,gBAAgB;IAgYxB,2EAA2E;IAC3E,OAAO,CAAC,OAAO;IAyDf,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI;IAWjF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS;IAMhH,2FAA2F;IAC3F,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMhE,iFAAiF;IACjF,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS;IAO5D,KAAK,IAAI,IAAI;CAGd"}