@actuate-media/cms-core 0.65.0 → 0.67.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/CHANGELOG.md +143 -0
- package/dist/__tests__/api/ai-quality.test.js +73 -0
- package/dist/__tests__/api/ai-quality.test.js.map +1 -1
- package/dist/__tests__/api/llms-txt.test.js +59 -0
- package/dist/__tests__/api/llms-txt.test.js.map +1 -1
- package/dist/__tests__/api/public-seo.test.js +402 -4
- package/dist/__tests__/api/public-seo.test.js.map +1 -1
- package/dist/__tests__/api/route-contracts.test.js +7 -0
- package/dist/__tests__/api/route-contracts.test.js.map +1 -1
- package/dist/__tests__/content/slug.test.d.ts +2 -0
- package/dist/__tests__/content/slug.test.d.ts.map +1 -0
- package/dist/__tests__/content/slug.test.js +68 -0
- package/dist/__tests__/content/slug.test.js.map +1 -0
- package/dist/__tests__/middleware.test.js +47 -0
- package/dist/__tests__/middleware.test.js.map +1 -1
- package/dist/__tests__/redirects/auto-301.test.d.ts +2 -0
- package/dist/__tests__/redirects/auto-301.test.d.ts.map +1 -0
- package/dist/__tests__/redirects/auto-301.test.js +172 -0
- package/dist/__tests__/redirects/auto-301.test.js.map +1 -0
- package/dist/__tests__/seo/ai-bots.test.d.ts +2 -0
- package/dist/__tests__/seo/ai-bots.test.d.ts.map +1 -0
- package/dist/__tests__/seo/ai-bots.test.js +53 -0
- package/dist/__tests__/seo/ai-bots.test.js.map +1 -0
- package/dist/__tests__/seo/alt-text.test.d.ts +2 -0
- package/dist/__tests__/seo/alt-text.test.d.ts.map +1 -0
- package/dist/__tests__/seo/alt-text.test.js +47 -0
- package/dist/__tests__/seo/alt-text.test.js.map +1 -0
- package/dist/__tests__/seo/feeds.test.d.ts +2 -0
- package/dist/__tests__/seo/feeds.test.d.ts.map +1 -0
- package/dist/__tests__/seo/feeds.test.js +61 -0
- package/dist/__tests__/seo/feeds.test.js.map +1 -0
- package/dist/__tests__/seo/freshness.test.d.ts +2 -0
- package/dist/__tests__/seo/freshness.test.d.ts.map +1 -0
- package/dist/__tests__/seo/freshness.test.js +89 -0
- package/dist/__tests__/seo/freshness.test.js.map +1 -0
- package/dist/__tests__/seo/meta-tags-alternates.test.d.ts +2 -0
- package/dist/__tests__/seo/meta-tags-alternates.test.d.ts.map +1 -0
- package/dist/__tests__/seo/meta-tags-alternates.test.js +52 -0
- package/dist/__tests__/seo/meta-tags-alternates.test.js.map +1 -0
- package/dist/__tests__/seo/page-meta.test.js +230 -14
- package/dist/__tests__/seo/page-meta.test.js.map +1 -1
- package/dist/__tests__/seo/sitemap-notify.test.js +77 -1
- package/dist/__tests__/seo/sitemap-notify.test.js.map +1 -1
- package/dist/__tests__/validation/publish.test.d.ts +2 -0
- package/dist/__tests__/validation/publish.test.d.ts.map +1 -0
- package/dist/__tests__/validation/publish.test.js +164 -0
- package/dist/__tests__/validation/publish.test.js.map +1 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +172 -8
- package/dist/actions.js.map +1 -1
- package/dist/api/route-helpers.d.ts +8 -0
- package/dist/api/route-helpers.d.ts.map +1 -1
- package/dist/api/route-helpers.js +20 -0
- package/dist/api/route-helpers.js.map +1 -1
- package/dist/api/routes/ai-seo.d.ts.map +1 -1
- package/dist/api/routes/ai-seo.js +32 -1
- package/dist/api/routes/ai-seo.js.map +1 -1
- package/dist/api/routes/auth.d.ts.map +1 -1
- package/dist/api/routes/auth.js +2 -1
- package/dist/api/routes/auth.js.map +1 -1
- package/dist/api/routes/documents.d.ts.map +1 -1
- package/dist/api/routes/documents.js +3 -3
- package/dist/api/routes/documents.js.map +1 -1
- package/dist/api/routes/seo-public.d.ts.map +1 -1
- package/dist/api/routes/seo-public.js +371 -62
- package/dist/api/routes/seo-public.js.map +1 -1
- package/dist/api/routes/seo.d.ts.map +1 -1
- package/dist/api/routes/seo.js +21 -10
- package/dist/api/routes/seo.js.map +1 -1
- package/dist/api/routes/url-resolution.d.ts.map +1 -1
- package/dist/api/routes/url-resolution.js +40 -1
- package/dist/api/routes/url-resolution.js.map +1 -1
- package/dist/api/routes/users.d.ts.map +1 -1
- package/dist/api/routes/users.js +6 -3
- package/dist/api/routes/users.js.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -0
- package/dist/client.js.map +1 -1
- package/dist/config/types.d.ts +35 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/content/index.d.ts +1 -0
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/content/slug.d.ts +40 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +78 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/structured-data.d.ts +6 -0
- package/dist/content/structured-data.d.ts.map +1 -1
- package/dist/content/structured-data.js +6 -0
- package/dist/content/structured-data.js.map +1 -1
- package/dist/content-health/scanner.d.ts +4 -3
- package/dist/content-health/scanner.d.ts.map +1 -1
- package/dist/content-health/scanner.js +6 -12
- package/dist/content-health/scanner.js.map +1 -1
- package/dist/middleware.d.ts +1 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +11 -2
- package/dist/middleware.js.map +1 -1
- package/dist/redirects/auto.d.ts +45 -0
- package/dist/redirects/auto.d.ts.map +1 -0
- package/dist/redirects/auto.js +55 -0
- package/dist/redirects/auto.js.map +1 -0
- package/dist/redirects/index.d.ts +2 -0
- package/dist/redirects/index.d.ts.map +1 -1
- package/dist/redirects/index.js +1 -0
- package/dist/redirects/index.js.map +1 -1
- package/dist/seo/ai-bots.d.ts +42 -0
- package/dist/seo/ai-bots.d.ts.map +1 -0
- package/dist/seo/ai-bots.js +104 -0
- package/dist/seo/ai-bots.js.map +1 -0
- package/dist/seo/alt-text.d.ts +39 -0
- package/dist/seo/alt-text.d.ts.map +1 -0
- package/dist/seo/alt-text.js +67 -0
- package/dist/seo/alt-text.js.map +1 -0
- package/dist/seo/analysis.d.ts.map +1 -1
- package/dist/seo/analysis.js +7 -11
- package/dist/seo/analysis.js.map +1 -1
- package/dist/seo/audit-engine.d.ts +1 -0
- package/dist/seo/audit-engine.d.ts.map +1 -1
- package/dist/seo/audit-engine.js +4 -4
- package/dist/seo/audit-engine.js.map +1 -1
- package/dist/seo/audit-runner.d.ts.map +1 -1
- package/dist/seo/audit-runner.js +1 -0
- package/dist/seo/audit-runner.js.map +1 -1
- package/dist/seo/feeds.d.ts +36 -0
- package/dist/seo/feeds.d.ts.map +1 -0
- package/dist/seo/feeds.js +71 -0
- package/dist/seo/feeds.js.map +1 -0
- package/dist/seo/index.d.ts +9 -3
- package/dist/seo/index.d.ts.map +1 -1
- package/dist/seo/index.js +5 -2
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/llms-txt.d.ts.map +1 -1
- package/dist/seo/llms-txt.js +13 -2
- package/dist/seo/llms-txt.js.map +1 -1
- package/dist/seo/meta-tags.d.ts +14 -0
- package/dist/seo/meta-tags.d.ts.map +1 -1
- package/dist/seo/meta-tags.js +21 -2
- package/dist/seo/meta-tags.js.map +1 -1
- package/dist/seo/page-meta.d.ts +47 -0
- package/dist/seo/page-meta.d.ts.map +1 -1
- package/dist/seo/page-meta.js +280 -70
- package/dist/seo/page-meta.js.map +1 -1
- package/dist/seo/sitemap-notify.d.ts +30 -0
- package/dist/seo/sitemap-notify.d.ts.map +1 -1
- package/dist/seo/sitemap-notify.js +87 -0
- package/dist/seo/sitemap-notify.js.map +1 -1
- package/dist/validation/publish.d.ts +53 -0
- package/dist/validation/publish.d.ts.map +1 -0
- package/dist/validation/publish.js +75 -0
- package/dist/validation/publish.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/content/structured-data.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/content/structured-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -71,9 +71,10 @@ export interface ScannerOptions {
|
|
|
71
71
|
siteOrigin?: string | null;
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
|
-
* Count <img> tags in the HTML that
|
|
75
|
-
*
|
|
76
|
-
*
|
|
74
|
+
* Count <img> tags in the HTML that are missing alt text, excluding images
|
|
75
|
+
* correctly marked decorative (empty alt + role="presentation"/aria-hidden).
|
|
76
|
+
* Delegates to the shared, decorative-aware analyzer so every SEO surface
|
|
77
|
+
* (analysis, audit engine, this scanner, the cron scan) agrees.
|
|
77
78
|
*/
|
|
78
79
|
export declare function countMissingAltImages(html: string): number;
|
|
79
80
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/content-health/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/content-health/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAMH,MAAM,MAAM,gBAAgB,GACxB,0BAA0B,GAC1B,kBAAkB,GAClB,sBAAsB,GACtB,kBAAkB,CAAA;AAEtB,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,SAAS,EAAE,IAAI,CAAA;IACf,WAAW,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;IACtD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAsCD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUnD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA8BlD;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBhG;AAID;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,YAAY,EACjB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,YAAY,EAAE,CAAC,CA4DzB"}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* collapse to one row per (document, type) with `count` carrying
|
|
32
32
|
* the per-document magnitude.
|
|
33
33
|
*/
|
|
34
|
+
import { countMissingAltImages as sharedCountMissingAltImages } from '../seo/alt-text.js';
|
|
34
35
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
35
36
|
/**
|
|
36
37
|
* Return the longest plausible HTML payload from a document. CMS
|
|
@@ -67,20 +68,13 @@ function getMetaDescription(data) {
|
|
|
67
68
|
return null;
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
|
-
* Count <img> tags in the HTML that
|
|
71
|
-
*
|
|
72
|
-
*
|
|
71
|
+
* Count <img> tags in the HTML that are missing alt text, excluding images
|
|
72
|
+
* correctly marked decorative (empty alt + role="presentation"/aria-hidden).
|
|
73
|
+
* Delegates to the shared, decorative-aware analyzer so every SEO surface
|
|
74
|
+
* (analysis, audit engine, this scanner, the cron scan) agrees.
|
|
73
75
|
*/
|
|
74
76
|
export function countMissingAltImages(html) {
|
|
75
|
-
|
|
76
|
-
return 0;
|
|
77
|
-
const re = /<img(?![^>]*\salt\s*=)[^>]*>/gi;
|
|
78
|
-
let count = 0;
|
|
79
|
-
// We don't iterate matches into an array — just count, so memory
|
|
80
|
-
// stays bounded even on huge pages.
|
|
81
|
-
while (re.exec(html) !== null)
|
|
82
|
-
count++;
|
|
83
|
-
return count;
|
|
77
|
+
return sharedCountMissingAltImages(html);
|
|
84
78
|
}
|
|
85
79
|
/**
|
|
86
80
|
* Extract candidate URLs from <a href="..."> attributes. Returns
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/content-health/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/content-health/scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/middleware.d.ts
CHANGED
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAKzD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,UAAU,uBAAuB;IAC/B,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAKzD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,UAAU,uBAAuB;IAC/B,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;IAC3F,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAKD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,GAAG,uBAAuB,IAQnD,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA2EhF"}
|
package/dist/middleware.js
CHANGED
|
@@ -6,11 +6,15 @@ import { getClientIp, isResolvedIp } from './security/client-ip.js';
|
|
|
6
6
|
// `as unknown as` cast, while still tolerating the looser shape used in tests.
|
|
7
7
|
export function createCMSMiddleware(cmsConfig) {
|
|
8
8
|
const adminPath = cmsConfig.admin?.path ?? '/admin';
|
|
9
|
+
// Split-login installs serve the auth screens on their own mount; it gets
|
|
10
|
+
// the same guards (IP allowlist, CMS_SECRET check) as the admin itself.
|
|
11
|
+
const loginPath = cmsConfig.admin?.loginPath;
|
|
9
12
|
const ipAllowlist = cmsConfig.admin?.ipAllowlist;
|
|
10
13
|
const secret = process.env.CMS_SECRET ?? '';
|
|
11
14
|
return async function cmsMiddleware(request) {
|
|
12
15
|
const url = new URL(request.url);
|
|
13
|
-
const isAdminRoute = pathMatchesPrefix(url.pathname, adminPath)
|
|
16
|
+
const isAdminRoute = pathMatchesPrefix(url.pathname, adminPath) ||
|
|
17
|
+
(loginPath ? pathMatchesPrefix(url.pathname, loginPath) : false);
|
|
14
18
|
const isCMSApiRoute = pathMatchesPrefix(url.pathname, '/api/cms');
|
|
15
19
|
if (!isAdminRoute && !isCMSApiRoute) {
|
|
16
20
|
return null;
|
|
@@ -21,6 +25,9 @@ export function createCMSMiddleware(cmsConfig) {
|
|
|
21
25
|
// checks during initial install.
|
|
22
26
|
const isSetupRoute = url.pathname === `${adminPath}/setup` ||
|
|
23
27
|
url.pathname.startsWith(`${adminPath}/setup/`) ||
|
|
28
|
+
(loginPath
|
|
29
|
+
? url.pathname === `${loginPath}/setup` || url.pathname.startsWith(`${loginPath}/setup/`)
|
|
30
|
+
: false) ||
|
|
24
31
|
url.pathname.startsWith('/api/cms/setup');
|
|
25
32
|
if (isSetupRoute) {
|
|
26
33
|
return null;
|
|
@@ -59,7 +66,9 @@ export function createCMSMiddleware(cmsConfig) {
|
|
|
59
66
|
return new Response(null, {
|
|
60
67
|
status: 302,
|
|
61
68
|
headers: {
|
|
62
|
-
|
|
69
|
+
// Expired/invalid session: send the user where they can sign in
|
|
70
|
+
// again — the dedicated login mount on split-login installs.
|
|
71
|
+
Location: loginPath ?? adminPath,
|
|
63
72
|
'Set-Cookie': 'actuate_session=; Path=/; HttpOnly; Max-Age=0',
|
|
64
73
|
},
|
|
65
74
|
});
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAYnE,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CAAC,SAAqD;IACvF,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,IAAI,QAAQ,CAAA;IACnD,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,EAAE,WAAW,CAAA;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAA;IAE3C,OAAO,KAAK,UAAU,aAAa,CAAC,OAAgB;QAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAEhC,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-301 planning for slug/path changes.
|
|
3
|
+
*
|
|
4
|
+
* When a *published* document's resolved URL changes, the old URL was already
|
|
5
|
+
* crawled/linked/indexed and must not 404. This module computes — as a pure,
|
|
6
|
+
* fully testable function — the redirect mutations needed to keep the old URL
|
|
7
|
+
* alive without building chains or loops:
|
|
8
|
+
*
|
|
9
|
+
* 1. Drop any rule whose source is the new (now-live) path, which would
|
|
10
|
+
* otherwise redirect the page away from itself.
|
|
11
|
+
* 2. Repoint any rule that pointed at the old path so it points at the new
|
|
12
|
+
* path directly (chain flattening — never old→mid→new).
|
|
13
|
+
* 3. Add old→new, but only if the simulated post-mutation rule set stays
|
|
14
|
+
* loop-free (e.g. a pre-existing new→old rule we are not removing).
|
|
15
|
+
*
|
|
16
|
+
* The caller (actions.ts) applies the returned plan in a single transaction.
|
|
17
|
+
*/
|
|
18
|
+
import { type RedirectRecord } from './graph.js';
|
|
19
|
+
export interface SlugRedirectPlan {
|
|
20
|
+
/** Redirect to create or upsert (source already normalized), or null to skip. */
|
|
21
|
+
upsert: {
|
|
22
|
+
source: string;
|
|
23
|
+
destination: string;
|
|
24
|
+
} | null;
|
|
25
|
+
/** Existing redirect ids to delete (their source is the now-live new path). */
|
|
26
|
+
deleteIds: string[];
|
|
27
|
+
/** Existing redirects to repoint at the new path (chain flattening). */
|
|
28
|
+
repoint: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
destination: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
/** True when the plan would make no database changes. */
|
|
34
|
+
export declare function isEmptyPlan(plan: SlugRedirectPlan): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Compute the redirect mutations for a slug/path change. Both paths are
|
|
37
|
+
* site-relative (e.g. `/old-about`); normalization (leading slash, no trailing
|
|
38
|
+
* slash, lowercase) is applied internally and matches request-time matching.
|
|
39
|
+
*/
|
|
40
|
+
export declare function planSlugChangeRedirects(params: {
|
|
41
|
+
oldPath: string;
|
|
42
|
+
newPath: string;
|
|
43
|
+
existing: RedirectRecord[];
|
|
44
|
+
}): SlugRedirectPlan;
|
|
45
|
+
//# sourceMappingURL=auto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/redirects/auto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAA;AAExF,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACtD,+EAA+E;IAC/E,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,wEAAwE;IACxE,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACpD;AAID,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,cAAc,EAAE,CAAA;CAC3B,GAAG,gBAAgB,CAiCnB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-301 planning for slug/path changes.
|
|
3
|
+
*
|
|
4
|
+
* When a *published* document's resolved URL changes, the old URL was already
|
|
5
|
+
* crawled/linked/indexed and must not 404. This module computes — as a pure,
|
|
6
|
+
* fully testable function — the redirect mutations needed to keep the old URL
|
|
7
|
+
* alive without building chains or loops:
|
|
8
|
+
*
|
|
9
|
+
* 1. Drop any rule whose source is the new (now-live) path, which would
|
|
10
|
+
* otherwise redirect the page away from itself.
|
|
11
|
+
* 2. Repoint any rule that pointed at the old path so it points at the new
|
|
12
|
+
* path directly (chain flattening — never old→mid→new).
|
|
13
|
+
* 3. Add old→new, but only if the simulated post-mutation rule set stays
|
|
14
|
+
* loop-free (e.g. a pre-existing new→old rule we are not removing).
|
|
15
|
+
*
|
|
16
|
+
* The caller (actions.ts) applies the returned plan in a single transaction.
|
|
17
|
+
*/
|
|
18
|
+
import { normalizeRedirectPath, wouldCreateLoop } from './graph.js';
|
|
19
|
+
const EMPTY_PLAN = { upsert: null, deleteIds: [], repoint: [] };
|
|
20
|
+
/** True when the plan would make no database changes. */
|
|
21
|
+
export function isEmptyPlan(plan) {
|
|
22
|
+
return !plan.upsert && plan.deleteIds.length === 0 && plan.repoint.length === 0;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compute the redirect mutations for a slug/path change. Both paths are
|
|
26
|
+
* site-relative (e.g. `/old-about`); normalization (leading slash, no trailing
|
|
27
|
+
* slash, lowercase) is applied internally and matches request-time matching.
|
|
28
|
+
*/
|
|
29
|
+
export function planSlugChangeRedirects(params) {
|
|
30
|
+
const oldN = normalizeRedirectPath(params.oldPath);
|
|
31
|
+
const newN = normalizeRedirectPath(params.newPath);
|
|
32
|
+
// Nothing to do when the URL did not actually change. Never redirect the
|
|
33
|
+
// site root onto itself or onto a child — a homepage "move" is almost always
|
|
34
|
+
// an unrelated path edit and a `/` → /x rule would break the whole site.
|
|
35
|
+
if (!oldN || !newN || oldN === newN || oldN === '/')
|
|
36
|
+
return EMPTY_PLAN;
|
|
37
|
+
const deleteIds = params.existing
|
|
38
|
+
.filter((r) => normalizeRedirectPath(r.from) === newN)
|
|
39
|
+
.map((r) => r.id);
|
|
40
|
+
const repoint = params.existing
|
|
41
|
+
.filter((r) => !deleteIds.includes(r.id) &&
|
|
42
|
+
normalizeRedirectPath(r.to) === oldN &&
|
|
43
|
+
normalizeRedirectPath(r.from) !== newN)
|
|
44
|
+
.map((r) => ({ id: r.id, destination: newN }));
|
|
45
|
+
// Simulate the post-mutation rule set (deletes applied, repoints applied)
|
|
46
|
+
// and only add the new edge if it stays loop-free.
|
|
47
|
+
const remaining = params.existing
|
|
48
|
+
.filter((r) => !deleteIds.includes(r.id))
|
|
49
|
+
.map((r) => (repoint.some((p) => p.id === r.id) ? { ...r, to: newN } : r));
|
|
50
|
+
if (wouldCreateLoop(remaining, oldN, newN)) {
|
|
51
|
+
return { upsert: null, deleteIds, repoint };
|
|
52
|
+
}
|
|
53
|
+
return { upsert: { source: oldN, destination: newN }, deleteIds, repoint };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=auto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto.js","sourceRoot":"","sources":["../../src/redirects/auto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAuB,MAAM,YAAY,CAAA;AAWxF,MAAM,UAAU,GAAqB,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;AAEjF,yDAAyD;AACzD,MAAM,UAAU,WAAW,CAAC,IAAsB;IAChD,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAA;AACjF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAIvC;IACC,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAClD,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAElD,yEAAyE;IACzE,6EAA6E;IAC7E,yEAAyE;IACzE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG;QAAE,OAAO,UAAU,CAAA;IAEtE,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;SACrD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAEnB,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ;SAC5B,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI;QACpC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CACzC;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAEhD,0EAA0E;IAC1E,mDAAmD;IACnD,MAAM,SAAS,GAAqB,MAAM,CAAC,QAAQ;SAChD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAE5E,IAAI,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;IAC7C,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AAC5E,CAAC"}
|
|
@@ -2,4 +2,6 @@ export { normalizeRedirectPath, isExternal, buildEdgeMap, resolveChain, detectCh
|
|
|
2
2
|
export type { RedirectRecord, ChainResolution, DetectedChain } from './graph.js';
|
|
3
3
|
export { suggestRedirectTarget } from './suggest.js';
|
|
4
4
|
export type { SuggestCandidate, RedirectSuggestionResult } from './suggest.js';
|
|
5
|
+
export { planSlugChangeRedirects, isEmptyPlan } from './auto.js';
|
|
6
|
+
export type { SlugRedirectPlan } from './auto.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redirects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEhF,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,YAAY,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/redirects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEhF,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEpD,YAAY,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAE9E,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEhE,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/redirects/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { normalizeRedirectPath, isExternal, buildEdgeMap, resolveChain, detectChainsAndLoops, wouldCreateLoop, isRedirectStale, } from './graph.js';
|
|
2
2
|
export { suggestRedirectTarget } from './suggest.js';
|
|
3
|
+
export { planSlugChangeRedirects, isEmptyPlan } from './auto.js';
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/redirects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AAInB,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/redirects/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AAInB,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAIpD,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI crawler taxonomy + robots.txt policy.
|
|
3
|
+
*
|
|
4
|
+
* Not all "AI bots" are equal, and blocking them all is usually the wrong call
|
|
5
|
+
* for visibility:
|
|
6
|
+
*
|
|
7
|
+
* - TRAINING crawlers ingest your content into model weights and never send a
|
|
8
|
+
* user or a citation back. Blocking these has little downside for traffic
|
|
9
|
+
* and is what most "block AI" intentions actually mean.
|
|
10
|
+
* - RETRIEVAL / answer-engine crawlers fetch a page to answer a user's live
|
|
11
|
+
* query and typically cite + link the source (ChatGPT browsing, Perplexity,
|
|
12
|
+
* etc.). Blocking these removes you from AI answers — usually undesirable.
|
|
13
|
+
*
|
|
14
|
+
* So we model the two independently. Lists are curated for 2026 and grouped by
|
|
15
|
+
* vendor for maintainability; keep them conservative (only well-attested UA
|
|
16
|
+
* tokens) to avoid accidentally blocking a general search crawler.
|
|
17
|
+
*/
|
|
18
|
+
/** Crawlers that ingest content for model TRAINING (no citation, no referral). */
|
|
19
|
+
export declare const AI_TRAINING_BOTS: readonly string[];
|
|
20
|
+
/** Answer-engine / live-retrieval crawlers (cite + refer users back). */
|
|
21
|
+
export declare const AI_RETRIEVAL_BOTS: readonly string[];
|
|
22
|
+
export type AiBotStance = 'allow' | 'block';
|
|
23
|
+
export interface AiBotPolicy {
|
|
24
|
+
/** Stance toward TRAINING crawlers. Default `allow`. */
|
|
25
|
+
training?: AiBotStance;
|
|
26
|
+
/** Stance toward RETRIEVAL / answer-engine crawlers. Default `allow`. */
|
|
27
|
+
retrieval?: AiBotStance;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the robots.txt User-agent/Disallow line groups for blocked AI bots.
|
|
31
|
+
*
|
|
32
|
+
* Precedence:
|
|
33
|
+
* 1. An explicit `policy` (nuanced training vs retrieval) wins.
|
|
34
|
+
* 2. Otherwise the legacy `blockAIBots` boolean blocks BOTH groups (preserves
|
|
35
|
+
* pre-nuance behavior for sites that set it).
|
|
36
|
+
* 3. Otherwise nothing is emitted.
|
|
37
|
+
*
|
|
38
|
+
* Returns a flat array of robots.txt lines (each blocked bot gets its own
|
|
39
|
+
* `User-agent` + `Disallow: /` + blank-line group). Pure + deterministic.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildAiBotRobotsLines(policy: AiBotPolicy | undefined, legacyBlockAIBots: boolean | undefined): string[];
|
|
42
|
+
//# sourceMappingURL=ai-bots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-bots.d.ts","sourceRoot":"","sources":["../../src/seo/ai-bots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EA0B7C,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAiB9C,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,yEAAyE;IACzE,SAAS,CAAC,EAAE,WAAW,CAAA;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,iBAAiB,EAAE,OAAO,GAAG,SAAS,GACrC,MAAM,EAAE,CAyBV"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI crawler taxonomy + robots.txt policy.
|
|
3
|
+
*
|
|
4
|
+
* Not all "AI bots" are equal, and blocking them all is usually the wrong call
|
|
5
|
+
* for visibility:
|
|
6
|
+
*
|
|
7
|
+
* - TRAINING crawlers ingest your content into model weights and never send a
|
|
8
|
+
* user or a citation back. Blocking these has little downside for traffic
|
|
9
|
+
* and is what most "block AI" intentions actually mean.
|
|
10
|
+
* - RETRIEVAL / answer-engine crawlers fetch a page to answer a user's live
|
|
11
|
+
* query and typically cite + link the source (ChatGPT browsing, Perplexity,
|
|
12
|
+
* etc.). Blocking these removes you from AI answers — usually undesirable.
|
|
13
|
+
*
|
|
14
|
+
* So we model the two independently. Lists are curated for 2026 and grouped by
|
|
15
|
+
* vendor for maintainability; keep them conservative (only well-attested UA
|
|
16
|
+
* tokens) to avoid accidentally blocking a general search crawler.
|
|
17
|
+
*/
|
|
18
|
+
/** Crawlers that ingest content for model TRAINING (no citation, no referral). */
|
|
19
|
+
export const AI_TRAINING_BOTS = [
|
|
20
|
+
// OpenAI
|
|
21
|
+
'GPTBot',
|
|
22
|
+
// Anthropic
|
|
23
|
+
'ClaudeBot',
|
|
24
|
+
'anthropic-ai',
|
|
25
|
+
// Google (Gemini training; distinct from Googlebot search)
|
|
26
|
+
'Google-Extended',
|
|
27
|
+
// Common Crawl (feeds many training sets)
|
|
28
|
+
'CCBot',
|
|
29
|
+
// ByteDance
|
|
30
|
+
'Bytespider',
|
|
31
|
+
// Apple (Apple Intelligence training; distinct from Applebot search)
|
|
32
|
+
'Applebot-Extended',
|
|
33
|
+
// Meta
|
|
34
|
+
'Meta-ExternalAgent',
|
|
35
|
+
'FacebookBot',
|
|
36
|
+
// Misc training/scraping crawlers
|
|
37
|
+
'Diffbot',
|
|
38
|
+
'Omgilibot',
|
|
39
|
+
'omgili',
|
|
40
|
+
'PanguBot',
|
|
41
|
+
'Timpibot',
|
|
42
|
+
'cohere-ai',
|
|
43
|
+
'ImagesiftBot',
|
|
44
|
+
'PetalBot',
|
|
45
|
+
];
|
|
46
|
+
/** Answer-engine / live-retrieval crawlers (cite + refer users back). */
|
|
47
|
+
export const AI_RETRIEVAL_BOTS = [
|
|
48
|
+
// OpenAI
|
|
49
|
+
'OAI-SearchBot',
|
|
50
|
+
'ChatGPT-User',
|
|
51
|
+
// Perplexity
|
|
52
|
+
'PerplexityBot',
|
|
53
|
+
'Perplexity-User',
|
|
54
|
+
// Anthropic retrieval
|
|
55
|
+
'Claude-Web',
|
|
56
|
+
'Claude-User',
|
|
57
|
+
// Apple search (Siri/Spotlight)
|
|
58
|
+
'Applebot',
|
|
59
|
+
// Amazon (Alexa)
|
|
60
|
+
'Amazonbot',
|
|
61
|
+
// You.com / DuckDuckGo assist
|
|
62
|
+
'YouBot',
|
|
63
|
+
'DuckAssistBot',
|
|
64
|
+
];
|
|
65
|
+
/**
|
|
66
|
+
* Build the robots.txt User-agent/Disallow line groups for blocked AI bots.
|
|
67
|
+
*
|
|
68
|
+
* Precedence:
|
|
69
|
+
* 1. An explicit `policy` (nuanced training vs retrieval) wins.
|
|
70
|
+
* 2. Otherwise the legacy `blockAIBots` boolean blocks BOTH groups (preserves
|
|
71
|
+
* pre-nuance behavior for sites that set it).
|
|
72
|
+
* 3. Otherwise nothing is emitted.
|
|
73
|
+
*
|
|
74
|
+
* Returns a flat array of robots.txt lines (each blocked bot gets its own
|
|
75
|
+
* `User-agent` + `Disallow: /` + blank-line group). Pure + deterministic.
|
|
76
|
+
*/
|
|
77
|
+
export function buildAiBotRobotsLines(policy, legacyBlockAIBots) {
|
|
78
|
+
let blockTraining;
|
|
79
|
+
let blockRetrieval;
|
|
80
|
+
if (policy && (policy.training || policy.retrieval)) {
|
|
81
|
+
blockTraining = policy.training === 'block';
|
|
82
|
+
blockRetrieval = policy.retrieval === 'block';
|
|
83
|
+
}
|
|
84
|
+
else if (legacyBlockAIBots) {
|
|
85
|
+
blockTraining = true;
|
|
86
|
+
blockRetrieval = true;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const bots = [];
|
|
92
|
+
if (blockTraining)
|
|
93
|
+
bots.push(...AI_TRAINING_BOTS);
|
|
94
|
+
if (blockRetrieval)
|
|
95
|
+
bots.push(...AI_RETRIEVAL_BOTS);
|
|
96
|
+
const lines = [];
|
|
97
|
+
for (const bot of bots) {
|
|
98
|
+
lines.push(`User-agent: ${bot}`);
|
|
99
|
+
lines.push('Disallow: /');
|
|
100
|
+
lines.push('');
|
|
101
|
+
}
|
|
102
|
+
return lines;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=ai-bots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-bots.js","sourceRoot":"","sources":["../../src/seo/ai-bots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,SAAS;IACT,QAAQ;IACR,YAAY;IACZ,WAAW;IACX,cAAc;IACd,2DAA2D;IAC3D,iBAAiB;IACjB,0CAA0C;IAC1C,OAAO;IACP,YAAY;IACZ,YAAY;IACZ,qEAAqE;IACrE,mBAAmB;IACnB,OAAO;IACP,oBAAoB;IACpB,aAAa;IACb,kCAAkC;IAClC,SAAS;IACT,WAAW;IACX,QAAQ;IACR,UAAU;IACV,UAAU;IACV,WAAW;IACX,cAAc;IACd,UAAU;CACX,CAAA;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,SAAS;IACT,eAAe;IACf,cAAc;IACd,aAAa;IACb,eAAe;IACf,iBAAiB;IACjB,sBAAsB;IACtB,YAAY;IACZ,aAAa;IACb,gCAAgC;IAChC,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,8BAA8B;IAC9B,QAAQ;IACR,eAAe;CAChB,CAAA;AAWD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAA+B,EAC/B,iBAAsC;IAEtC,IAAI,aAAsB,CAAA;IAC1B,IAAI,cAAuB,CAAA;IAE3B,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QACpD,aAAa,GAAG,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAA;QAC3C,cAAc,GAAG,MAAM,CAAC,SAAS,KAAK,OAAO,CAAA;IAC/C,CAAC;SAAM,IAAI,iBAAiB,EAAE,CAAC;QAC7B,aAAa,GAAG,IAAI,CAAA;QACpB,cAAc,GAAG,IAAI,CAAA;IACvB,CAAC;SAAM,CAAC;QACN,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,IAAI,aAAa;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAA;IACjD,IAAI,cAAc;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAA;IAEnD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,CAAA;QAChC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical image alt-text analysis, shared by every surface that reports on
|
|
3
|
+
* alt coverage (SEO analysis, the audit engine, the content-health scanner, the
|
|
4
|
+
* cron scan). Previously each had its own regex and they disagreed on the most
|
|
5
|
+
* important edge case — an intentionally *decorative* image — which produced
|
|
6
|
+
* conflicting "missing alt" counts.
|
|
7
|
+
*
|
|
8
|
+
* Rules (chosen to match the long-standing scanner/cron contract: an explicit
|
|
9
|
+
* empty `alt=""` is an intentional, valid decorative choice — only a *missing*
|
|
10
|
+
* `alt` attribute is an error):
|
|
11
|
+
* - DECORATIVE: an empty `alt=""` (the author opted the image out of the
|
|
12
|
+
* accessibility tree), or any image explicitly marked decorative for
|
|
13
|
+
* assistive tech (`role="presentation"`, `role="none"`, `aria-hidden="true"`).
|
|
14
|
+
* Decorative images are correct and never flagged as missing.
|
|
15
|
+
* - MISSING: a non-decorative image with no `alt` attribute at all.
|
|
16
|
+
* - HAS ALT: a non-empty `alt`.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* True when an `<img>` tag is decorative: either an explicit empty `alt=""`, or
|
|
20
|
+
* marked decorative for assistive tech (`role="presentation"`/`"none"` or
|
|
21
|
+
* `aria-hidden="true"`). A descriptive (non-empty) alt is never decorative.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isDecorativeImgTag(tag: string): boolean;
|
|
24
|
+
export interface ImageAltAnalysis {
|
|
25
|
+
/** All `<img>` tags found. */
|
|
26
|
+
total: number;
|
|
27
|
+
/** Non-decorative images that have non-empty alt text. */
|
|
28
|
+
withAlt: number;
|
|
29
|
+
/** Images correctly marked decorative (excluded from coverage math). */
|
|
30
|
+
decorative: number;
|
|
31
|
+
/** Non-decorative images with no/empty alt. */
|
|
32
|
+
missing: number;
|
|
33
|
+
/** The non-empty alt strings, trimmed. */
|
|
34
|
+
altTexts: string[];
|
|
35
|
+
}
|
|
36
|
+
export declare function analyzeImageAlts(html: string | null | undefined): ImageAltAnalysis;
|
|
37
|
+
/** Count images missing alt text (decorative images excluded). */
|
|
38
|
+
export declare function countMissingAltImages(html: string | null | undefined): number;
|
|
39
|
+
//# sourceMappingURL=alt-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alt-text.d.ts","sourceRoot":"","sources":["../../src/seo/alt-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAA;IAClB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,gBAAgB,CAiBlF;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE7E"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical image alt-text analysis, shared by every surface that reports on
|
|
3
|
+
* alt coverage (SEO analysis, the audit engine, the content-health scanner, the
|
|
4
|
+
* cron scan). Previously each had its own regex and they disagreed on the most
|
|
5
|
+
* important edge case — an intentionally *decorative* image — which produced
|
|
6
|
+
* conflicting "missing alt" counts.
|
|
7
|
+
*
|
|
8
|
+
* Rules (chosen to match the long-standing scanner/cron contract: an explicit
|
|
9
|
+
* empty `alt=""` is an intentional, valid decorative choice — only a *missing*
|
|
10
|
+
* `alt` attribute is an error):
|
|
11
|
+
* - DECORATIVE: an empty `alt=""` (the author opted the image out of the
|
|
12
|
+
* accessibility tree), or any image explicitly marked decorative for
|
|
13
|
+
* assistive tech (`role="presentation"`, `role="none"`, `aria-hidden="true"`).
|
|
14
|
+
* Decorative images are correct and never flagged as missing.
|
|
15
|
+
* - MISSING: a non-decorative image with no `alt` attribute at all.
|
|
16
|
+
* - HAS ALT: a non-empty `alt`.
|
|
17
|
+
*/
|
|
18
|
+
const IMG_TAG_RE = /<img\b[^>]*>/gi;
|
|
19
|
+
function getAttr(tag, name) {
|
|
20
|
+
// The negative lookbehind prevents matching a hyphenated/namespaced attribute
|
|
21
|
+
// that merely *ends* with `name` (e.g. `data-default-alt="…"` must not be read
|
|
22
|
+
// as the `alt` attribute).
|
|
23
|
+
const m = tag.match(new RegExp(`(?<![-\\w:])${name}\\s*=\\s*["']([^"']*)["']`, 'i'));
|
|
24
|
+
return m ? (m[1] ?? '') : null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* True when an `<img>` tag is decorative: either an explicit empty `alt=""`, or
|
|
28
|
+
* marked decorative for assistive tech (`role="presentation"`/`"none"` or
|
|
29
|
+
* `aria-hidden="true"`). A descriptive (non-empty) alt is never decorative.
|
|
30
|
+
*/
|
|
31
|
+
export function isDecorativeImgTag(tag) {
|
|
32
|
+
const alt = getAttr(tag, 'alt');
|
|
33
|
+
if (alt !== null && alt.trim().length > 0)
|
|
34
|
+
return false;
|
|
35
|
+
if (alt !== null && alt.trim().length === 0)
|
|
36
|
+
return true;
|
|
37
|
+
// No alt attribute at all: decorative only if explicitly marked so.
|
|
38
|
+
const role = getAttr(tag, 'role')?.toLowerCase();
|
|
39
|
+
const ariaHidden = getAttr(tag, 'aria-hidden')?.toLowerCase();
|
|
40
|
+
return role === 'presentation' || role === 'none' || ariaHidden === 'true';
|
|
41
|
+
}
|
|
42
|
+
export function analyzeImageAlts(html) {
|
|
43
|
+
const result = { total: 0, withAlt: 0, decorative: 0, missing: 0, altTexts: [] };
|
|
44
|
+
if (!html)
|
|
45
|
+
return result;
|
|
46
|
+
const tags = html.match(IMG_TAG_RE) ?? [];
|
|
47
|
+
result.total = tags.length;
|
|
48
|
+
for (const tag of tags) {
|
|
49
|
+
const alt = getAttr(tag, 'alt');
|
|
50
|
+
if (alt !== null && alt.trim().length > 0) {
|
|
51
|
+
result.withAlt++;
|
|
52
|
+
result.altTexts.push(alt.trim());
|
|
53
|
+
}
|
|
54
|
+
else if (isDecorativeImgTag(tag)) {
|
|
55
|
+
result.decorative++;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
result.missing++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/** Count images missing alt text (decorative images excluded). */
|
|
64
|
+
export function countMissingAltImages(html) {
|
|
65
|
+
return analyzeImageAlts(html).missing;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=alt-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alt-text.js","sourceRoot":"","sources":["../../src/seo/alt-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,UAAU,GAAG,gBAAgB,CAAA;AAEnC,SAAS,OAAO,CAAC,GAAW,EAAE,IAAY;IACxC,8EAA8E;IAC9E,+EAA+E;IAC/E,2BAA2B;IAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,eAAe,IAAI,2BAA2B,EAAE,GAAG,CAAC,CAAC,CAAA;IACpF,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC/B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACxD,oEAAoE;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IAChD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,WAAW,EAAE,CAAA;IAC7D,OAAO,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,CAAA;AAC5E,CAAC;AAeD,MAAM,UAAU,gBAAgB,CAAC,IAA+B;IAC9D,MAAM,MAAM,GAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IAClG,IAAI,CAAC,IAAI;QAAE,OAAO,MAAM,CAAA;IACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;IACzC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC/B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,OAAO,EAAE,CAAA;YAChB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;QAClC,CAAC;aAAM,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,UAAU,EAAE,CAAA;QACrB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,EAAE,CAAA;QAClB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,qBAAqB,CAAC,IAA+B;IACnE,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAA;AACvC,CAAC"}
|