ax-audit 2.4.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +43 -17
  3. package/dist/checks/agent-json.d.ts +10 -0
  4. package/dist/checks/agent-json.d.ts.map +1 -1
  5. package/dist/checks/agent-json.js +66 -2
  6. package/dist/checks/agent-json.js.map +1 -1
  7. package/dist/checks/content-negotiation.d.ts +4 -0
  8. package/dist/checks/content-negotiation.d.ts.map +1 -0
  9. package/dist/checks/content-negotiation.js +138 -0
  10. package/dist/checks/content-negotiation.js.map +1 -0
  11. package/dist/checks/html-rendering.d.ts +21 -0
  12. package/dist/checks/html-rendering.d.ts.map +1 -0
  13. package/dist/checks/html-rendering.js +204 -0
  14. package/dist/checks/html-rendering.js.map +1 -0
  15. package/dist/checks/html-utils.d.ts +37 -0
  16. package/dist/checks/html-utils.d.ts.map +1 -0
  17. package/dist/checks/html-utils.js +93 -0
  18. package/dist/checks/html-utils.js.map +1 -0
  19. package/dist/checks/http-headers.js +1 -1
  20. package/dist/checks/http-headers.js.map +1 -1
  21. package/dist/checks/index.d.ts.map +1 -1
  22. package/dist/checks/index.js +12 -0
  23. package/dist/checks/index.js.map +1 -1
  24. package/dist/checks/llms-txt.d.ts.map +1 -1
  25. package/dist/checks/llms-txt.js +17 -2
  26. package/dist/checks/llms-txt.js.map +1 -1
  27. package/dist/checks/mcp.d.ts.map +1 -1
  28. package/dist/checks/mcp.js +11 -2
  29. package/dist/checks/mcp.js.map +1 -1
  30. package/dist/checks/meta-tags.d.ts +13 -0
  31. package/dist/checks/meta-tags.d.ts.map +1 -1
  32. package/dist/checks/meta-tags.js +104 -24
  33. package/dist/checks/meta-tags.js.map +1 -1
  34. package/dist/checks/openapi.d.ts.map +1 -1
  35. package/dist/checks/openapi.js +11 -2
  36. package/dist/checks/openapi.js.map +1 -1
  37. package/dist/checks/robots-txt.js +1 -1
  38. package/dist/checks/security-txt.js +1 -1
  39. package/dist/checks/seo-basics.d.ts +13 -0
  40. package/dist/checks/seo-basics.d.ts.map +1 -0
  41. package/dist/checks/seo-basics.js +222 -0
  42. package/dist/checks/seo-basics.js.map +1 -0
  43. package/dist/checks/sitemap.d.ts +12 -0
  44. package/dist/checks/sitemap.d.ts.map +1 -0
  45. package/dist/checks/sitemap.js +241 -0
  46. package/dist/checks/sitemap.js.map +1 -0
  47. package/dist/checks/structured-data.js +1 -1
  48. package/dist/checks/structured-data.js.map +1 -1
  49. package/dist/checks/tls-https.d.ts +13 -0
  50. package/dist/checks/tls-https.d.ts.map +1 -0
  51. package/dist/checks/tls-https.js +164 -0
  52. package/dist/checks/tls-https.js.map +1 -0
  53. package/dist/checks/utils.d.ts +13 -1
  54. package/dist/checks/utils.d.ts.map +1 -1
  55. package/dist/checks/utils.js +28 -0
  56. package/dist/checks/utils.js.map +1 -1
  57. package/dist/checks/well-known-ai.d.ts +17 -0
  58. package/dist/checks/well-known-ai.d.ts.map +1 -0
  59. package/dist/checks/well-known-ai.js +123 -0
  60. package/dist/checks/well-known-ai.js.map +1 -0
  61. package/dist/constants.d.ts +19 -0
  62. package/dist/constants.d.ts.map +1 -1
  63. package/dist/constants.js +50 -10
  64. package/dist/constants.js.map +1 -1
  65. package/dist/fetcher.d.ts +2 -2
  66. package/dist/fetcher.d.ts.map +1 -1
  67. package/dist/fetcher.js +42 -9
  68. package/dist/fetcher.js.map +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/scorer.d.ts.map +1 -1
  72. package/dist/scorer.js +8 -0
  73. package/dist/scorer.js.map +1 -1
  74. package/dist/types.d.ts +10 -1
  75. package/dist/types.d.ts.map +1 -1
  76. package/package.json +1 -1
