@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.
- package/LICENSE +92 -0
- package/README.md +211 -0
- package/dist/audit/checks.d.ts +35 -0
- package/dist/audit/checks.d.ts.map +1 -0
- package/dist/audit/checks.js +1475 -0
- package/dist/audit/checks.js.map +1 -0
- package/dist/audit/drift.d.ts +40 -0
- package/dist/audit/drift.d.ts.map +1 -0
- package/dist/audit/drift.js +148 -0
- package/dist/audit/drift.js.map +1 -0
- package/dist/audit/engine.d.ts +33 -0
- package/dist/audit/engine.d.ts.map +1 -0
- package/dist/audit/engine.js +186 -0
- package/dist/audit/engine.js.map +1 -0
- package/dist/audit/opportunities.d.ts +23 -0
- package/dist/audit/opportunities.d.ts.map +1 -0
- package/dist/audit/opportunities.js +149 -0
- package/dist/audit/opportunities.js.map +1 -0
- package/dist/audit/report.d.ts +11 -0
- package/dist/audit/report.d.ts.map +1 -0
- package/dist/audit/report.js +59 -0
- package/dist/audit/report.js.map +1 -0
- package/dist/audit/schema-validate.d.ts +35 -0
- package/dist/audit/schema-validate.d.ts.map +1 -0
- package/dist/audit/schema-validate.js +293 -0
- package/dist/audit/schema-validate.js.map +1 -0
- package/dist/audit/templates.d.ts +43 -0
- package/dist/audit/templates.d.ts.map +1 -0
- package/dist/audit/templates.js +129 -0
- package/dist/audit/templates.js.map +1 -0
- package/dist/audit/topicGaps.d.ts +42 -0
- package/dist/audit/topicGaps.d.ts.map +1 -0
- package/dist/audit/topicGaps.js +181 -0
- package/dist/audit/topicGaps.js.map +1 -0
- package/dist/core/AuditDatabase.d.ts +33 -0
- package/dist/core/AuditDatabase.d.ts.map +1 -0
- package/dist/core/AuditDatabase.js +481 -0
- package/dist/core/AuditDatabase.js.map +1 -0
- package/dist/core/Backlinks.d.ts +33 -0
- package/dist/core/Backlinks.d.ts.map +1 -0
- package/dist/core/Backlinks.js +110 -0
- package/dist/core/Backlinks.js.map +1 -0
- package/dist/core/Crawler.d.ts +23 -0
- package/dist/core/Crawler.d.ts.map +1 -0
- package/dist/core/Crawler.js +588 -0
- package/dist/core/Crawler.js.map +1 -0
- package/dist/core/DataForSeoClient.d.ts +86 -0
- package/dist/core/DataForSeoClient.d.ts.map +1 -0
- package/dist/core/DataForSeoClient.js +232 -0
- package/dist/core/DataForSeoClient.js.map +1 -0
- package/dist/core/Entities.d.ts +23 -0
- package/dist/core/Entities.d.ts.map +1 -0
- package/dist/core/Entities.js +62 -0
- package/dist/core/Entities.js.map +1 -0
- package/dist/core/GscClient.d.ts +22 -0
- package/dist/core/GscClient.d.ts.map +1 -0
- package/dist/core/GscClient.js +93 -0
- package/dist/core/GscClient.js.map +1 -0
- package/dist/core/GscSync.d.ts +20 -0
- package/dist/core/GscSync.d.ts.map +1 -0
- package/dist/core/GscSync.js +133 -0
- package/dist/core/GscSync.js.map +1 -0
- package/dist/core/JobManager.d.ts +30 -0
- package/dist/core/JobManager.d.ts.map +1 -0
- package/dist/core/JobManager.js +68 -0
- package/dist/core/JobManager.js.map +1 -0
- package/dist/core/RankTracker.d.ts +25 -0
- package/dist/core/RankTracker.d.ts.map +1 -0
- package/dist/core/RankTracker.js +78 -0
- package/dist/core/RankTracker.js.map +1 -0
- package/dist/core/Refresh.d.ts +32 -0
- package/dist/core/Refresh.d.ts.map +1 -0
- package/dist/core/Refresh.js +73 -0
- package/dist/core/Refresh.js.map +1 -0
- package/dist/core/UrlInspector.d.ts +22 -0
- package/dist/core/UrlInspector.d.ts.map +1 -0
- package/dist/core/UrlInspector.js +92 -0
- package/dist/core/UrlInspector.js.map +1 -0
- package/dist/core/WikidataClient.d.ts +19 -0
- package/dist/core/WikidataClient.d.ts.map +1 -0
- package/dist/core/WikidataClient.js +59 -0
- package/dist/core/WikidataClient.js.map +1 -0
- package/dist/core/agentReadiness.d.ts +34 -0
- package/dist/core/agentReadiness.d.ts.map +1 -0
- package/dist/core/agentReadiness.js +119 -0
- package/dist/core/agentReadiness.js.map +1 -0
- package/dist/core/ctrModel.d.ts +2 -0
- package/dist/core/ctrModel.d.ts.map +1 -0
- package/dist/core/ctrModel.js +6 -0
- package/dist/core/ctrModel.js.map +1 -0
- package/dist/core/dashboardData.d.ts +312 -0
- package/dist/core/dashboardData.d.ts.map +1 -0
- package/dist/core/dashboardData.js +550 -0
- package/dist/core/dashboardData.js.map +1 -0
- package/dist/core/dataStorage.d.ts +42 -0
- package/dist/core/dataStorage.d.ts.map +1 -0
- package/dist/core/dataStorage.js +193 -0
- package/dist/core/dataStorage.js.map +1 -0
- package/dist/core/draftBrief.d.ts +27 -0
- package/dist/core/draftBrief.d.ts.map +1 -0
- package/dist/core/draftBrief.js +69 -0
- package/dist/core/draftBrief.js.map +1 -0
- package/dist/core/extract.d.ts +67 -0
- package/dist/core/extract.d.ts.map +1 -0
- package/dist/core/extract.js +262 -0
- package/dist/core/extract.js.map +1 -0
- package/dist/core/gscFreshness.d.ts +18 -0
- package/dist/core/gscFreshness.d.ts.map +1 -0
- package/dist/core/gscFreshness.js +32 -0
- package/dist/core/gscFreshness.js.map +1 -0
- package/dist/core/linkGraph.d.ts +19 -0
- package/dist/core/linkGraph.d.ts.map +1 -0
- package/dist/core/linkGraph.js +125 -0
- package/dist/core/linkGraph.js.map +1 -0
- package/dist/core/passageScore.d.ts +19 -0
- package/dist/core/passageScore.d.ts.map +1 -0
- package/dist/core/passageScore.js +59 -0
- package/dist/core/passageScore.js.map +1 -0
- package/dist/core/paths.d.ts +5 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +15 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/queryData.d.ts +35 -0
- package/dist/core/queryData.d.ts.map +1 -0
- package/dist/core/queryData.js +200 -0
- package/dist/core/queryData.js.map +1 -0
- package/dist/core/reranker.d.ts +8 -0
- package/dist/core/reranker.d.ts.map +1 -0
- package/dist/core/reranker.js +68 -0
- package/dist/core/reranker.js.map +1 -0
- package/dist/core/robots.d.ts +11 -0
- package/dist/core/robots.d.ts.map +1 -0
- package/dist/core/robots.js +76 -0
- package/dist/core/robots.js.map +1 -0
- package/dist/core/sitemap.d.ts +15 -0
- package/dist/core/sitemap.d.ts.map +1 -0
- package/dist/core/sitemap.js +100 -0
- package/dist/core/sitemap.js.map +1 -0
- package/dist/core/sql.d.ts +6 -0
- package/dist/core/sql.d.ts.map +1 -0
- package/dist/core/sql.js +6 -0
- package/dist/core/sql.js.map +1 -0
- package/dist/core/types.d.ts +22 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/url-key.d.ts +39 -0
- package/dist/core/url-key.d.ts.map +1 -0
- package/dist/core/url-key.js +106 -0
- package/dist/core/url-key.js.map +1 -0
- package/dist/generators/index.d.ts +45 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +184 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1387 -0
- package/dist/server.js.map +1 -0
- package/dist/src/ui/dashboard.html +347 -0
- package/dist/src/ui/sync-progress.html +104 -0
- package/package.json +101 -0
- package/server.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* url-key — the single source of truth for the join between GSC data and crawl data.
|
|
3
|
+
*
|
|
4
|
+
* GSC stores Google-canonicalised URLs; the crawler stores raw discovered URLs.
|
|
5
|
+
* Neither normalises, and they normalise differently — so a naive `page = url`
|
|
6
|
+
* join silently misses trailing-slash / www / protocol / tracking-param variants.
|
|
7
|
+
* Both write paths run their URL through `urlKey()` and store the result in a
|
|
8
|
+
* `*_key` column; all joins use the key. The raw URL is kept for evidence, and
|
|
9
|
+
* raw-vs-key divergence (esp. canonical mismatch) is itself a finding.
|
|
10
|
+
*
|
|
11
|
+
* See research/05 (normalisation pitfalls) and plan/architecture §2.
|
|
12
|
+
*/
|
|
13
|
+
export interface UrlKeyOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Host form to unify to, derived from the GSC property at sync time:
|
|
16
|
+
* - 'apex' → strip a leading `www.`
|
|
17
|
+
* - 'www' → ensure a leading `www.`
|
|
18
|
+
* - 'asis' → leave host as delivered (default; safest when property type unknown)
|
|
19
|
+
*/
|
|
20
|
+
hostForm?: 'apex' | 'www' | 'asis';
|
|
21
|
+
/** Force https (Google almost always canonicalises to https). Default true. */
|
|
22
|
+
forceHttps?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Normalise a URL into a stable join key.
|
|
26
|
+
* Returns the original trimmed string if it cannot be parsed (so a bad URL still
|
|
27
|
+
* joins to itself rather than throwing).
|
|
28
|
+
*/
|
|
29
|
+
export declare function urlKey(rawUrl: string, options?: UrlKeyOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* The registrable brand label of a property — the first domain label, lower-cased, alphanumerics
|
|
32
|
+
* only (so "sc-domain:ehi.com.au" → "ehi", "https://www.sim-racing.gg/" → "simracing"). Returns null
|
|
33
|
+
* for labels under 3 chars (too short to match safely). Used for whole-token brand matching:
|
|
34
|
+
* `(' '||LOWER(query)||' ') LIKE '% '||brand||' %'` — same scheme as the dashboard's branded split.
|
|
35
|
+
*/
|
|
36
|
+
export declare function brandToken(siteUrl: string): string | null;
|
|
37
|
+
/** Derive the hostForm to use from a GSC property identifier. */
|
|
38
|
+
export declare function hostFormForProperty(siteUrl: string): UrlKeyOptions['hostForm'];
|
|
39
|
+
//# sourceMappingURL=url-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-key.d.ts","sourceRoot":"","sources":["../../src/core/url-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACnC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAQD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAgD1E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIzD;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAS9E"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* url-key — the single source of truth for the join between GSC data and crawl data.
|
|
3
|
+
*
|
|
4
|
+
* GSC stores Google-canonicalised URLs; the crawler stores raw discovered URLs.
|
|
5
|
+
* Neither normalises, and they normalise differently — so a naive `page = url`
|
|
6
|
+
* join silently misses trailing-slash / www / protocol / tracking-param variants.
|
|
7
|
+
* Both write paths run their URL through `urlKey()` and store the result in a
|
|
8
|
+
* `*_key` column; all joins use the key. The raw URL is kept for evidence, and
|
|
9
|
+
* raw-vs-key divergence (esp. canonical mismatch) is itself a finding.
|
|
10
|
+
*
|
|
11
|
+
* See research/05 (normalisation pitfalls) and plan/architecture §2.
|
|
12
|
+
*/
|
|
13
|
+
/** Tracking / session params stripped before keying (prefix match for families). */
|
|
14
|
+
const TRACKING_PARAM_PREFIXES = ['utm_', 'mc_', 'hsa_', '_hs', 'pk_', 'piwik_', 'matomo_'];
|
|
15
|
+
const TRACKING_PARAM_EXACT = new Set([
|
|
16
|
+
'gclid', 'gbraid', 'wbraid', 'dclid', 'fbclid', 'msclkid', 'twclid', 'ttclid',
|
|
17
|
+
'igshid', 'mkt_tok', 'yclid', 'ref', 'ref_src', 'spm', 'vero_id', 'oly_anon_id',
|
|
18
|
+
'oly_enc_id', '_ga', '_gl', 'gclsrc',
|
|
19
|
+
]);
|
|
20
|
+
function isTrackingParam(name) {
|
|
21
|
+
const lower = name.toLowerCase();
|
|
22
|
+
if (TRACKING_PARAM_EXACT.has(lower))
|
|
23
|
+
return true;
|
|
24
|
+
return TRACKING_PARAM_PREFIXES.some(p => lower.startsWith(p));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Normalise a URL into a stable join key.
|
|
28
|
+
* Returns the original trimmed string if it cannot be parsed (so a bad URL still
|
|
29
|
+
* joins to itself rather than throwing).
|
|
30
|
+
*/
|
|
31
|
+
export function urlKey(rawUrl, options = {}) {
|
|
32
|
+
const { hostForm = 'asis', forceHttps = true } = options;
|
|
33
|
+
const raw = (rawUrl ?? '').trim();
|
|
34
|
+
if (!raw)
|
|
35
|
+
return '';
|
|
36
|
+
let u;
|
|
37
|
+
try {
|
|
38
|
+
u = new URL(raw);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return raw; // un-parseable — key to itself, never throw on the hot path
|
|
42
|
+
}
|
|
43
|
+
// Only normalise http(s); leave other schemes (mailto:, tel:) untouched.
|
|
44
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:')
|
|
45
|
+
return raw;
|
|
46
|
+
// Scheme
|
|
47
|
+
if (forceHttps)
|
|
48
|
+
u.protocol = 'https:';
|
|
49
|
+
// Host: lowercase (hosts are case-insensitive), strip default ports, unify www.
|
|
50
|
+
let host = u.hostname.toLowerCase();
|
|
51
|
+
if (hostForm === 'apex' && host.startsWith('www.'))
|
|
52
|
+
host = host.slice(4);
|
|
53
|
+
else if (hostForm === 'www' && !host.startsWith('www.'))
|
|
54
|
+
host = `www.${host}`;
|
|
55
|
+
u.hostname = host;
|
|
56
|
+
// Strip default web ports unconditionally — after the https rewrite, a leftover
|
|
57
|
+
// :80 would otherwise survive on an https key and break the join.
|
|
58
|
+
if (u.port === '80' || u.port === '443')
|
|
59
|
+
u.port = '';
|
|
60
|
+
// Fragment never affects indexing identity.
|
|
61
|
+
u.hash = '';
|
|
62
|
+
// Query: drop tracking params, sort the rest for stable ordering. Preserve key case.
|
|
63
|
+
const kept = [];
|
|
64
|
+
for (const [k, v] of u.searchParams.entries()) {
|
|
65
|
+
if (!isTrackingParam(k))
|
|
66
|
+
kept.push([k, v]);
|
|
67
|
+
}
|
|
68
|
+
kept.sort((a, b) => (a[0] === b[0] ? (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0) : a[0] < b[0] ? -1 : 1));
|
|
69
|
+
u.search = '';
|
|
70
|
+
for (const [k, v] of kept)
|
|
71
|
+
u.searchParams.append(k, v);
|
|
72
|
+
// Path: preserve case (paths are case-sensitive); strip a single trailing slash
|
|
73
|
+
// except the root. Decode nothing — leave percent-encoding as delivered.
|
|
74
|
+
let path = u.pathname;
|
|
75
|
+
if (path.length > 1 && path.endsWith('/'))
|
|
76
|
+
path = path.slice(0, -1);
|
|
77
|
+
u.pathname = path;
|
|
78
|
+
// Rebuild without a trailing '?' when there are no params.
|
|
79
|
+
const query = u.searchParams.toString();
|
|
80
|
+
return `${u.protocol}//${u.host}${u.pathname}${query ? `?${query}` : ''}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The registrable brand label of a property — the first domain label, lower-cased, alphanumerics
|
|
84
|
+
* only (so "sc-domain:ehi.com.au" → "ehi", "https://www.sim-racing.gg/" → "simracing"). Returns null
|
|
85
|
+
* for labels under 3 chars (too short to match safely). Used for whole-token brand matching:
|
|
86
|
+
* `(' '||LOWER(query)||' ') LIKE '% '||brand||' %'` — same scheme as the dashboard's branded split.
|
|
87
|
+
*/
|
|
88
|
+
export function brandToken(siteUrl) {
|
|
89
|
+
const host = (siteUrl ?? '').replace(/^sc-domain:/, '').replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/.*$/, '');
|
|
90
|
+
const b = (host.split('.')[0] ?? '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
91
|
+
return b.length >= 3 ? b : null;
|
|
92
|
+
}
|
|
93
|
+
/** Derive the hostForm to use from a GSC property identifier. */
|
|
94
|
+
export function hostFormForProperty(siteUrl) {
|
|
95
|
+
// Domain properties ("sc-domain:example.com") cover both — default to apex.
|
|
96
|
+
if (siteUrl.startsWith('sc-domain:'))
|
|
97
|
+
return 'apex';
|
|
98
|
+
// URL-prefix properties carry their own host form; honour it.
|
|
99
|
+
try {
|
|
100
|
+
return new URL(siteUrl).hostname.toLowerCase().startsWith('www.') ? 'www' : 'apex';
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return 'asis';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=url-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-key.js","sourceRoot":"","sources":["../../src/core/url-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export interface JsonLdResult {
|
|
3
|
+
type: string;
|
|
4
|
+
jsonLd: Record<string, unknown>;
|
|
5
|
+
scriptTag: string;
|
|
6
|
+
filledFrom: string[];
|
|
7
|
+
todo: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function generateJsonLd(page: any): JsonLdResult;
|
|
10
|
+
export interface RedirectResult {
|
|
11
|
+
brokenUrl: string;
|
|
12
|
+
suggested: string | null;
|
|
13
|
+
score: number;
|
|
14
|
+
rule: string;
|
|
15
|
+
}
|
|
16
|
+
export type RedirectFormat = 'htaccess' | 'nginx' | 'nextjs';
|
|
17
|
+
export declare function redirectRule(fromPath: string, toPath: string, format: RedirectFormat): string;
|
|
18
|
+
/**
|
|
19
|
+
* Suggest a 301 for a broken/redirecting URL. When the crawler already RECORDED the real
|
|
20
|
+
* destination (redirect findings), pass it as `knownTarget` — it is used verbatim. Token-
|
|
21
|
+
* overlap fuzzy matching is only the fallback for genuinely dead URLs (404s) where no
|
|
22
|
+
* destination is known; a fuzzy guess presented as a paste-ready rule can be confidently wrong.
|
|
23
|
+
*/
|
|
24
|
+
export declare function suggestRedirect(brokenUrl: string, livePages: {
|
|
25
|
+
url: string;
|
|
26
|
+
}[], format?: RedirectFormat, knownTarget?: string | null): RedirectResult;
|
|
27
|
+
/** Collapse a recorded redirect chain: one exact-match rule per hop, straight to the final URL. */
|
|
28
|
+
export declare function collapseChainRules(finalUrl: string, hops: {
|
|
29
|
+
from: string;
|
|
30
|
+
to: string;
|
|
31
|
+
}[], format: RedirectFormat): {
|
|
32
|
+
finalUrl: string;
|
|
33
|
+
rules: string[];
|
|
34
|
+
};
|
|
35
|
+
export interface LinkSuggestion {
|
|
36
|
+
donorUrl: string;
|
|
37
|
+
ipr: number;
|
|
38
|
+
inlinkCount: number;
|
|
39
|
+
relevance: number;
|
|
40
|
+
}
|
|
41
|
+
export declare function suggestInternalLinks(db: Database.Database, receiverUrlKey: string, anchor: string): {
|
|
42
|
+
anchor: string;
|
|
43
|
+
donors: LinkSuggestion[];
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAwB3C,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;AAiBxI,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,GAAG,YAAY,CAgCtD;AAGD,MAAM,WAAW,cAAc;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAE5G,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAQ7D,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAI7F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,MAAM,GAAE,cAA2B,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,CAYjK;AAED,mGAAmG;AACnG,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,MAAM,EAAE,cAAc,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAOxJ;AAGD,MAAM,WAAW,cAAc;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAEzG,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,EAAE,CAAA;CAAE,CAiBhJ"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding → fix generators. Each produces a concrete, paste-ready remediation from
|
|
3
|
+
* crawl/GSC data — the differentiator over a static report. All are dry-run: they
|
|
4
|
+
* return artifacts, they never write to the user's site.
|
|
5
|
+
*/
|
|
6
|
+
// schema-dts is compile-time types; at runtime we build plain objects + serialise.
|
|
7
|
+
// safeJsonLd escapes for safe <script> embedding (per schema-dts docs).
|
|
8
|
+
const safeJsonLd = (data) => JSON.stringify(data, null, 2).replace(/</g, '\\u003C').replace(/>/g, '\\u003E').replace(/&/g, '\\u0026').replace(/'/g, '\\u0027');
|
|
9
|
+
const pathOf = (u) => { try {
|
|
10
|
+
return new URL(u).pathname;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return u || '/';
|
|
14
|
+
} };
|
|
15
|
+
const pathTokens = (u) => pathOf(u).toLowerCase().split(/[/\-_.]+/).filter(Boolean);
|
|
16
|
+
function tokenOverlap(a, b) {
|
|
17
|
+
const ta = new Set(pathTokens(a)), tb = new Set(pathTokens(b));
|
|
18
|
+
if (!tb.size)
|
|
19
|
+
return 0;
|
|
20
|
+
let m = 0;
|
|
21
|
+
for (const t of tb)
|
|
22
|
+
if (ta.has(t))
|
|
23
|
+
m++;
|
|
24
|
+
return m / Math.max(ta.size, tb.size);
|
|
25
|
+
}
|
|
26
|
+
function inferType(urlKey) {
|
|
27
|
+
const p = pathOf(urlKey);
|
|
28
|
+
if (p === '/' || p === '')
|
|
29
|
+
return 'Organization';
|
|
30
|
+
if (/\/(articles?|blog|news|posts?|guides?)\//.test(p))
|
|
31
|
+
return 'Article';
|
|
32
|
+
if (/\/(products?|shop|item|store)\//.test(p))
|
|
33
|
+
return 'Product';
|
|
34
|
+
return 'WebPage';
|
|
35
|
+
}
|
|
36
|
+
// Resolve a possibly-relative URL to absolute against the page URL (Google requires
|
|
37
|
+
// absolute image/logo URLs — generating a relative one just reproduces the finding).
|
|
38
|
+
function absUrl(v, base) {
|
|
39
|
+
if (!v)
|
|
40
|
+
return undefined;
|
|
41
|
+
try {
|
|
42
|
+
return new URL(v, base).toString();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return v;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function generateJsonLd(page) {
|
|
49
|
+
const type = inferType(page.url_key);
|
|
50
|
+
// A malformed og_tags row must degrade to a fix without og:image, not error the tool call.
|
|
51
|
+
const og = (() => { try {
|
|
52
|
+
return page.og_tags ? JSON.parse(page.og_tags) : {};
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return {};
|
|
56
|
+
} })();
|
|
57
|
+
const filledFrom = [];
|
|
58
|
+
const todo = [];
|
|
59
|
+
const o = { '@context': 'https://schema.org', '@type': type };
|
|
60
|
+
const ogImage = absUrl(og['og:image'], page.url); // absolutised
|
|
61
|
+
if (type === 'Organization') {
|
|
62
|
+
if (page.title) {
|
|
63
|
+
o.name = page.title;
|
|
64
|
+
filledFrom.push('name←title');
|
|
65
|
+
}
|
|
66
|
+
else
|
|
67
|
+
todo.push('name');
|
|
68
|
+
o.url = page.url;
|
|
69
|
+
filledFrom.push('url');
|
|
70
|
+
if (ogImage) {
|
|
71
|
+
o.logo = ogImage;
|
|
72
|
+
filledFrom.push('logo←og:image');
|
|
73
|
+
}
|
|
74
|
+
else
|
|
75
|
+
todo.push('logo');
|
|
76
|
+
todo.push('sameAs (social profiles)');
|
|
77
|
+
}
|
|
78
|
+
else if (type === 'Article') {
|
|
79
|
+
o.headline = page.h1 || page.title || '';
|
|
80
|
+
filledFrom.push('headline←h1/title');
|
|
81
|
+
o.url = page.url;
|
|
82
|
+
filledFrom.push('url');
|
|
83
|
+
if (page.meta_description) {
|
|
84
|
+
o.description = page.meta_description;
|
|
85
|
+
filledFrom.push('description');
|
|
86
|
+
}
|
|
87
|
+
if (ogImage) {
|
|
88
|
+
o.image = ogImage;
|
|
89
|
+
filledFrom.push('image←og:image');
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
todo.push('image');
|
|
93
|
+
o.author = { '@type': 'Person', name: 'TODO — author name' };
|
|
94
|
+
todo.push('author.name', 'datePublished', 'dateModified');
|
|
95
|
+
}
|
|
96
|
+
else if (type === 'Product') {
|
|
97
|
+
if (page.title) {
|
|
98
|
+
o.name = page.title;
|
|
99
|
+
filledFrom.push('name←title');
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
todo.push('name');
|
|
103
|
+
if (ogImage) {
|
|
104
|
+
o.image = ogImage;
|
|
105
|
+
filledFrom.push('image←og:image');
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
todo.push('image');
|
|
109
|
+
o.offers = { '@type': 'Offer', price: 'TODO', priceCurrency: 'TODO', availability: 'https://schema.org/InStock' };
|
|
110
|
+
todo.push('offers.price', 'offers.priceCurrency');
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
if (page.title) {
|
|
114
|
+
o.name = page.title;
|
|
115
|
+
filledFrom.push('name←title');
|
|
116
|
+
}
|
|
117
|
+
o.url = page.url;
|
|
118
|
+
filledFrom.push('url');
|
|
119
|
+
if (page.meta_description) {
|
|
120
|
+
o.description = page.meta_description;
|
|
121
|
+
filledFrom.push('description');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { type, jsonLd: o, scriptTag: `<script type="application/ld+json">\n${safeJsonLd(o)}\n</script>`, filledFrom, todo };
|
|
125
|
+
}
|
|
126
|
+
// Escape regex metacharacters — a path with `.`/`+`/`(` must not match other URLs or
|
|
127
|
+
// break the nginx config load.
|
|
128
|
+
const reEsc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
129
|
+
// One exact-match 301 rule. htaccess uses RedirectMatch with an anchored regex — plain
|
|
130
|
+
// `Redirect 301 /from /to` is PREFIX-matching and silently redirects every sub-path.
|
|
131
|
+
export function redirectRule(fromPath, toPath, format) {
|
|
132
|
+
return format === 'nginx' ? `rewrite ^${reEsc(fromPath)}$ ${toPath} permanent;`
|
|
133
|
+
: format === 'nextjs' ? `{ source: '${fromPath}', destination: '${toPath}', permanent: true },`
|
|
134
|
+
: `RedirectMatch 301 ^${reEsc(fromPath)}$ ${toPath}`;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Suggest a 301 for a broken/redirecting URL. When the crawler already RECORDED the real
|
|
138
|
+
* destination (redirect findings), pass it as `knownTarget` — it is used verbatim. Token-
|
|
139
|
+
* overlap fuzzy matching is only the fallback for genuinely dead URLs (404s) where no
|
|
140
|
+
* destination is known; a fuzzy guess presented as a paste-ready rule can be confidently wrong.
|
|
141
|
+
*/
|
|
142
|
+
export function suggestRedirect(brokenUrl, livePages, format = 'htaccess', knownTarget) {
|
|
143
|
+
const from = pathOf(brokenUrl);
|
|
144
|
+
if (knownTarget) {
|
|
145
|
+
return { brokenUrl, suggested: knownTarget, score: 1, rule: redirectRule(from, pathOf(knownTarget), format) };
|
|
146
|
+
}
|
|
147
|
+
let best = null, bestScore = 0;
|
|
148
|
+
for (const p of livePages) {
|
|
149
|
+
const s = tokenOverlap(brokenUrl, p.url);
|
|
150
|
+
if (s > bestScore) {
|
|
151
|
+
bestScore = s;
|
|
152
|
+
best = p.url;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const to = best ? pathOf(best) : '/';
|
|
156
|
+
const rule = !best || bestScore < 0.34
|
|
157
|
+
? `# no confident match for ${from} — choose a target manually`
|
|
158
|
+
: redirectRule(from, to, format);
|
|
159
|
+
return { brokenUrl, suggested: bestScore >= 0.34 ? best : null, score: Math.round(bestScore * 100) / 100, rule };
|
|
160
|
+
}
|
|
161
|
+
/** Collapse a recorded redirect chain: one exact-match rule per hop, straight to the final URL. */
|
|
162
|
+
export function collapseChainRules(finalUrl, hops, format) {
|
|
163
|
+
const toPath = pathOf(finalUrl);
|
|
164
|
+
const rules = hops
|
|
165
|
+
.map(h => pathOf(h.from))
|
|
166
|
+
.filter(fromPath => fromPath !== toPath)
|
|
167
|
+
.map(fromPath => redirectRule(fromPath, toPath, format));
|
|
168
|
+
return { finalUrl, rules };
|
|
169
|
+
}
|
|
170
|
+
export function suggestInternalLinks(db, receiverUrlKey, anchor) {
|
|
171
|
+
const alreadyLinking = new Set(db.prepare('SELECT DISTINCT source_key FROM links WHERE target_key = ?').all(receiverUrlKey).map(r => r.source_key));
|
|
172
|
+
// Prefer high-authority donors (iPR) — the "money move" is link equity flowing from
|
|
173
|
+
// strong pages to the under-linked receiver; topical relevance breaks ties.
|
|
174
|
+
// HTML pages only — never suggest linking from a non-HTML resource (RSS feed, image, PDF).
|
|
175
|
+
// Match the MIME type before any charset parameter (mirrors isHtmlContentType).
|
|
176
|
+
const candidates = db.prepare("SELECT url, url_key, ipr, inlink_count FROM pages WHERE status_code=200 AND indexable=1 AND (LOWER(content_type) LIKE 'text/html%' OR LOWER(content_type) LIKE 'application/xhtml+xml%') AND url_key != ? ORDER BY ipr DESC LIMIT 80").all(receiverUrlKey);
|
|
177
|
+
const donors = candidates
|
|
178
|
+
.filter(c => !alreadyLinking.has(c.url_key))
|
|
179
|
+
.map(c => ({ donorUrl: c.url, ipr: Math.round(c.ipr ?? 0), inlinkCount: c.inlink_count, relevance: Math.round(tokenOverlap(c.url, receiverUrlKey) * 100) / 100 }))
|
|
180
|
+
.sort((a, b) => b.relevance - a.relevance || b.ipr - a.ipr)
|
|
181
|
+
.slice(0, 5);
|
|
182
|
+
return { anchor, donors };
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright 2026 Richard Baxter — Apache-2.0
|
|
3
|
+
// seo-audit-console — MCP server entry point.
|
|
4
|
+
import { createServer } from './server.js';
|
|
5
|
+
const { run } = createServer();
|
|
6
|
+
run().catch((err) => {
|
|
7
|
+
console.error('[seo-audit-console] fatal:', err instanceof Error ? err.message : err);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,6CAA6C;AAC7C,8CAA8C;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,CAAC;AAC/B,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwDpE,wBAAgB,OAAO,IAAI,MAAM,CAGhC;AAuJD,wBAAgB,YAAY,IAAI;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAu3C9E"}
|