@actuate-media/cms-core 0.28.0 → 0.29.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/dist/__tests__/diagnostics/env.test.js +18 -0
- package/dist/__tests__/diagnostics/env.test.js.map +1 -1
- package/dist/__tests__/media/seo.test.d.ts +2 -0
- package/dist/__tests__/media/seo.test.d.ts.map +1 -0
- package/dist/__tests__/media/seo.test.js +186 -0
- package/dist/__tests__/media/seo.test.js.map +1 -0
- package/dist/__tests__/redirects/graph.test.d.ts +2 -0
- package/dist/__tests__/redirects/graph.test.d.ts.map +1 -0
- package/dist/__tests__/redirects/graph.test.js +104 -0
- package/dist/__tests__/redirects/graph.test.js.map +1 -0
- package/dist/__tests__/redirects/suggest.test.d.ts +2 -0
- package/dist/__tests__/redirects/suggest.test.d.ts.map +1 -0
- package/dist/__tests__/redirects/suggest.test.js +28 -0
- package/dist/__tests__/redirects/suggest.test.js.map +1 -0
- package/dist/__tests__/seo/audit-engine.test.d.ts +2 -0
- package/dist/__tests__/seo/audit-engine.test.d.ts.map +1 -0
- package/dist/__tests__/seo/audit-engine.test.js +152 -0
- package/dist/__tests__/seo/audit-engine.test.js.map +1 -0
- package/dist/__tests__/seo/config-store.test.js +24 -160
- package/dist/__tests__/seo/config-store.test.js.map +1 -1
- package/dist/__tests__/seo/score.test.d.ts +2 -0
- package/dist/__tests__/seo/score.test.d.ts.map +1 -0
- package/dist/__tests__/seo/score.test.js +152 -0
- package/dist/__tests__/seo/score.test.js.map +1 -0
- package/dist/__tests__/setup/index.test.d.ts +2 -0
- package/dist/__tests__/setup/index.test.d.ts.map +1 -0
- package/dist/__tests__/setup/index.test.js +82 -0
- package/dist/__tests__/setup/index.test.js.map +1 -0
- package/dist/api/handlers.d.ts.map +1 -1
- package/dist/api/handlers.js +2095 -228
- package/dist/api/handlers.js.map +1 -1
- package/dist/diagnostics/env.d.ts.map +1 -1
- package/dist/diagnostics/env.js +9 -5
- package/dist/diagnostics/env.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/media/index.d.ts +2 -0
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js +1 -0
- package/dist/media/index.js.map +1 -1
- package/dist/media/seo.d.ts +88 -0
- package/dist/media/seo.d.ts.map +1 -0
- package/dist/media/seo.js +215 -0
- package/dist/media/seo.js.map +1 -0
- package/dist/redirects/graph.d.ts +68 -0
- package/dist/redirects/graph.d.ts.map +1 -0
- package/dist/redirects/graph.js +136 -0
- package/dist/redirects/graph.js.map +1 -0
- package/dist/redirects/index.d.ts +5 -0
- package/dist/redirects/index.d.ts.map +1 -0
- package/dist/redirects/index.js +3 -0
- package/dist/redirects/index.js.map +1 -0
- package/dist/redirects/suggest.d.ts +21 -0
- package/dist/redirects/suggest.d.ts.map +1 -0
- package/dist/redirects/suggest.js +55 -0
- package/dist/redirects/suggest.js.map +1 -0
- package/dist/seo/audit-engine.d.ts +119 -0
- package/dist/seo/audit-engine.d.ts.map +1 -0
- package/dist/seo/audit-engine.js +402 -0
- package/dist/seo/audit-engine.js.map +1 -0
- package/dist/seo/audit-runner.d.ts +41 -0
- package/dist/seo/audit-runner.d.ts.map +1 -0
- package/dist/seo/audit-runner.js +223 -0
- package/dist/seo/audit-runner.js.map +1 -0
- package/dist/seo/config-store.d.ts +28 -0
- package/dist/seo/config-store.d.ts.map +1 -1
- package/dist/seo/config-store.js +22 -0
- package/dist/seo/config-store.js.map +1 -1
- package/dist/seo/index.d.ts +7 -2
- package/dist/seo/index.d.ts.map +1 -1
- package/dist/seo/index.js +4 -1
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/score.d.ts +128 -0
- package/dist/seo/score.d.ts.map +1 -0
- package/dist/seo/score.js +213 -0
- package/dist/seo/score.js.map +1 -0
- package/dist/setup/index.d.ts +16 -1
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js +52 -2
- package/dist/setup/index.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/0008_media_center/migration.sql +47 -0
- package/prisma/migrations/0009_seo/migration.sql +143 -0
- package/prisma/schema.prisma +183 -8
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEO audit orchestration: gather content from the DB, run the pure analysis
|
|
3
|
+
* engine, and persist a `SeoAuditRun` snapshot plus the live `SeoIssue` set.
|
|
4
|
+
*
|
|
5
|
+
* Issue lifecycle (carried across runs by `issueKey`):
|
|
6
|
+
* - newly detected -> status `open`
|
|
7
|
+
* - detected + was `ignored` -> stays `ignored`
|
|
8
|
+
* - detected + was `resolved` -> `recurring`
|
|
9
|
+
* - detected + open/recurring -> unchanged (lastDetectedAt bumped)
|
|
10
|
+
* - NOT detected + open/recurring -> auto `resolved` (resolvedAt set)
|
|
11
|
+
* - NOT detected + ignored/resolved -> unchanged
|
|
12
|
+
*
|
|
13
|
+
* The run row stores the score + counts snapshot, so audit *history* is the
|
|
14
|
+
* sequence of runs while the issue table reflects current state.
|
|
15
|
+
*/
|
|
16
|
+
import { runSeoAuditAnalysis, } from './audit-engine.js';
|
|
17
|
+
import { resolveSeoModuleSettings, getSeoOverrides, SEO_CONFIG_COLLECTION } from './config-store.js';
|
|
18
|
+
/** Collections that are never audited (internal/system data). */
|
|
19
|
+
const EXCLUDED_COLLECTIONS = new Set([
|
|
20
|
+
SEO_CONFIG_COLLECTION,
|
|
21
|
+
'page-tags',
|
|
22
|
+
'redirects',
|
|
23
|
+
'__seo_config__',
|
|
24
|
+
]);
|
|
25
|
+
function asRecord(v) {
|
|
26
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
27
|
+
}
|
|
28
|
+
function str(v) {
|
|
29
|
+
return typeof v === 'string' && v.length > 0 ? v : null;
|
|
30
|
+
}
|
|
31
|
+
function bool(v) {
|
|
32
|
+
return v === true || v === 'true';
|
|
33
|
+
}
|
|
34
|
+
/** Map a published document row into the audit engine's entity shape. */
|
|
35
|
+
export function documentToAuditEntity(doc) {
|
|
36
|
+
const data = asRecord(doc.data);
|
|
37
|
+
const structured = asRecord(doc.structuredData);
|
|
38
|
+
const slug = str(data.slug) ?? doc.slug ?? doc.id;
|
|
39
|
+
const url = str(data.path) ?? str(data.url) ?? (slug === 'home' ? '/' : `/${slug}`);
|
|
40
|
+
const content = str(data.body) ??
|
|
41
|
+
str(data.content) ??
|
|
42
|
+
(typeof doc.plainText === 'string' ? doc.plainText : '') ??
|
|
43
|
+
'';
|
|
44
|
+
return {
|
|
45
|
+
entityType: doc.collection === 'pages' ? 'page' : 'post',
|
|
46
|
+
entityId: doc.id,
|
|
47
|
+
title: str(data.title) ?? doc.title ?? 'Untitled',
|
|
48
|
+
url,
|
|
49
|
+
content,
|
|
50
|
+
metaTitle: str(data.metaTitle) ?? str(data.seoTitle),
|
|
51
|
+
metaDescription: str(data.metaDescription) ?? str(data.seoDescription),
|
|
52
|
+
focusKeyword: str(data.focusKeyword) ?? str(data.focusKeyphrase),
|
|
53
|
+
canonicalUrl: str(data.canonical) ?? str(data.canonicalUrl),
|
|
54
|
+
ogTitle: str(data.ogTitle),
|
|
55
|
+
ogDescription: str(data.ogDescription),
|
|
56
|
+
ogImage: str(data.ogImage),
|
|
57
|
+
structuredDataType: str(data.structuredDataType) ?? str(data.schemaType) ?? str(structured.schemaType),
|
|
58
|
+
noindex: bool(data.noindex) || bool(data.robotsNoindex),
|
|
59
|
+
shouldBeIndexable: true,
|
|
60
|
+
wordCount: typeof data.wordCount === 'number' ? data.wordCount : null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function gatherAuditEntities(db) {
|
|
64
|
+
const docs = await db.document.findMany({
|
|
65
|
+
where: { deletedAt: null, status: 'PUBLISHED' },
|
|
66
|
+
select: {
|
|
67
|
+
id: true,
|
|
68
|
+
collection: true,
|
|
69
|
+
title: true,
|
|
70
|
+
slug: true,
|
|
71
|
+
data: true,
|
|
72
|
+
structuredData: true,
|
|
73
|
+
plainText: true,
|
|
74
|
+
},
|
|
75
|
+
orderBy: { updatedAt: 'desc' },
|
|
76
|
+
});
|
|
77
|
+
return docs
|
|
78
|
+
.filter((d) => !EXCLUDED_COLLECTIONS.has(d.collection) && !String(d.collection).startsWith('__'))
|
|
79
|
+
.map(documentToAuditEntity);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Run an audit and persist the run + issue snapshot. Returns the run summary.
|
|
83
|
+
* Throws if the SEO models aren't available (caller maps to 501).
|
|
84
|
+
*/
|
|
85
|
+
export async function runAndPersistAudit(db, options = {}) {
|
|
86
|
+
if (!db?.seoAuditRun?.create || !db?.seoIssue?.findMany) {
|
|
87
|
+
throw new Error('SEO models not available');
|
|
88
|
+
}
|
|
89
|
+
const scope = options.scope ?? 'full';
|
|
90
|
+
// Resolve sitemap/robots health from module settings.
|
|
91
|
+
const overrides = await getSeoOverrides(db).catch(() => null);
|
|
92
|
+
const moduleSettings = resolveSeoModuleSettings(overrides);
|
|
93
|
+
const signals = {
|
|
94
|
+
sitemapEnabled: moduleSettings.sitemapEnabled,
|
|
95
|
+
robotsEnabled: moduleSettings.robotsEnabled,
|
|
96
|
+
...options.signals,
|
|
97
|
+
};
|
|
98
|
+
// Previous run's after-score becomes this run's before-score.
|
|
99
|
+
const prev = await db.seoAuditRun.findFirst({
|
|
100
|
+
where: { status: 'COMPLETED' },
|
|
101
|
+
orderBy: { startedAt: 'desc' },
|
|
102
|
+
select: { siteScoreAfter: true },
|
|
103
|
+
});
|
|
104
|
+
const run = await db.seoAuditRun.create({
|
|
105
|
+
data: {
|
|
106
|
+
status: 'RUNNING',
|
|
107
|
+
scope,
|
|
108
|
+
startedById: options.startedById ?? null,
|
|
109
|
+
siteScoreBefore: prev?.siteScoreAfter ?? null,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
try {
|
|
113
|
+
const entities = await gatherAuditEntities(db);
|
|
114
|
+
const result = runSeoAuditAnalysis(entities, signals);
|
|
115
|
+
await persistIssues(db, run.id, result.issues);
|
|
116
|
+
await db.seoAuditRun.update({
|
|
117
|
+
where: { id: run.id },
|
|
118
|
+
data: {
|
|
119
|
+
status: 'COMPLETED',
|
|
120
|
+
finishedAt: new Date(),
|
|
121
|
+
siteScoreAfter: result.siteScore.score,
|
|
122
|
+
pagesScanned: entities.length,
|
|
123
|
+
issuesFound: result.counts.total,
|
|
124
|
+
criticalCount: result.counts.critical,
|
|
125
|
+
warningCount: result.counts.warning,
|
|
126
|
+
infoCount: result.counts.info,
|
|
127
|
+
metadata: { breakdown: result.siteScore.breakdown },
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
id: run.id,
|
|
132
|
+
status: 'COMPLETED',
|
|
133
|
+
siteScoreAfter: result.siteScore.score,
|
|
134
|
+
issuesFound: result.counts.total,
|
|
135
|
+
criticalCount: result.counts.critical,
|
|
136
|
+
warningCount: result.counts.warning,
|
|
137
|
+
infoCount: result.counts.info,
|
|
138
|
+
pagesScanned: entities.length,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
await db.seoAuditRun
|
|
143
|
+
.update({
|
|
144
|
+
where: { id: run.id },
|
|
145
|
+
data: {
|
|
146
|
+
status: 'FAILED',
|
|
147
|
+
finishedAt: new Date(),
|
|
148
|
+
errorMessage: err instanceof Error ? err.message : 'Audit failed',
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
.catch(() => { });
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Upsert detected issues and auto-resolve no-longer-detected ones. */
|
|
156
|
+
async function persistIssues(db, auditRunId, detected) {
|
|
157
|
+
const existing = await db.seoIssue.findMany({});
|
|
158
|
+
const byKey = new Map(existing.map((i) => [i.issueKey, i]));
|
|
159
|
+
const detectedKeys = new Set(detected.map((d) => d.issueKey));
|
|
160
|
+
const now = new Date();
|
|
161
|
+
for (const issue of detected) {
|
|
162
|
+
const prior = byKey.get(issue.issueKey);
|
|
163
|
+
if (prior) {
|
|
164
|
+
let status = prior.status;
|
|
165
|
+
if (prior.status === 'resolved')
|
|
166
|
+
status = 'recurring';
|
|
167
|
+
// 'ignored' stays ignored; 'open'/'recurring' unchanged.
|
|
168
|
+
await db.seoIssue.update({
|
|
169
|
+
where: { id: prior.id },
|
|
170
|
+
data: {
|
|
171
|
+
auditRunId,
|
|
172
|
+
status,
|
|
173
|
+
lastDetectedAt: now,
|
|
174
|
+
entityTitle: issue.entityTitle,
|
|
175
|
+
url: issue.url,
|
|
176
|
+
severity: issue.severity,
|
|
177
|
+
category: issue.category,
|
|
178
|
+
title: issue.title,
|
|
179
|
+
description: issue.description,
|
|
180
|
+
impact: issue.impact,
|
|
181
|
+
recommendation: issue.recommendation,
|
|
182
|
+
fixable: issue.fixable,
|
|
183
|
+
fixActionType: issue.fixActionType,
|
|
184
|
+
relatedEntityIds: issue.relatedEntityIds,
|
|
185
|
+
resolvedAt: status === 'resolved' ? prior.resolvedAt : null,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
await db.seoIssue.create({
|
|
191
|
+
data: {
|
|
192
|
+
auditRunId,
|
|
193
|
+
issueKey: issue.issueKey,
|
|
194
|
+
entityType: issue.entityType,
|
|
195
|
+
entityId: issue.entityId,
|
|
196
|
+
entityTitle: issue.entityTitle,
|
|
197
|
+
url: issue.url,
|
|
198
|
+
severity: issue.severity,
|
|
199
|
+
category: issue.category,
|
|
200
|
+
type: issue.type,
|
|
201
|
+
title: issue.title,
|
|
202
|
+
description: issue.description,
|
|
203
|
+
impact: issue.impact,
|
|
204
|
+
recommendation: issue.recommendation,
|
|
205
|
+
status: 'open',
|
|
206
|
+
fixable: issue.fixable,
|
|
207
|
+
fixActionType: issue.fixActionType,
|
|
208
|
+
relatedEntityIds: issue.relatedEntityIds,
|
|
209
|
+
source: 'audit',
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Auto-resolve open/recurring issues that were not detected this run.
|
|
215
|
+
const toResolve = existing.filter((i) => !detectedKeys.has(i.issueKey) && (i.status === 'open' || i.status === 'recurring'));
|
|
216
|
+
for (const i of toResolve) {
|
|
217
|
+
await db.seoIssue.update({
|
|
218
|
+
where: { id: i.id },
|
|
219
|
+
data: { status: 'resolved', resolvedAt: now },
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=audit-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-runner.js","sourceRoot":"","sources":["../../src/seo/audit-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,11 +28,39 @@ export interface SeoConfigOverrides {
|
|
|
28
28
|
site?: Partial<SiteSEOConfig>;
|
|
29
29
|
/** Per-collection overrides keyed by collection slug. */
|
|
30
30
|
collections?: Record<string, Partial<CollectionSEOConfig>>;
|
|
31
|
+
/** SEO module settings edited from the Technical tab (crawl/robots/sitemap). */
|
|
32
|
+
module?: Partial<SeoModuleSettings>;
|
|
31
33
|
/** Last update timestamp (set by the writer). */
|
|
32
34
|
updatedAt?: string;
|
|
33
35
|
/** User id of the last editor (set by the writer). */
|
|
34
36
|
updatedBy?: string;
|
|
35
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Editable SEO-module behaviour surfaced on the Technical tab. These are the
|
|
40
|
+
* crawl/index toggles, sitemap options, custom robots.txt body, and the
|
|
41
|
+
* Search Console connection flag from the SEO spec's `SEOConfig` shape. Stored
|
|
42
|
+
* alongside the field overrides in the same `__seo_config__` document.
|
|
43
|
+
*/
|
|
44
|
+
export interface SeoModuleSettings {
|
|
45
|
+
sitemapEnabled: boolean;
|
|
46
|
+
robotsEnabled: boolean;
|
|
47
|
+
autoRegenerateSitemapOnPublish: boolean;
|
|
48
|
+
includeImagesInSitemap: boolean;
|
|
49
|
+
includePostsInSitemap: boolean;
|
|
50
|
+
indexEntireSite: boolean;
|
|
51
|
+
noindexPaginatedArchives: boolean;
|
|
52
|
+
noindexTagPages: boolean;
|
|
53
|
+
/** Custom robots.txt body. Empty string means "use generated defaults". */
|
|
54
|
+
robotsTxt: string;
|
|
55
|
+
/** Whether Google Search Console is connected (gated; false in demo/local). */
|
|
56
|
+
searchConsoleConnected: boolean;
|
|
57
|
+
/** ISO timestamp of the last manual sitemap regeneration (null = never). */
|
|
58
|
+
sitemapLastGeneratedAt: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Safe defaults applied when the overrides document has no `module` block. */
|
|
61
|
+
export declare const DEFAULT_SEO_MODULE_SETTINGS: SeoModuleSettings;
|
|
62
|
+
/** Merge stored module settings over the defaults (field-by-field). */
|
|
63
|
+
export declare function resolveSeoModuleSettings(overrides: SeoConfigOverrides | null): SeoModuleSettings;
|
|
36
64
|
/** Read the SEO overrides document. Returns null when no row exists yet. */
|
|
37
65
|
export declare function getSeoOverrides(db: unknown): Promise<SeoConfigOverrides | null>;
|
|
38
66
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/seo/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAEhB,mBAAmB,EACnB,aAAa,EACd,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,qBAAqB,mBAAmB,CAAA;AAErD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAA;IAC1D,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,4EAA4E;AAC5E,wBAAsB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAerF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,OAAO,EACX,SAAS,EAAE,kBAAkB,EAC7B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CA8B7B;AAwBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,SAAS,GACvC,aAAa,CA6Bf;AAED,qFAAqF;AACrF,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,mBAAmB,GAAG,SAAS,EACrC,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,SAAS,GAC7C,mBAAmB,CAiBrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC3C,SAAS,EAAE,kBAAkB,GAAG,IAAI,GACnC,gBAAgB,GAAG,IAAI,CAkBzB"}
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/seo/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAEhB,mBAAmB,EACnB,aAAa,EACd,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,qBAAqB,mBAAmB,CAAA;AAErD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAA;IAC1D,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,OAAO,CAAA;IACvB,aAAa,EAAE,OAAO,CAAA;IACtB,8BAA8B,EAAE,OAAO,CAAA;IACvC,sBAAsB,EAAE,OAAO,CAAA;IAC/B,qBAAqB,EAAE,OAAO,CAAA;IAC9B,eAAe,EAAE,OAAO,CAAA;IACxB,wBAAwB,EAAE,OAAO,CAAA;IACjC,eAAe,EAAE,OAAO,CAAA;IACxB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,sBAAsB,EAAE,OAAO,CAAA;IAC/B,4EAA4E;IAC5E,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC;AAED,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,EAAE,iBAYzC,CAAA;AAED,uEAAuE;AACvE,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,kBAAkB,GAAG,IAAI,GAAG,iBAAiB,CAMhG;AAED,4EAA4E;AAC5E,wBAAsB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAerF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,OAAO,EACX,SAAS,EAAE,kBAAkB,EAC7B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CA8B7B;AAwBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,SAAS,GACvC,aAAa,CA6Bf;AAED,qFAAqF;AACrF,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,mBAAmB,GAAG,SAAS,EACrC,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,SAAS,GAC7C,mBAAmB,CAiBrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAC3C,SAAS,EAAE,kBAAkB,GAAG,IAAI,GACnC,gBAAgB,GAAG,IAAI,CAkBzB"}
|
package/dist/seo/config-store.js
CHANGED
|
@@ -17,6 +17,28 @@
|
|
|
17
17
|
* never destructive of code-level config.
|
|
18
18
|
*/
|
|
19
19
|
export const SEO_CONFIG_COLLECTION = '__seo_config__';
|
|
20
|
+
/** Safe defaults applied when the overrides document has no `module` block. */
|
|
21
|
+
export const DEFAULT_SEO_MODULE_SETTINGS = {
|
|
22
|
+
sitemapEnabled: true,
|
|
23
|
+
robotsEnabled: true,
|
|
24
|
+
autoRegenerateSitemapOnPublish: true,
|
|
25
|
+
includeImagesInSitemap: true,
|
|
26
|
+
includePostsInSitemap: true,
|
|
27
|
+
indexEntireSite: true,
|
|
28
|
+
noindexPaginatedArchives: true,
|
|
29
|
+
noindexTagPages: false,
|
|
30
|
+
robotsTxt: '',
|
|
31
|
+
searchConsoleConnected: false,
|
|
32
|
+
sitemapLastGeneratedAt: null,
|
|
33
|
+
};
|
|
34
|
+
/** Merge stored module settings over the defaults (field-by-field). */
|
|
35
|
+
export function resolveSeoModuleSettings(overrides) {
|
|
36
|
+
const stored = overrides?.module ?? {};
|
|
37
|
+
return {
|
|
38
|
+
...DEFAULT_SEO_MODULE_SETTINGS,
|
|
39
|
+
...Object.fromEntries(Object.entries(stored).filter(([, v]) => v !== undefined && v !== null)),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
20
42
|
/** Read the SEO overrides document. Returns null when no row exists yet. */
|
|
21
43
|
export async function getSeoOverrides(db) {
|
|
22
44
|
const d = db;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/seo/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/seo/config-store.ts"],"names":[],"mappings":"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"}
|
package/dist/seo/index.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ export { generateLlmsTxt } from './llms-txt.js';
|
|
|
10
10
|
export type { LlmsTxtConfig, LlmsTxtPage } from './llms-txt.js';
|
|
11
11
|
export { composePageMeta, detectSchemaType } from './page-meta.js';
|
|
12
12
|
export type { ComposePageMetaInput, ComposedPageMeta, ComposeDocumentInput } from './page-meta.js';
|
|
13
|
-
export { SEO_CONFIG_COLLECTION, getSeoOverrides, putSeoOverrides, applySeoOverrides, mergeSiteSeoConfig, mergeCollectionSeoConfig, } from './config-store.js';
|
|
14
|
-
export type { SeoConfigOverrides } from './config-store.js';
|
|
13
|
+
export { SEO_CONFIG_COLLECTION, getSeoOverrides, putSeoOverrides, applySeoOverrides, mergeSiteSeoConfig, mergeCollectionSeoConfig, DEFAULT_SEO_MODULE_SETTINGS, resolveSeoModuleSettings, } from './config-store.js';
|
|
14
|
+
export type { SeoConfigOverrides, SeoModuleSettings } from './config-store.js';
|
|
15
|
+
export { calculatePageSeoScore, calculateSiteSeoScore, gradeForSeoScore, countH1, PAGE_SEO_WEIGHTS, SITE_SEO_WEIGHTS, } from './score.js';
|
|
16
|
+
export type { SeoGrade, SeoCheckStatus, SeoScoreCheck, PageSeoScoreResult, PageSeoScoreInput, SiteSeoScoreInput, SiteSeoScoreResult, SiteSeoScoreBreakdownItem, } from './score.js';
|
|
17
|
+
export { runSeoAuditAnalysis, buildQuickWins, issueKeyFor } from './audit-engine.js';
|
|
18
|
+
export type { AuditEntityInput, AuditExtraSignals, DetectedIssue, AuditPageRecord, QuickWin, SeoAuditResult, } from './audit-engine.js';
|
|
19
|
+
export { runAndPersistAudit, gatherAuditEntities, documentToAuditEntity } from './audit-runner.js';
|
|
15
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/seo/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAA;AAEtB,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAElG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE3F,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAErD,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE1F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAErE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAElE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAElG,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAE1B,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAA;AAEtB,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAElG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE3F,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAErD,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE1F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAErE,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAElE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAElG,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAE1B,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE9E,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpF,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,cAAc,GACf,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
package/dist/seo/index.js
CHANGED
|
@@ -4,5 +4,8 @@ export { resolveRobotsDirectives } from './robots.js';
|
|
|
4
4
|
export { resolveTitle, getDocumentTitle } from './title-templates.js';
|
|
5
5
|
export { generateLlmsTxt } from './llms-txt.js';
|
|
6
6
|
export { composePageMeta, detectSchemaType } from './page-meta.js';
|
|
7
|
-
export { SEO_CONFIG_COLLECTION, getSeoOverrides, putSeoOverrides, applySeoOverrides, mergeSiteSeoConfig, mergeCollectionSeoConfig, } from './config-store.js';
|
|
7
|
+
export { SEO_CONFIG_COLLECTION, getSeoOverrides, putSeoOverrides, applySeoOverrides, mergeSiteSeoConfig, mergeCollectionSeoConfig, DEFAULT_SEO_MODULE_SETTINGS, resolveSeoModuleSettings, } from './config-store.js';
|
|
8
|
+
export { calculatePageSeoScore, calculateSiteSeoScore, gradeForSeoScore, countH1, PAGE_SEO_WEIGHTS, SITE_SEO_WEIGHTS, } from './score.js';
|
|
9
|
+
export { runSeoAuditAnalysis, buildQuickWins, issueKeyFor } from './audit-engine.js';
|
|
10
|
+
export { runAndPersistAudit, gatherAuditEntities, documentToAuditEntity } from './audit-runner.js';
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
package/dist/seo/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAA;AAItB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAI3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAIrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAIrE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAI/C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAIlE,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,GAChB,MAAM,eAAe,CAAA;AAItB,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAI3F,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAIrD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAIrE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAI/C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAIlE,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAA;AAanB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAWpF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEO scoring model.
|
|
3
|
+
*
|
|
4
|
+
* Pure, dependency-light functions that turn a page/post's metadata + content
|
|
5
|
+
* into an explainable 0-100 score, and aggregate per-category signals into a
|
|
6
|
+
* site-wide score. Nothing here is persisted directly — the audit engine
|
|
7
|
+
* (Phase 2) calls these and snapshots the results into `SeoAuditRun` /
|
|
8
|
+
* `SeoIssue` rows, while the Content SEO table recomputes page scores on read.
|
|
9
|
+
*
|
|
10
|
+
* The score is intentionally NOT a mystery number: every result carries a
|
|
11
|
+
* `checks` array describing exactly which points were earned/lost and why, so
|
|
12
|
+
* the admin UI can show editors what to fix. The unit tests in
|
|
13
|
+
* `__tests__/seo/score.test.ts` are the source of truth for the weights.
|
|
14
|
+
*/
|
|
15
|
+
export type SeoGrade = 'good' | 'fair' | 'poor' | 'critical';
|
|
16
|
+
export type SeoCheckStatus = 'pass' | 'warn' | 'fail';
|
|
17
|
+
/** One explainable line item in a page score. */
|
|
18
|
+
export interface SeoScoreCheck {
|
|
19
|
+
id: string;
|
|
20
|
+
label: string;
|
|
21
|
+
/** Points earned (0..max). */
|
|
22
|
+
points: number;
|
|
23
|
+
/** Maximum points this check contributes. */
|
|
24
|
+
max: number;
|
|
25
|
+
status: SeoCheckStatus;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
export interface PageSeoScoreResult {
|
|
29
|
+
score: number;
|
|
30
|
+
grade: SeoGrade;
|
|
31
|
+
checks: SeoScoreCheck[];
|
|
32
|
+
}
|
|
33
|
+
/** The metadata + content subset a page score depends on. */
|
|
34
|
+
export interface PageSeoScoreInput {
|
|
35
|
+
title?: string | null;
|
|
36
|
+
slug?: string | null;
|
|
37
|
+
url?: string | null;
|
|
38
|
+
/** Raw HTML or plain content body, used for H1 + length checks. */
|
|
39
|
+
content?: string | null;
|
|
40
|
+
metaTitle?: string | null;
|
|
41
|
+
metaDescription?: string | null;
|
|
42
|
+
focusKeyword?: string | null;
|
|
43
|
+
canonicalUrl?: string | null;
|
|
44
|
+
ogTitle?: string | null;
|
|
45
|
+
ogDescription?: string | null;
|
|
46
|
+
ogImage?: string | null;
|
|
47
|
+
structuredDataType?: string | null;
|
|
48
|
+
noindex?: boolean | null;
|
|
49
|
+
/** True when this content is intended to be public/indexable. */
|
|
50
|
+
shouldBeIndexable?: boolean;
|
|
51
|
+
/** Number of internal links that failed validation, when known. */
|
|
52
|
+
brokenInternalLinks?: number;
|
|
53
|
+
/** Pre-computed word count; falls back to counting `content`. */
|
|
54
|
+
wordCount?: number | null;
|
|
55
|
+
}
|
|
56
|
+
/** Page score weights. Must sum to 100. */
|
|
57
|
+
export declare const PAGE_SEO_WEIGHTS: {
|
|
58
|
+
readonly metaTitlePresent: 10;
|
|
59
|
+
readonly metaTitleLength: 5;
|
|
60
|
+
readonly metaDescPresent: 10;
|
|
61
|
+
readonly metaDescLength: 5;
|
|
62
|
+
readonly focusKeyword: 8;
|
|
63
|
+
readonly canonical: 7;
|
|
64
|
+
readonly h1: 10;
|
|
65
|
+
readonly contentLength: 10;
|
|
66
|
+
readonly ogImage: 8;
|
|
67
|
+
readonly ogTitleDesc: 5;
|
|
68
|
+
readonly structuredData: 7;
|
|
69
|
+
readonly internalLinks: 5;
|
|
70
|
+
readonly indexable: 10;
|
|
71
|
+
};
|
|
72
|
+
/** Site score category weights (spec). Must sum to 100. */
|
|
73
|
+
export declare const SITE_SEO_WEIGHTS: {
|
|
74
|
+
readonly content: 30;
|
|
75
|
+
readonly technical: 25;
|
|
76
|
+
readonly linkRedirect: 20;
|
|
77
|
+
readonly structuredSocial: 15;
|
|
78
|
+
readonly performance: 10;
|
|
79
|
+
};
|
|
80
|
+
/** Map a 0-100 score to a grade. Aligns with the Content SEO table colours. */
|
|
81
|
+
export declare function gradeForSeoScore(score: number): SeoGrade;
|
|
82
|
+
/** Count `<h1>` tags in an HTML string (case-insensitive). */
|
|
83
|
+
export declare function countH1(html: string): number;
|
|
84
|
+
/**
|
|
85
|
+
* Compute a page/post SEO score (0-100) with an explainable breakdown.
|
|
86
|
+
*
|
|
87
|
+
* Points are additive per {@link PAGE_SEO_WEIGHTS}; "warn" checks earn partial
|
|
88
|
+
* credit. The total is clamped to 0-100 and rounded.
|
|
89
|
+
*/
|
|
90
|
+
export declare function calculatePageSeoScore(input: PageSeoScoreInput): PageSeoScoreResult;
|
|
91
|
+
export interface SiteScoreCategory {
|
|
92
|
+
/** 0-100 sub-score for this category. */
|
|
93
|
+
score: number;
|
|
94
|
+
weight: number;
|
|
95
|
+
}
|
|
96
|
+
export interface SiteSeoScoreInput {
|
|
97
|
+
/** 0-100 — metadata completeness/uniqueness across content. */
|
|
98
|
+
content: number;
|
|
99
|
+
/** 0-100 — crawl/index health (sitemap, robots, canonicals, noindex). */
|
|
100
|
+
technical: number;
|
|
101
|
+
/** 0-100 — internal link + redirect health. */
|
|
102
|
+
linkRedirect: number;
|
|
103
|
+
/** 0-100 — structured data + social metadata coverage. */
|
|
104
|
+
structuredSocial: number;
|
|
105
|
+
/** 0-100 — performance + search signals (defaults neutral when unknown). */
|
|
106
|
+
performance?: number;
|
|
107
|
+
}
|
|
108
|
+
export interface SiteSeoScoreBreakdownItem {
|
|
109
|
+
category: keyof typeof SITE_SEO_WEIGHTS;
|
|
110
|
+
score: number;
|
|
111
|
+
weight: number;
|
|
112
|
+
/** Weighted contribution to the final score. */
|
|
113
|
+
contribution: number;
|
|
114
|
+
}
|
|
115
|
+
export interface SiteSeoScoreResult {
|
|
116
|
+
score: number;
|
|
117
|
+
grade: SeoGrade;
|
|
118
|
+
breakdown: SiteSeoScoreBreakdownItem[];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Combine per-category sub-scores into a weighted 0-100 site score.
|
|
122
|
+
*
|
|
123
|
+
* Performance defaults to 70 (neutral) when not supplied, so sites without a
|
|
124
|
+
* connected performance source aren't unfairly penalised — the weight is still
|
|
125
|
+
* applied so connecting Search Console can only improve the signal's accuracy.
|
|
126
|
+
*/
|
|
127
|
+
export declare function calculateSiteSeoScore(input: SiteSeoScoreInput): SiteSeoScoreResult;
|
|
128
|
+
//# sourceMappingURL=score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../src/seo/score.ts"],"names":[],"mappings":"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"}
|