@@ -1,12 +1,30 @@
1
1
  import { guideUrl } from '../guide-urls.js';
2
+ import { findLinkTags, findMetaTagsByPrefix, getMetaContent } from './html-utils.js';
2
3
  import { buildResult } from './utils.js';
4
+ /**
5
+ * "meta-tags" — AI-discovery and identity meta/link tags inside the HTML <head>.
6
+ *
7
+ * Scope:
8
+ * - Custom AI namespace (`ai:summary`, `ai:content_type`, `ai:author`, `ai:api`, `ai:agent_card`)
9
+ * - `<link rel="alternate">` pointing to llms.txt and agent.json
10
+ * - `rel="me"` identity links (IndieAuth / Mastodon-style verification)
11
+ * - OpenGraph completeness (`og:title`, `og:description`, `og:image`, `og:url`, `og:type`)
12
+ * - Twitter Card completeness (`twitter:card`, `twitter:title`, `twitter:description`, `twitter:image`)
13
+ *
14
+ * Title/description quality and canonical/lang/charset live in the `seo-basics` check
15
+ * to avoid double-penalty.
16
+ */
3
17
  export const meta = {
4
18
  id: 'meta-tags',
5
19
  name: 'Meta Tags',
6
- description: 'Checks AI meta tags, rel="alternate", and rel="me" links',
7
- weight: 8,
20
+ description: 'Checks AI meta tags, rel="alternate", rel="me", and Open Graph / Twitter Card completeness',
21
+ weight: 6,
8
22
  };
9
23
  const AI_META_NAMES = ['ai:summary', 'ai:content_type', 'ai:author', 'ai:api', 'ai:agent_card'];
24
+ const OG_REQUIRED = ['og:title', 'og:description', 'og:url', 'og:type'];
25
+ const OG_RECOMMENDED = ['og:image', 'og:site_name'];
26
+ const TWITTER_REQUIRED = ['twitter:card', 'twitter:title', 'twitter:description'];
27
+ const TWITTER_RECOMMENDED = ['twitter:image'];
10
28
  export default async function check(ctx) {
11
29
  const start = performance.now();
12
30
  const findings = [];
@@ -16,10 +34,7 @@ export default async function check(ctx) {
16
34
  findings.push({ status: 'fail', message: 'Could not fetch homepage HTML' });
17
35
  return buildResult(meta, 0, findings, start);
18
36
  }
19
- const foundAiMeta = AI_META_NAMES.filter((name) => {
20
- const pattern = new RegExp(`<meta\\s+[^>]*name=["']${escapeRegex(name)}["'][^>]*>`, 'i');
21
- return pattern.test(html);
22
- });
37
+ const foundAiMeta = AI_META_NAMES.filter((name) => getMetaContent(html, name) !== null);
23
38
  if (foundAiMeta.length >= 3) {
24
39
  findings.push({
25
40
  status: 'pass',
@@ -35,7 +50,7 @@ export default async function check(ctx) {
35
50
  hint: 'Add more AI meta tags to your <head>: <meta name="ai:summary" content="...">, <meta name="ai:content_type" content="...">, <meta name="ai:author" content="...">, etc.',
36
51
  learnMoreUrl: guideUrl(meta.id, 'few-ai-meta'),
37
52
  });
38
- score -= 15;
53
+ score -= 12;
39
54
  }
40
55
  else {
41
56
  findings.push({
@@ -44,9 +59,10 @@ export default async function check(ctx) {
44
59
  hint: 'Add AI meta tags to your HTML <head>: <meta name="ai:summary" content="Brief description">, <meta name="ai:content_type" content="website">, <meta name="ai:author" content="Your Name">.',
45
60
  learnMoreUrl: guideUrl(meta.id, 'no-ai-meta'),
46
61
  });
47
- score -= 25;
62
+ score -= 18;
48
63
  }
49
- const hasLlmsAlternate = /rel=["']alternate["'][^>]*llms\.txt/i.test(html) || /llms\.txt[^>]*rel=["']alternate["']/i.test(html);
64
+ const alternateTags = findLinkTags(html, 'alternate');
65
+ const hasLlmsAlternate = alternateTags.some((tag) => /href\s*=\s*["'][^"']*llms\.txt/i.test(tag));
50
66
  if (hasLlmsAlternate) {
51
67
  findings.push({ status: 'pass', message: 'rel="alternate" link to llms.txt present' });
52
68
  }
@@ -57,9 +73,9 @@ export default async function check(ctx) {
57
73
  hint: 'Add to your <head>: <link rel="alternate" type="text/plain" href="/llms.txt" title="LLM-optimized content">',
58
74
  learnMoreUrl: guideUrl(meta.id, 'no-llms-alternate'),
59
75
  });
60
- score -= 15;
76
+ score -= 12;
61
77
  }
62
- const hasAgentAlternate = /rel=["']alternate["'][^>]*agent\.json/i.test(html) || /agent\.json[^>]*rel=["']alternate["']/i.test(html);
78
+ const hasAgentAlternate = alternateTags.some((tag) => /href\s*=\s*["'][^"']*agent\.json/i.test(tag));
63
79
  if (hasAgentAlternate) {
64
80
  findings.push({ status: 'pass', message: 'rel="alternate" link to agent.json present' });
65
81
  }
@@ -70,10 +86,9 @@ export default async function check(ctx) {
70
86
  hint: 'Add to your <head>: <link rel="alternate" type="application/json" href="/.well-known/agent.json" title="Agent Card">',
71
87
  learnMoreUrl: guideUrl(meta.id, 'no-agent-alternate'),
72
88
  });
73
- score -= 10;
89
+ score -= 8;
74
90
  }
75
- const relMePattern = /rel=["']me["']/gi;
76
- const relMeCount = (html.match(relMePattern) ?? []).length;
91
+ const relMeCount = findLinkTags(html, 'me').length;
77
92
  if (relMeCount > 0) {
78
93
  findings.push({ status: 'pass', message: `${relMeCount} rel="me" identity link(s) found` });
79
94
  }
@@ -84,24 +99,89 @@ export default async function check(ctx) {
84
99
  hint: 'Add rel="me" links to verify your identity across platforms: <link rel="me" href="https://github.com/yourname">, <link rel="me" href="https://twitter.com/yourname">.',
85
100
  learnMoreUrl: guideUrl(meta.id, 'no-rel-me'),
86
101
  });
87
- score -= 10;
102
+ score -= 8;
88
103
  }
89
- const hasOg = /<meta\s+[^>]*property=["']og:/i.test(html);
90
- if (hasOg) {
91
- findings.push({ status: 'pass', message: 'OpenGraph meta tags present' });
92
- }
93
- else {
104
+ const ogPresent = countMetaPresence(html, OG_REQUIRED);
105
+ const ogRecommendedPresent = countMetaPresence(html, OG_RECOMMENDED);
106
+ if (findMetaTagsByPrefix(html, 'og:').length === 0) {
94
107
  findings.push({
95
108
  status: 'warn',
96
109
  message: 'No OpenGraph meta tags found',
97
- hint: 'Add OpenGraph meta tags for better social and AI sharing: <meta property="og:title" content="...">, <meta property="og:description" content="...">, <meta property="og:url" content="...">.',
110
+ hint: 'Add at minimum og:title, og:description, og:url, og:type, and og:image. Agents and link previews depend on these.',
98
111
  learnMoreUrl: guideUrl(meta.id, 'no-opengraph'),
99
112
  });
100
- score -= 10;
113
+ score -= 12;
114
+ }
115
+ else if (ogPresent.missing.length === 0) {
116
+ findings.push({
117
+ status: 'pass',
118
+ message: `OpenGraph required tags present (${OG_REQUIRED.join(', ')})`,
119
+ });
120
+ if (ogRecommendedPresent.missing.length > 0) {
121
+ findings.push({
122
+ status: 'warn',
123
+ message: `OpenGraph recommended tags missing: ${ogRecommendedPresent.missing.join(', ')}`,
124
+ hint: `Add these for richer previews: ${ogRecommendedPresent.missing.join(', ')}.`,
125
+ learnMoreUrl: guideUrl(meta.id, 'og-recommended-missing'),
126
+ });
127
+ score -= 3;
128
+ }
129
+ }
130
+ else {
131
+ findings.push({
132
+ status: 'warn',
133
+ message: `OpenGraph required tags missing: ${ogPresent.missing.join(', ')}`,
134
+ hint: `Add these meta tags: ${ogPresent.missing.map((t) => `<meta property="${t}" content="...">`).join(', ')}.`,
135
+ learnMoreUrl: guideUrl(meta.id, 'og-required-missing'),
136
+ });
137
+ score -= 8;
138
+ }
139
+ const twitterPresent = countMetaPresence(html, TWITTER_REQUIRED);
140
+ const twitterRecommendedPresent = countMetaPresence(html, TWITTER_RECOMMENDED);
141
+ if (findMetaTagsByPrefix(html, 'twitter:').length === 0) {
142
+ findings.push({
143
+ status: 'warn',
144
+ message: 'No Twitter Card meta tags found',
145
+ hint: 'Add twitter:card, twitter:title, twitter:description, and twitter:image so X / Threads / Bluesky / Discord agents render link previews correctly.',
146
+ learnMoreUrl: guideUrl(meta.id, 'no-twitter'),
147
+ });
148
+ score -= 6;
149
+ }
150
+ else if (twitterPresent.missing.length === 0) {
151
+ findings.push({
152
+ status: 'pass',
153
+ message: `Twitter Card required tags present (${TWITTER_REQUIRED.join(', ')})`,
154
+ });
155
+ if (twitterRecommendedPresent.missing.length > 0) {
156
+ findings.push({
157
+ status: 'warn',
158
+ message: `Twitter Card recommended tags missing: ${twitterRecommendedPresent.missing.join(', ')}`,
159
+ hint: 'Add twitter:image for richer previews.',
160
+ learnMoreUrl: guideUrl(meta.id, 'twitter-recommended-missing'),
161
+ });
162
+ score -= 2;
163
+ }
164
+ }
165
+ else {
166
+ findings.push({
167
+ status: 'warn',
168
+ message: `Twitter Card required tags missing: ${twitterPresent.missing.join(', ')}`,
169
+ hint: `Add these meta tags: ${twitterPresent.missing.map((t) => `<meta name="${t}" content="...">`).join(', ')}.`,
170
+ learnMoreUrl: guideUrl(meta.id, 'twitter-required-missing'),
171
+ });
172
+ score -= 5;
101
173
  }
102
174
  return buildResult(meta, score, findings, start);
103
175
  }
104
- function escapeRegex(str) {
105
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
176
+ function countMetaPresence(html, names) {
177
+ const present = [];
178
+ const missing = [];
179
+ for (const name of names) {
180
+ if (getMetaContent(html, name) !== null)
181
+ present.push(name);
182
+ else
183
+ missing.push(name);
184
+ }
185
+ return { present, missing };
106
186
  }
107
187
  //# sourceMappingURL=meta-tags.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta-tags.js","sourceRoot":"","sources":["../../src/checks/meta-tags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meta-tags.js","sourceRoot":"","sources":["../../src/checks/meta-tags.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/checks/openapi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAEF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAyG3E"}
1
+ {"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/checks/openapi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAEF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAmH3E"}
@@ -1,10 +1,10 @@
1
1
  import { guideUrl } from '../guide-urls.js';
2
- import { buildResult } from './utils.js';
2
+ import { buildResult, checkContentType } from './utils.js';
3
3
  export const meta = {
4
4
  id: 'openapi',
5
5
  name: 'OpenAPI Spec',
6
6
  description: 'Checks /.well-known/openapi.json presence and validity',
7
- weight: 8,
7
+ weight: 6,
8
8
  };
9
9
  export default async function check(ctx) {
10
10
  const start = performance.now();
@@ -22,6 +22,15 @@ export default async function check(ctx) {
22
22
  return buildResult(meta, 0, findings, start);
23
23
  }
24
24
  findings.push({ status: 'pass', message: '/.well-known/openapi.json exists' });
25
+ const ctFinding = checkContentType(res, ['application/json'], {
26
+ checkId: meta.id,
27
+ resourceLabel: '/.well-known/openapi.json',
28
+ anchor: 'wrong-content-type',
29
+ });
30
+ if (ctFinding) {
31
+ findings.push(ctFinding);
32
+ score -= 5;
33
+ }
25
34
  let data;
26
35
  try {
27
36
  data = JSON.parse(res.body);
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/checks/openapi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/checks/openapi.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ export const meta = {
5
5
  id: 'robots-txt',
6
6
  name: 'Robots.txt',
7
7
  description: 'Checks AI crawler configuration in robots.txt',
8
- weight: 15,
8
+ weight: 11,
9
9
  };
10
10
  export default async function check(ctx) {
11
11
  const start = performance.now();
@@ -5,7 +5,7 @@ export const meta = {
5
5
  id: 'security-txt',
6
6
  name: 'Security.txt',
7
7
  description: 'Checks /.well-known/security.txt RFC 9116 compliance',
8
- weight: 8,
8
+ weight: 6,
9
9
  };
10
10
  export default async function check(ctx) {
11
11
  const start = performance.now();
@@ -0,0 +1,13 @@
1
+ import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
+ /**
3
+ * "seo-basics" — the head-tag fundamentals every AI agent and search crawler relies on
4
+ * before anything else: `<title>`, `<meta description>`, `<link rel="canonical">`,
5
+ * `<html lang>`, `viewport`, `charset`, and `hreflang` for multilingual sites.
6
+ *
7
+ * These are not "SEO tricks"; they are the unambiguous identity, language, and topic
8
+ * signals an agent uses to summarize, rank, or cite a page. ax-audit treats this as
9
+ * baseline hygiene rather than optimization.
10
+ */
11
+ export declare const meta: CheckMeta;
12
+ export default function check(ctx: CheckContext): Promise<CheckResult>;
13
+ //# sourceMappingURL=seo-basics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-basics.d.ts","sourceRoot":"","sources":["../../src/checks/seo-basics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAIjF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAOF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAmM3E"}
@@ -0,0 +1,222 @@
1
+ import { guideUrl } from '../guide-urls.js';
2
+ import { extractVisibleText, findLinkTags, getAttribute, getMetaContent, getTagAttribute } from './html-utils.js';
3
+ import { buildResult } from './utils.js';
4
+ /**
5
+ * "seo-basics" — the head-tag fundamentals every AI agent and search crawler relies on
6
+ * before anything else: `<title>`, `<meta description>`, `<link rel="canonical">`,
7
+ * `<html lang>`, `viewport`, `charset`, and `hreflang` for multilingual sites.
8
+ *
9
+ * These are not "SEO tricks"; they are the unambiguous identity, language, and topic
10
+ * signals an agent uses to summarize, rank, or cite a page. ax-audit treats this as
11
+ * baseline hygiene rather than optimization.
12
+ */
13
+ export const meta = {
14
+ id: 'seo-basics',
15
+ name: 'SEO Basics',
16
+ description: 'Checks <title>, meta description, canonical, lang, charset, viewport, hreflang',
17
+ weight: 7,
18
+ };
19
+ const TITLE_MIN = 20;
20
+ const TITLE_MAX = 70;
21
+ const DESCRIPTION_MIN = 70;
22
+ const DESCRIPTION_MAX = 160;
23
+ export default async function check(ctx) {
24
+ const start = performance.now();
25
+ const findings = [];
26
+ let score = 100;
27
+ const html = ctx.html;
28
+ if (!html) {
29
+ findings.push({
30
+ status: 'fail',
31
+ message: 'Could not fetch homepage HTML',
32
+ hint: 'Verify the homepage returns a non-empty 200 response on the root URL.',
33
+ learnMoreUrl: guideUrl(meta.id, 'no-html'),
34
+ });
35
+ return buildResult(meta, 0, findings, start);
36
+ }
37
+ const titleMatch = html.match(/<title\b[^>]*>([\s\S]*?)<\/title>/i);
38
+ const title = titleMatch ? extractVisibleText(titleMatch[1]) : '';
39
+ if (!title) {
40
+ findings.push({
41
+ status: 'fail',
42
+ message: '<title> is missing or empty',
43
+ hint: 'Add a <title> in <head> describing the page in 20-70 characters. Agents quote it as the document name.',
44
+ learnMoreUrl: guideUrl(meta.id, 'no-title'),
45
+ });
46
+ score -= 25;
47
+ }
48
+ else if (title.length < TITLE_MIN) {
49
+ findings.push({
50
+ status: 'warn',
51
+ message: `<title> is too short (${title.length} chars): "${title}"`,
52
+ hint: `Lengthen the title to ${TITLE_MIN}-${TITLE_MAX} characters with a clear topic indicator.`,
53
+ learnMoreUrl: guideUrl(meta.id, 'short-title'),
54
+ });
55
+ score -= 10;
56
+ }
57
+ else if (title.length > TITLE_MAX) {
58
+ findings.push({
59
+ status: 'warn',
60
+ message: `<title> is too long (${title.length} chars)`,
61
+ detail: `"${title.slice(0, 80)}…"`,
62
+ hint: `Shorten the title to ${TITLE_MIN}-${TITLE_MAX} characters. Many agents and search engines truncate beyond ~70.`,
63
+ learnMoreUrl: guideUrl(meta.id, 'long-title'),
64
+ });
65
+ score -= 5;
66
+ }
67
+ else {
68
+ findings.push({ status: 'pass', message: `<title> length ${title.length} chars: "${title}"` });
69
+ }
70
+ const description = getMetaContent(html, 'description');
71
+ if (!description) {
72
+ findings.push({
73
+ status: 'fail',
74
+ message: '<meta name="description"> is missing',
75
+ hint: 'Add <meta name="description" content="..."> in <head> with a 70-160 character summary. Agents use this as the canonical short description.',
76
+ learnMoreUrl: guideUrl(meta.id, 'no-description'),
77
+ });
78
+ score -= 20;
79
+ }
80
+ else if (description.length < DESCRIPTION_MIN) {
81
+ findings.push({
82
+ status: 'warn',
83
+ message: `Meta description is short (${description.length} chars)`,
84
+ hint: `Expand the description to ${DESCRIPTION_MIN}-${DESCRIPTION_MAX} characters with the page's main value proposition.`,
85
+ learnMoreUrl: guideUrl(meta.id, 'short-description'),
86
+ });
87
+ score -= 8;
88
+ }
89
+ else if (description.length > DESCRIPTION_MAX) {
90
+ findings.push({
91
+ status: 'warn',
92
+ message: `Meta description is long (${description.length} chars)`,
93
+ hint: `Trim to ${DESCRIPTION_MIN}-${DESCRIPTION_MAX} characters; longer descriptions get truncated.`,
94
+ learnMoreUrl: guideUrl(meta.id, 'long-description'),
95
+ });
96
+ score -= 5;
97
+ }
98
+ else {
99
+ findings.push({ status: 'pass', message: `Meta description length ${description.length} chars` });
100
+ }
101
+ if (description && title && description.trim().toLowerCase() === title.trim().toLowerCase()) {
102
+ findings.push({
103
+ status: 'warn',
104
+ message: 'Meta description duplicates the <title>',
105
+ hint: 'Write a description that complements the title rather than repeating it. Agents lose context when both fields contain the same text.',
106
+ learnMoreUrl: guideUrl(meta.id, 'duplicate-title-description'),
107
+ });
108
+ score -= 5;
109
+ }
110
+ const canonicalLinks = findLinkTags(html, 'canonical');
111
+ if (canonicalLinks.length === 0) {
112
+ findings.push({
113
+ status: 'warn',
114
+ message: 'No <link rel="canonical"> found',
115
+ hint: 'Add <link rel="canonical" href="https://your-site.com/page"> so agents have an unambiguous URL to cite even when crawled via a redirect or query-string variant.',
116
+ learnMoreUrl: guideUrl(meta.id, 'no-canonical'),
117
+ });
118
+ score -= 10;
119
+ }
120
+ else if (canonicalLinks.length > 1) {
121
+ findings.push({
122
+ status: 'warn',
123
+ message: `${canonicalLinks.length} <link rel="canonical"> tags (must be exactly 1)`,
124
+ hint: 'Keep a single canonical link per page. Multiple canonical hints are ignored by agents and search engines.',
125
+ learnMoreUrl: guideUrl(meta.id, 'multiple-canonical'),
126
+ });
127
+ score -= 5;
128
+ }
129
+ else {
130
+ const href = getAttribute(canonicalLinks[0], 'href');
131
+ if (!href) {
132
+ findings.push({
133
+ status: 'warn',
134
+ message: '<link rel="canonical"> is missing href',
135
+ hint: 'Add an absolute URL to the canonical link tag.',
136
+ learnMoreUrl: guideUrl(meta.id, 'canonical-no-href'),
137
+ });
138
+ score -= 5;
139
+ }
140
+ else if (!/^https?:\/\//i.test(href)) {
141
+ findings.push({
142
+ status: 'warn',
143
+ message: `Canonical href is not absolute: ${href}`,
144
+ hint: 'Use an absolute URL (https://...) for the canonical href. Relative paths are ambiguous when fetched outside the original page context.',
145
+ learnMoreUrl: guideUrl(meta.id, 'canonical-relative'),
146
+ });
147
+ score -= 5;
148
+ }
149
+ else {
150
+ findings.push({ status: 'pass', message: `Canonical URL: ${href}` });
151
+ }
152
+ }
153
+ const lang = getTagAttribute(html, 'html', 'lang');
154
+ if (!lang) {
155
+ findings.push({
156
+ status: 'warn',
157
+ message: '<html lang="..."> is missing',
158
+ hint: 'Set the document language: <html lang="en">. Multilingual agents rely on this to pick the right summarization model and avoid mixed-language ranking.',
159
+ learnMoreUrl: guideUrl(meta.id, 'no-lang'),
160
+ });
161
+ score -= 10;
162
+ }
163
+ else if (!/^[a-z]{2,3}(-[A-Za-z0-9]+)*$/i.test(lang)) {
164
+ findings.push({
165
+ status: 'warn',
166
+ message: `<html lang> looks invalid: "${lang}"`,
167
+ hint: 'Use a valid BCP 47 tag (e.g., en, en-US, es-419, zh-Hant).',
168
+ learnMoreUrl: guideUrl(meta.id, 'invalid-lang'),
169
+ });
170
+ score -= 5;
171
+ }
172
+ else {
173
+ findings.push({ status: 'pass', message: `<html lang="${lang}">` });
174
+ }
175
+ if (/<meta\s+charset\s*=\s*["']?utf-8["']?/i.test(html) ||
176
+ /<meta\s+http-equiv\s*=\s*["']content-type["'][^>]*charset=utf-8/i.test(html)) {
177
+ findings.push({ status: 'pass', message: 'UTF-8 charset declared' });
178
+ }
179
+ else {
180
+ findings.push({
181
+ status: 'warn',
182
+ message: 'No UTF-8 charset declaration in HTML head',
183
+ hint: 'Add <meta charset="utf-8"> as the first child of <head>. Without it, agents can mis-decode non-ASCII content.',
184
+ learnMoreUrl: guideUrl(meta.id, 'no-charset'),
185
+ });
186
+ score -= 5;
187
+ }
188
+ const viewport = getMetaContent(html, 'viewport');
189
+ if (viewport && /width\s*=/.test(viewport)) {
190
+ findings.push({ status: 'pass', message: `Viewport meta present: "${viewport}"` });
191
+ }
192
+ else {
193
+ findings.push({
194
+ status: 'warn',
195
+ message: 'Missing or incomplete viewport meta tag',
196
+ hint: 'Add <meta name="viewport" content="width=device-width, initial-scale=1">. Helps mobile agents render the page correctly.',
197
+ learnMoreUrl: guideUrl(meta.id, 'no-viewport'),
198
+ });
199
+ score -= 5;
200
+ }
201
+ const hreflangs = findLinkTags(html, 'alternate').filter((tag) => /\bhreflang\s*=/.test(tag));
202
+ if (hreflangs.length > 0) {
203
+ const hasXDefault = hreflangs.some((tag) => /hreflang\s*=\s*["']x-default["']/.test(tag));
204
+ if (hasXDefault) {
205
+ findings.push({
206
+ status: 'pass',
207
+ message: `${hreflangs.length} hreflang alternate(s) including x-default`,
208
+ });
209
+ }
210
+ else {
211
+ findings.push({
212
+ status: 'warn',
213
+ message: `${hreflangs.length} hreflang alternate(s) but no x-default`,
214
+ hint: 'Add <link rel="alternate" hreflang="x-default" href="..."> as a fallback for unmatched locales.',
215
+ learnMoreUrl: guideUrl(meta.id, 'no-x-default'),
216
+ });
217
+ score -= 3;
218
+ }
219
+ }
220
+ return buildResult(meta, score, findings, start);
221
+ }
222
+ //# sourceMappingURL=seo-basics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seo-basics.js","sourceRoot":"","sources":["../../src/checks/seo-basics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
+ /**
3
+ * "sitemap" — fetch and validate the XML sitemap so AI agents and search crawlers can discover
4
+ * the full URL surface. Sitemaps may be referenced from `robots.txt` (`Sitemap:` directive) or
5
+ * served at the conventional `/sitemap.xml` path. This check covers both, validates the XML
6
+ * shape, and respects sitemap-index files (which point to multiple child sitemaps).
7
+ *
8
+ * Reference: https://www.sitemaps.org/protocol.html
9
+ */
10
+ export declare const meta: CheckMeta;
11
+ export default function check(ctx: CheckContext): Promise<CheckResult>;
12
+ //# sourceMappingURL=sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/checks/sitemap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAGhG;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAMF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2J3E"}