ax-audit 3.1.0 → 4.0.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 +198 -0
- package/LICENSE +1 -1
- package/README.md +89 -231
- package/dist/baseline.d.ts +2 -0
- package/dist/baseline.d.ts.map +1 -1
- package/dist/baseline.js +42 -4
- package/dist/baseline.js.map +1 -1
- package/dist/check-ids.d.ts +19 -0
- package/dist/check-ids.d.ts.map +1 -0
- package/dist/check-ids.js +53 -0
- package/dist/check-ids.js.map +1 -0
- package/dist/checks/agent-access.d.ts +33 -0
- package/dist/checks/agent-access.d.ts.map +1 -0
- package/dist/checks/agent-access.js +256 -0
- package/dist/checks/agent-access.js.map +1 -0
- package/dist/checks/agent-card.d.ts +37 -0
- package/dist/checks/agent-card.d.ts.map +1 -0
- package/dist/checks/agent-card.js +352 -0
- package/dist/checks/agent-card.js.map +1 -0
- package/dist/checks/agent-operability.d.ts +66 -0
- package/dist/checks/agent-operability.d.ts.map +1 -0
- package/dist/checks/agent-operability.js +383 -0
- package/dist/checks/agent-operability.js.map +1 -0
- package/dist/checks/agent-skills.d.ts +24 -0
- package/dist/checks/agent-skills.d.ts.map +1 -0
- package/dist/checks/agent-skills.js +316 -0
- package/dist/checks/agent-skills.js.map +1 -0
- package/dist/checks/ai-catalog.d.ts +28 -0
- package/dist/checks/ai-catalog.d.ts.map +1 -0
- package/dist/checks/ai-catalog.js +254 -0
- package/dist/checks/ai-catalog.js.map +1 -0
- package/dist/checks/ai-directives.d.ts +57 -0
- package/dist/checks/ai-directives.d.ts.map +1 -0
- package/dist/checks/ai-directives.js +263 -0
- package/dist/checks/ai-directives.js.map +1 -0
- package/dist/checks/api-discovery.d.ts +26 -0
- package/dist/checks/api-discovery.d.ts.map +1 -0
- package/dist/checks/api-discovery.js +432 -0
- package/dist/checks/api-discovery.js.map +1 -0
- package/dist/checks/auth-discovery.d.ts +28 -0
- package/dist/checks/auth-discovery.d.ts.map +1 -0
- package/dist/checks/auth-discovery.js +213 -0
- package/dist/checks/auth-discovery.js.map +1 -0
- package/dist/checks/commerce-discovery.d.ts +40 -0
- package/dist/checks/commerce-discovery.d.ts.map +1 -0
- package/dist/checks/commerce-discovery.js +295 -0
- package/dist/checks/commerce-discovery.js.map +1 -0
- package/dist/checks/content-negotiation.d.ts.map +1 -1
- package/dist/checks/content-negotiation.js +135 -20
- package/dist/checks/content-negotiation.js.map +1 -1
- package/dist/checks/crawl-efficiency.d.ts +16 -0
- package/dist/checks/crawl-efficiency.d.ts.map +1 -0
- package/dist/checks/crawl-efficiency.js +186 -0
- package/dist/checks/crawl-efficiency.js.map +1 -0
- package/dist/checks/frontmatter.d.ts +34 -0
- package/dist/checks/frontmatter.d.ts.map +1 -0
- package/dist/checks/frontmatter.js +100 -0
- package/dist/checks/frontmatter.js.map +1 -0
- package/dist/checks/html-rendering.d.ts.map +1 -1
- package/dist/checks/html-rendering.js +0 -1
- package/dist/checks/html-rendering.js.map +1 -1
- package/dist/checks/html-utils.d.ts +10 -0
- package/dist/checks/html-utils.d.ts.map +1 -1
- package/dist/checks/html-utils.js +19 -0
- package/dist/checks/html-utils.js.map +1 -1
- package/dist/checks/http-headers.d.ts.map +1 -1
- package/dist/checks/http-headers.js +82 -10
- package/dist/checks/http-headers.js.map +1 -1
- package/dist/checks/http-hygiene.d.ts +26 -0
- package/dist/checks/http-hygiene.d.ts.map +1 -0
- package/dist/checks/http-hygiene.js +257 -0
- package/dist/checks/http-hygiene.js.map +1 -0
- package/dist/checks/index.d.ts.map +1 -1
- package/dist/checks/index.js +30 -8
- package/dist/checks/index.js.map +1 -1
- package/dist/checks/llms-txt.d.ts +15 -0
- package/dist/checks/llms-txt.d.ts.map +1 -1
- package/dist/checks/llms-txt.js +162 -2
- package/dist/checks/llms-txt.js.map +1 -1
- package/dist/checks/mcp-discovery.d.ts +30 -0
- package/dist/checks/mcp-discovery.d.ts.map +1 -0
- package/dist/checks/mcp-discovery.js +523 -0
- package/dist/checks/mcp-discovery.js.map +1 -0
- package/dist/checks/meta-tags.d.ts.map +1 -1
- package/dist/checks/meta-tags.js +6 -5
- package/dist/checks/meta-tags.js.map +1 -1
- package/dist/checks/robots-parser.d.ts +110 -0
- package/dist/checks/robots-parser.d.ts.map +1 -0
- package/dist/checks/robots-parser.js +277 -0
- package/dist/checks/robots-parser.js.map +1 -0
- package/dist/checks/robots-txt.d.ts +2 -0
- package/dist/checks/robots-txt.d.ts.map +1 -1
- package/dist/checks/robots-txt.js +252 -45
- package/dist/checks/robots-txt.js.map +1 -1
- package/dist/checks/{mcp.d.ts → rsl.d.ts} +1 -1
- package/dist/checks/rsl.d.ts.map +1 -0
- package/dist/checks/rsl.js +242 -0
- package/dist/checks/rsl.js.map +1 -0
- package/dist/checks/security-txt.d.ts.map +1 -1
- package/dist/checks/security-txt.js +0 -1
- package/dist/checks/security-txt.js.map +1 -1
- package/dist/checks/seo-basics.d.ts.map +1 -1
- package/dist/checks/seo-basics.js +0 -1
- package/dist/checks/seo-basics.js.map +1 -1
- package/dist/checks/sitemap.d.ts.map +1 -1
- package/dist/checks/sitemap.js +0 -1
- package/dist/checks/sitemap.js.map +1 -1
- package/dist/checks/structured-data.d.ts.map +1 -1
- package/dist/checks/structured-data.js +215 -4
- package/dist/checks/structured-data.js.map +1 -1
- package/dist/checks/structured-fields.d.ts +46 -0
- package/dist/checks/structured-fields.d.ts.map +1 -0
- package/dist/checks/structured-fields.js +112 -0
- package/dist/checks/structured-fields.js.map +1 -0
- package/dist/checks/surface.d.ts +59 -0
- package/dist/checks/surface.d.ts.map +1 -0
- package/dist/checks/surface.js +106 -0
- package/dist/checks/surface.js.map +1 -0
- package/dist/checks/tls-https.d.ts.map +1 -1
- package/dist/checks/tls-https.js +0 -1
- package/dist/checks/tls-https.js.map +1 -1
- package/dist/checks/usage-policy.d.ts +53 -0
- package/dist/checks/usage-policy.d.ts.map +1 -0
- package/dist/checks/usage-policy.js +339 -0
- package/dist/checks/usage-policy.js.map +1 -0
- package/dist/checks/utils.d.ts +25 -1
- package/dist/checks/utils.d.ts.map +1 -1
- package/dist/checks/utils.js +33 -1
- package/dist/checks/utils.js.map +1 -1
- package/dist/checks/waf.d.ts +75 -0
- package/dist/checks/waf.d.ts.map +1 -0
- package/dist/checks/waf.js +203 -0
- package/dist/checks/waf.js.map +1 -0
- package/dist/checks/webmcp.d.ts +55 -0
- package/dist/checks/webmcp.d.ts.map +1 -0
- package/dist/checks/webmcp.js +209 -0
- package/dist/checks/webmcp.js.map +1 -0
- package/dist/checks/well-known.d.ts +38 -0
- package/dist/checks/well-known.d.ts.map +1 -0
- package/dist/checks/well-known.js +202 -0
- package/dist/checks/well-known.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +144 -6
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +212 -14
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +625 -59
- package/dist/constants.js.map +1 -1
- package/dist/fetcher.d.ts +5 -1
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/fetcher.js +62 -27
- package/dist/fetcher.js.map +1 -1
- package/dist/guide-urls.js +1 -1
- package/dist/guide-urls.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestrator.d.ts +2 -2
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +18 -7
- package/dist/orchestrator.js.map +1 -1
- package/dist/reporter/html.d.ts +9 -0
- package/dist/reporter/html.d.ts.map +1 -1
- package/dist/reporter/html.js +49 -11
- package/dist/reporter/html.js.map +1 -1
- package/dist/reporter/index.d.ts.map +1 -1
- package/dist/reporter/index.js +7 -0
- package/dist/reporter/index.js.map +1 -1
- package/dist/reporter/markdown.d.ts +8 -0
- package/dist/reporter/markdown.d.ts.map +1 -0
- package/dist/reporter/markdown.js +106 -0
- package/dist/reporter/markdown.js.map +1 -0
- package/dist/reporter/terminal.d.ts.map +1 -1
- package/dist/reporter/terminal.js +36 -1
- package/dist/reporter/terminal.js.map +1 -1
- package/dist/scorer.d.ts +10 -0
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +22 -5
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +96 -3
- package/dist/types.d.ts.map +1 -1
- package/docs/api.md +200 -0
- package/docs/architecture.md +104 -0
- package/docs/checks.md +555 -0
- package/docs/ci.md +89 -0
- package/docs/cli.md +103 -0
- package/docs/concepts.md +101 -0
- package/docs/faq.md +89 -0
- package/docs/getting-started.md +108 -0
- package/docs/roadmap.md +367 -0
- package/package.json +14 -5
- package/dist/checks/agent-json.d.ts +0 -14
- package/dist/checks/agent-json.d.ts.map +0 -1
- package/dist/checks/agent-json.js +0 -167
- package/dist/checks/agent-json.js.map +0 -1
- package/dist/checks/mcp.d.ts.map +0 -1
- package/dist/checks/mcp.js +0 -162
- package/dist/checks/mcp.js.map +0 -1
- package/dist/checks/openapi.d.ts +0 -4
- package/dist/checks/openapi.d.ts.map +0 -1
- package/dist/checks/openapi.js +0 -121
- package/dist/checks/openapi.js.map +0 -1
- package/dist/checks/well-known-ai.d.ts +0 -17
- package/dist/checks/well-known-ai.d.ts.map +0 -1
- package/dist/checks/well-known-ai.js +0 -123
- package/dist/checks/well-known-ai.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { guideUrl } from '../guide-urls.js';
|
|
2
|
+
import { extractVisibleText, findJsonLdBlocks } from './html-utils.js';
|
|
2
3
|
import { buildResult } from './utils.js';
|
|
3
4
|
export const meta = {
|
|
4
5
|
id: 'structured-data',
|
|
5
6
|
name: 'Structured Data',
|
|
6
7
|
description: 'Checks JSON-LD structured data on homepage',
|
|
7
|
-
weight: 9,
|
|
8
8
|
};
|
|
9
9
|
export default async function check(ctx) {
|
|
10
10
|
const start = performance.now();
|
|
@@ -15,8 +15,7 @@ export default async function check(ctx) {
|
|
|
15
15
|
findings.push({ status: 'fail', message: 'Could not fetch homepage HTML' });
|
|
16
16
|
return buildResult(meta, 0, findings, start);
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
const blocks = [...html.matchAll(jsonLdPattern)];
|
|
18
|
+
const blocks = findJsonLdBlocks(html);
|
|
20
19
|
if (blocks.length === 0) {
|
|
21
20
|
findings.push({
|
|
22
21
|
status: 'fail',
|
|
@@ -29,7 +28,7 @@ export default async function check(ctx) {
|
|
|
29
28
|
findings.push({ status: 'pass', message: `${blocks.length} JSON-LD block(s) found` });
|
|
30
29
|
const parsed = [];
|
|
31
30
|
for (const block of blocks) {
|
|
32
|
-
const raw = unescapeHtml(block
|
|
31
|
+
const raw = unescapeHtml(block);
|
|
33
32
|
try {
|
|
34
33
|
parsed.push(JSON.parse(raw));
|
|
35
34
|
}
|
|
@@ -118,8 +117,220 @@ export default async function check(ctx) {
|
|
|
118
117
|
});
|
|
119
118
|
score -= 5;
|
|
120
119
|
}
|
|
120
|
+
// Informational in 3.x: new findings inside a weighted check must not deduct.
|
|
121
|
+
reportProvenance(parsed, findings);
|
|
122
|
+
reportFreshness(parsed, findings);
|
|
123
|
+
reportVisibleTextAgreement(parsed, html, findings);
|
|
121
124
|
return buildResult(meta, score, findings, start);
|
|
122
125
|
}
|
|
126
|
+
/* ── Provenance and freshness (informational in 3.x) ────────────────────── */
|
|
127
|
+
/** Walk a JSON-LD tree, yielding every object node. */
|
|
128
|
+
function* nodes(value, depth = 0) {
|
|
129
|
+
if (depth > 8 || value === null || typeof value !== 'object')
|
|
130
|
+
return;
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
for (const item of value)
|
|
133
|
+
yield* nodes(item, depth + 1);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const obj = value;
|
|
137
|
+
yield obj;
|
|
138
|
+
for (const child of Object.values(obj))
|
|
139
|
+
yield* nodes(child, depth + 1);
|
|
140
|
+
}
|
|
141
|
+
/** Read a property that may be a string, an object with a name, or a list of either. */
|
|
142
|
+
function readNames(value) {
|
|
143
|
+
if (typeof value === 'string')
|
|
144
|
+
return [value];
|
|
145
|
+
if (Array.isArray(value))
|
|
146
|
+
return value.flatMap(readNames);
|
|
147
|
+
if (value !== null && typeof value === 'object') {
|
|
148
|
+
const name = value.name;
|
|
149
|
+
return typeof name === 'string' ? [name] : [];
|
|
150
|
+
}
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Who wrote this, and can it be tied to an entity that exists elsewhere?
|
|
155
|
+
*
|
|
156
|
+
* An assistant deciding whether to cite a page weighs where it came from. A
|
|
157
|
+
* byline with no `sameAs` is a string; a byline linked to Wikidata, an ORCID or
|
|
158
|
+
* a company page is an entity a model can already have an opinion about.
|
|
159
|
+
*/
|
|
160
|
+
function reportProvenance(parsed, findings) {
|
|
161
|
+
const authors = new Set();
|
|
162
|
+
const sameAs = new Set();
|
|
163
|
+
let publisher = false;
|
|
164
|
+
let organizationDetail = false;
|
|
165
|
+
for (const root of parsed) {
|
|
166
|
+
for (const node of nodes(root)) {
|
|
167
|
+
for (const name of readNames(node.author))
|
|
168
|
+
authors.add(name);
|
|
169
|
+
if (node.publisher !== undefined)
|
|
170
|
+
publisher = true;
|
|
171
|
+
for (const url of readNames(node.sameAs))
|
|
172
|
+
sameAs.add(url);
|
|
173
|
+
if (Array.isArray(node.sameAs)) {
|
|
174
|
+
for (const url of node.sameAs)
|
|
175
|
+
if (typeof url === 'string')
|
|
176
|
+
sameAs.add(url);
|
|
177
|
+
}
|
|
178
|
+
else if (typeof node.sameAs === 'string') {
|
|
179
|
+
sameAs.add(node.sameAs);
|
|
180
|
+
}
|
|
181
|
+
if (node.companyRegistration !== undefined ||
|
|
182
|
+
node.legalAddress !== undefined ||
|
|
183
|
+
node.contactPoint !== undefined) {
|
|
184
|
+
organizationDetail = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (authors.size > 0) {
|
|
189
|
+
findings.push({ status: 'pass', message: `Authorship declared: ${[...authors].slice(0, 3).join(', ')}` });
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
findings.push({
|
|
193
|
+
status: 'warn',
|
|
194
|
+
message: 'No author declared in structured data',
|
|
195
|
+
hint: 'An assistant deciding whether to cite a page weighs where it came from. Add author as a Person or ' +
|
|
196
|
+
'Organization, not a bare string.',
|
|
197
|
+
learnMoreUrl: guideUrl(meta.id, 'no-author'),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (sameAs.size > 0) {
|
|
201
|
+
findings.push({
|
|
202
|
+
status: 'pass',
|
|
203
|
+
message: `${sameAs.size} sameAs link(s) tie your entity to external identifiers`,
|
|
204
|
+
detail: [...sameAs].slice(0, 4).join(', '),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
findings.push({
|
|
209
|
+
status: 'warn',
|
|
210
|
+
message: 'No sameAs links',
|
|
211
|
+
hint: 'sameAs is what turns a name into an entity. Link your Organization or Person to Wikidata, LinkedIn, GitHub ' +
|
|
212
|
+
'or Crunchbase so a model can connect this page to what it already knows.',
|
|
213
|
+
learnMoreUrl: guideUrl(meta.id, 'no-same-as'),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if (!publisher && authors.size > 0) {
|
|
217
|
+
findings.push({
|
|
218
|
+
status: 'warn',
|
|
219
|
+
message: 'Author declared but no publisher',
|
|
220
|
+
hint: 'Declare publisher as well, so a citation can name the outlet as well as the writer.',
|
|
221
|
+
learnMoreUrl: guideUrl(meta.id, 'no-publisher'),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (organizationDetail) {
|
|
225
|
+
findings.push({
|
|
226
|
+
status: 'pass',
|
|
227
|
+
message: 'Organization carries disambiguating detail (registration, legal address or contact point)',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Freshness buckets, in days. */
|
|
232
|
+
const FRESH_DAYS = 90;
|
|
233
|
+
const STALE_DAYS = 730;
|
|
234
|
+
/**
|
|
235
|
+
* When did this page last change?
|
|
236
|
+
*
|
|
237
|
+
* Assistants answering time-sensitive questions weigh recency, and a page with
|
|
238
|
+
* no date at all cannot be weighed. The check reports rather than penalises:
|
|
239
|
+
* an evergreen reference page is legitimately old.
|
|
240
|
+
*/
|
|
241
|
+
function reportFreshness(parsed, findings) {
|
|
242
|
+
const dates = [];
|
|
243
|
+
for (const root of parsed) {
|
|
244
|
+
for (const node of nodes(root)) {
|
|
245
|
+
for (const field of ['dateModified', 'datePublished', 'uploadDate']) {
|
|
246
|
+
const raw = node[field];
|
|
247
|
+
if (typeof raw !== 'string')
|
|
248
|
+
continue;
|
|
249
|
+
const parsedDate = new Date(raw);
|
|
250
|
+
if (Number.isNaN(parsedDate.getTime())) {
|
|
251
|
+
findings.push({
|
|
252
|
+
status: 'warn',
|
|
253
|
+
message: `${field} is not a parseable date: "${raw}"`,
|
|
254
|
+
hint: 'Use ISO 8601, for example 2026-09-04 or 2026-09-04T12:00:00Z.',
|
|
255
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-date'),
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
dates.push({ field, value: parsedDate });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (dates.length === 0) {
|
|
264
|
+
findings.push({
|
|
265
|
+
status: 'warn',
|
|
266
|
+
message: 'No dateModified or datePublished in structured data',
|
|
267
|
+
hint: 'Assistants weigh recency when they answer time-sensitive questions, and a page with no date cannot be ' +
|
|
268
|
+
'weighed at all. Add dateModified to anything that changes.',
|
|
269
|
+
learnMoreUrl: guideUrl(meta.id, 'no-dates'),
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const newest = dates.reduce((a, b) => (a.value > b.value ? a : b));
|
|
274
|
+
const days = Math.round((Date.now() - newest.value.getTime()) / 86_400_000);
|
|
275
|
+
if (days < 0) {
|
|
276
|
+
findings.push({
|
|
277
|
+
status: 'warn',
|
|
278
|
+
message: `${newest.field} is in the future (${newest.value.toISOString().slice(0, 10)})`,
|
|
279
|
+
hint: 'A future date reads as a mistake or as manipulation. Use the real modification time.',
|
|
280
|
+
learnMoreUrl: guideUrl(meta.id, 'future-date'),
|
|
281
|
+
});
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
findings.push({
|
|
285
|
+
status: days > STALE_DAYS ? 'warn' : 'pass',
|
|
286
|
+
message: `Content last dated ${newest.value.toISOString().slice(0, 10)} (${days} days ago)`,
|
|
287
|
+
...(days > STALE_DAYS
|
|
288
|
+
? {
|
|
289
|
+
hint: 'Over two years without a recorded update. If the page is still accurate, refresh dateModified so an assistant knows that; if it is not, it is answering with stale facts.',
|
|
290
|
+
learnMoreUrl: guideUrl(meta.id, 'stale-content'),
|
|
291
|
+
}
|
|
292
|
+
: days < FRESH_DAYS
|
|
293
|
+
? {}
|
|
294
|
+
: { detail: 'Fine for reference material; worth refreshing on anything time-sensitive.' }),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Google's one explicit ask about structured data and AI features is that it
|
|
299
|
+
* match the visible text. Markup describing a page that is not there is the
|
|
300
|
+
* oldest form of spam, and it is now graded by systems that quote it.
|
|
301
|
+
*/
|
|
302
|
+
function reportVisibleTextAgreement(parsed, html, findings) {
|
|
303
|
+
const visible = extractVisibleText(html).toLowerCase();
|
|
304
|
+
if (visible.length < 200)
|
|
305
|
+
return;
|
|
306
|
+
const claims = [];
|
|
307
|
+
for (const root of parsed) {
|
|
308
|
+
for (const node of nodes(root)) {
|
|
309
|
+
for (const field of ['headline', 'name']) {
|
|
310
|
+
const value = node[field];
|
|
311
|
+
if (typeof value === 'string' && value.length >= 12 && value.length <= 110) {
|
|
312
|
+
claims.push({ field, value });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (claims.length === 0)
|
|
318
|
+
return;
|
|
319
|
+
const missing = claims.filter((c) => !visible.includes(c.value.toLowerCase())).slice(0, 3);
|
|
320
|
+
if (missing.length === 0) {
|
|
321
|
+
findings.push({ status: 'pass', message: 'Structured-data headings appear in the visible text' });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
findings.push({
|
|
325
|
+
status: 'warn',
|
|
326
|
+
message: `${missing.length} structured-data value(s) do not appear in the visible text`,
|
|
327
|
+
detail: missing.map((c) => `${c.field}: "${c.value}"`).join('\n'),
|
|
328
|
+
hint: 'Google\u2019s one explicit requirement for structured data and AI features is that it match what a reader sees. ' +
|
|
329
|
+
'Markup describing a page that is not there is the oldest form of spam, and it is now graded by systems that ' +
|
|
330
|
+
'quote it. Note this compares the static HTML, so text rendered by script will read as missing here too.',
|
|
331
|
+
learnMoreUrl: guideUrl(meta.id, 'markup-mismatch'),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
123
334
|
function unescapeHtml(str) {
|
|
124
335
|
return str
|
|
125
336
|
.replace(/&/g, '&')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/checks/structured-data.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/checks/structured-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal RFC 9651 (Structured Field Values) Dictionary parser.
|
|
3
|
+
*
|
|
4
|
+
* Scope is deliberately narrow: the fields ax-audit reads that are defined as
|
|
5
|
+
* Dictionaries carry token or boolean members with optional parameters —
|
|
6
|
+
* IETF AIPREF `Content-Usage: train-ai=n, search=y`
|
|
7
|
+
* (draft-ietf-aipref-attach-05 §2) and, on the request side, Web Bot Auth's
|
|
8
|
+
* `Signature-Input`. A full Structured Fields implementation (inner lists,
|
|
9
|
+
* byte sequences, dates, display strings) would be dead weight, so this parser
|
|
10
|
+
* covers dictionaries of bare items and reports anything else as malformed
|
|
11
|
+
* rather than guessing.
|
|
12
|
+
*
|
|
13
|
+
* The parser never throws. Malformed members are collected so callers can
|
|
14
|
+
* report *which* segment was wrong instead of discarding the whole header.
|
|
15
|
+
*/
|
|
16
|
+
export interface DictMember {
|
|
17
|
+
/** Member key, lowercased (RFC 9651 keys are case-sensitive but every field we read is lowercase). */
|
|
18
|
+
key: string;
|
|
19
|
+
/**
|
|
20
|
+
* Bare item value as written. A key with no `=` is a boolean true and
|
|
21
|
+
* yields `'?1'`, matching the RFC's serialization of a true Boolean.
|
|
22
|
+
*/
|
|
23
|
+
value: string;
|
|
24
|
+
/** Parameters attached to the member (`;key=value`), values as written. */
|
|
25
|
+
params: Record<string, string>;
|
|
26
|
+
/** The member as it appeared in the input, trimmed. */
|
|
27
|
+
raw: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ParsedDictionary {
|
|
30
|
+
members: DictMember[];
|
|
31
|
+
/** Segments that could not be parsed as `key[=value][;param...]`. */
|
|
32
|
+
malformed: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse a Structured Field Dictionary. Returns members in source order plus the
|
|
36
|
+
* segments that failed to parse.
|
|
37
|
+
*
|
|
38
|
+
* ```
|
|
39
|
+
* parseDictionary('train-ai=n, search=y')
|
|
40
|
+
* // members: [{key:'train-ai', value:'n'}, {key:'search', value:'y'}]
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseDictionary(input: string): ParsedDictionary;
|
|
44
|
+
/** Convenience: look up one member's value, or `null` when absent. */
|
|
45
|
+
export declare function dictValue(parsed: ParsedDictionary, key: string): string | null;
|
|
46
|
+
//# sourceMappingURL=structured-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-fields.d.ts","sourceRoot":"","sources":["../../src/checks/structured-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,UAAU;IACzB,sGAAsG;IACtG,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,qEAAqE;IACrE,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAkDD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CA0C/D;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal RFC 9651 (Structured Field Values) Dictionary parser.
|
|
3
|
+
*
|
|
4
|
+
* Scope is deliberately narrow: the fields ax-audit reads that are defined as
|
|
5
|
+
* Dictionaries carry token or boolean members with optional parameters —
|
|
6
|
+
* IETF AIPREF `Content-Usage: train-ai=n, search=y`
|
|
7
|
+
* (draft-ietf-aipref-attach-05 §2) and, on the request side, Web Bot Auth's
|
|
8
|
+
* `Signature-Input`. A full Structured Fields implementation (inner lists,
|
|
9
|
+
* byte sequences, dates, display strings) would be dead weight, so this parser
|
|
10
|
+
* covers dictionaries of bare items and reports anything else as malformed
|
|
11
|
+
* rather than guessing.
|
|
12
|
+
*
|
|
13
|
+
* The parser never throws. Malformed members are collected so callers can
|
|
14
|
+
* report *which* segment was wrong instead of discarding the whole header.
|
|
15
|
+
*/
|
|
16
|
+
/** RFC 9651 keys: lowercase alpha / `*` start, then alphanumerics and `_-.*`. */
|
|
17
|
+
const KEY_RE = /^[a-z*][a-z0-9_\-.*]*$/;
|
|
18
|
+
/**
|
|
19
|
+
* Split on top-level commas, keeping quoted strings intact so a value like
|
|
20
|
+
* `note="a, b"` stays one member.
|
|
21
|
+
*/
|
|
22
|
+
function splitTopLevel(input, separator) {
|
|
23
|
+
const parts = [];
|
|
24
|
+
let current = '';
|
|
25
|
+
let inQuote = false;
|
|
26
|
+
let escaped = false;
|
|
27
|
+
for (const ch of input) {
|
|
28
|
+
if (escaped) {
|
|
29
|
+
current += ch;
|
|
30
|
+
escaped = false;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (ch === '\\' && inQuote) {
|
|
34
|
+
current += ch;
|
|
35
|
+
escaped = true;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (ch === '"') {
|
|
39
|
+
inQuote = !inQuote;
|
|
40
|
+
current += ch;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (ch === separator && !inQuote) {
|
|
44
|
+
parts.push(current);
|
|
45
|
+
current = '';
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
current += ch;
|
|
49
|
+
}
|
|
50
|
+
parts.push(current);
|
|
51
|
+
return parts;
|
|
52
|
+
}
|
|
53
|
+
/** Strip surrounding double quotes from a string item, unescaping `\"` and `\\`. */
|
|
54
|
+
function unquote(value) {
|
|
55
|
+
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
|
56
|
+
return value.slice(1, -1).replace(/\\(["\\])/g, '$1');
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse a Structured Field Dictionary. Returns members in source order plus the
|
|
62
|
+
* segments that failed to parse.
|
|
63
|
+
*
|
|
64
|
+
* ```
|
|
65
|
+
* parseDictionary('train-ai=n, search=y')
|
|
66
|
+
* // members: [{key:'train-ai', value:'n'}, {key:'search', value:'y'}]
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function parseDictionary(input) {
|
|
70
|
+
const members = [];
|
|
71
|
+
const malformed = [];
|
|
72
|
+
if (!input || !input.trim())
|
|
73
|
+
return { members, malformed };
|
|
74
|
+
for (const segment of splitTopLevel(input, ',')) {
|
|
75
|
+
const raw = segment.trim();
|
|
76
|
+
if (!raw)
|
|
77
|
+
continue;
|
|
78
|
+
const [head, ...paramParts] = splitTopLevel(raw, ';');
|
|
79
|
+
const eq = head.indexOf('=');
|
|
80
|
+
const key = (eq === -1 ? head : head.slice(0, eq)).trim().toLowerCase();
|
|
81
|
+
const rawValue = eq === -1 ? '?1' : head.slice(eq + 1).trim();
|
|
82
|
+
if (!KEY_RE.test(key) || (eq !== -1 && rawValue === '')) {
|
|
83
|
+
malformed.push(raw);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const params = {};
|
|
87
|
+
let paramsOk = true;
|
|
88
|
+
for (const part of paramParts) {
|
|
89
|
+
const p = part.trim();
|
|
90
|
+
if (!p)
|
|
91
|
+
continue;
|
|
92
|
+
const pEq = p.indexOf('=');
|
|
93
|
+
const pKey = (pEq === -1 ? p : p.slice(0, pEq)).trim().toLowerCase();
|
|
94
|
+
if (!KEY_RE.test(pKey)) {
|
|
95
|
+
paramsOk = false;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
params[pKey] = pEq === -1 ? '?1' : unquote(p.slice(pEq + 1).trim());
|
|
99
|
+
}
|
|
100
|
+
if (!paramsOk) {
|
|
101
|
+
malformed.push(raw);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
members.push({ key, value: unquote(rawValue), params, raw });
|
|
105
|
+
}
|
|
106
|
+
return { members, malformed };
|
|
107
|
+
}
|
|
108
|
+
/** Convenience: look up one member's value, or `null` when absent. */
|
|
109
|
+
export function dictValue(parsed, key) {
|
|
110
|
+
return parsed.members.find((m) => m.key === key.toLowerCase())?.value ?? null;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=structured-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-fields.js","sourceRoot":"","sources":["../../src/checks/structured-fields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does this site have the surface a protocol check is about?
|
|
3
|
+
*
|
|
4
|
+
* From 4.0, protocol checks carry weight. That is only defensible if they apply
|
|
5
|
+
* to the site being audited. A blog has no API to describe and is not an agent;
|
|
6
|
+
* scoring it zero for publishing no OpenAPI document or Agent Card would say
|
|
7
|
+
* something false about the blog and make the overall number useless as a
|
|
8
|
+
* signal.
|
|
9
|
+
*
|
|
10
|
+
* So each protocol check asks first whether the site has the corresponding
|
|
11
|
+
* surface. When it does not, the check reports N/A — visible in the report,
|
|
12
|
+
* excluded from the score — and says what publishing one would enable. When it
|
|
13
|
+
* does, a missing description is a real finding, because the capability exists
|
|
14
|
+
* and agents cannot find it.
|
|
15
|
+
*
|
|
16
|
+
* A `--profile` flag overrides the detection, so a site can be audited against
|
|
17
|
+
* what it intends to become rather than only what it already is.
|
|
18
|
+
*/
|
|
19
|
+
import type { CheckContext } from '../types.js';
|
|
20
|
+
/** Surfaces a site can have, each gating one or more protocol checks. */
|
|
21
|
+
export type Surface = 'api' | 'mcp' | 'agent' | 'docs' | 'commerce';
|
|
22
|
+
/**
|
|
23
|
+
* Profiles a user can force with `--profile`. `all` makes every protocol check
|
|
24
|
+
* applicable, which is what a site planning its agent integration wants.
|
|
25
|
+
*/
|
|
26
|
+
export type Profile = 'auto' | 'api' | 'mcp' | 'agent' | 'docs' | 'commerce' | 'all';
|
|
27
|
+
export interface SurfaceEvidence {
|
|
28
|
+
found: boolean;
|
|
29
|
+
/** What made the check applicable, for the report. */
|
|
30
|
+
reason: string;
|
|
31
|
+
}
|
|
32
|
+
/** Read the profile a run was invoked with, defaulting to automatic detection. */
|
|
33
|
+
export declare function profileFrom(ctx: CheckContext): Profile;
|
|
34
|
+
/** Whether the active profile forces this surface applicable. */
|
|
35
|
+
export declare function forcedBy(profile: Profile, surface: Surface): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Does this site offer an HTTP API?
|
|
38
|
+
*
|
|
39
|
+
* Evidence: a description at a conventional location, an RFC 9727 catalog, a
|
|
40
|
+
* `service-desc` relation, or navigation into an API or developer area. The
|
|
41
|
+
* last is the loosest and the most common: a site with a "Developers" link
|
|
42
|
+
* almost certainly has an API worth describing.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hasApiSurface(ctx: CheckContext): Promise<SurfaceEvidence>;
|
|
45
|
+
/** Does this site run an MCP server? */
|
|
46
|
+
export declare function hasMcpSurface(ctx: CheckContext): Promise<SurfaceEvidence>;
|
|
47
|
+
/**
|
|
48
|
+
* Is this site agent-facing — something an agent would call rather than only
|
|
49
|
+
* read?
|
|
50
|
+
*
|
|
51
|
+
* An Agent Card describes capabilities another agent can invoke. Most sites do
|
|
52
|
+
* not have any, and asking a restaurant to publish one is noise. A site that
|
|
53
|
+
* runs an MCP server, offers an API, or already publishes a card is a different
|
|
54
|
+
* matter.
|
|
55
|
+
*/
|
|
56
|
+
export declare function hasAgentSurface(ctx: CheckContext): Promise<SurfaceEvidence>;
|
|
57
|
+
/** Does this site have documentation an agent could be taught to follow? */
|
|
58
|
+
export declare function hasDocsSurface(ctx: CheckContext): Promise<SurfaceEvidence>;
|
|
59
|
+
//# sourceMappingURL=surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/checks/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,yEAAyE;AACzE,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAErF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAEtD;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAEpE;AAaD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAkB/E;AAED,wCAAwC;AACxC,wBAAsB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAiB/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAmBjF;AAED,4EAA4E;AAC5E,wBAAsB,cAAc,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAWhF"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isHtmlDocument } from './utils.js';
|
|
2
|
+
import { parseLinkHeader } from './http-headers.js';
|
|
3
|
+
const NOT_FOUND = { found: false, reason: '' };
|
|
4
|
+
/** Read the profile a run was invoked with, defaulting to automatic detection. */
|
|
5
|
+
export function profileFrom(ctx) {
|
|
6
|
+
return ctx.profile ?? 'auto';
|
|
7
|
+
}
|
|
8
|
+
/** Whether the active profile forces this surface applicable. */
|
|
9
|
+
export function forcedBy(profile, surface) {
|
|
10
|
+
return profile === 'all' || profile === surface;
|
|
11
|
+
}
|
|
12
|
+
async function exists(ctx, path) {
|
|
13
|
+
const res = await ctx.fetch(`${ctx.url}${path}`);
|
|
14
|
+
return res.ok && res.body.trim().length > 0 && !isHtmlDocument(res.body);
|
|
15
|
+
}
|
|
16
|
+
/** Links and headers pointing at a named area of the site. */
|
|
17
|
+
function linksTo(ctx, pattern) {
|
|
18
|
+
if (pattern.test(ctx.html ?? ''))
|
|
19
|
+
return true;
|
|
20
|
+
return parseLinkHeader(ctx.headers?.['link'] ?? '').some((entry) => pattern.test(entry.url));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Does this site offer an HTTP API?
|
|
24
|
+
*
|
|
25
|
+
* Evidence: a description at a conventional location, an RFC 9727 catalog, a
|
|
26
|
+
* `service-desc` relation, or navigation into an API or developer area. The
|
|
27
|
+
* last is the loosest and the most common: a site with a "Developers" link
|
|
28
|
+
* almost certainly has an API worth describing.
|
|
29
|
+
*/
|
|
30
|
+
export async function hasApiSurface(ctx) {
|
|
31
|
+
if (forcedBy(profileFrom(ctx), 'api'))
|
|
32
|
+
return { found: true, reason: '--profile api' };
|
|
33
|
+
for (const path of ['/openapi.json', '/.well-known/openapi.json', '/.well-known/api-catalog', '/swagger.json']) {
|
|
34
|
+
if (await exists(ctx, path))
|
|
35
|
+
return { found: true, reason: `a document at ${path}` };
|
|
36
|
+
}
|
|
37
|
+
if (linksTo(ctx, /rel\s*=\s*["'][^"']*service-desc/i)) {
|
|
38
|
+
return { found: true, reason: 'a service-desc link relation' };
|
|
39
|
+
}
|
|
40
|
+
if (linksTo(ctx, /href\s*=\s*["'][^"']*\/(api|developers?|api-docs|reference)\b/i)) {
|
|
41
|
+
return { found: true, reason: 'navigation into an API or developer area' };
|
|
42
|
+
}
|
|
43
|
+
if (/\bapi\.[a-z0-9-]+\.[a-z]{2,}/i.test(ctx.html ?? '')) {
|
|
44
|
+
return { found: true, reason: 'references to an API subdomain' };
|
|
45
|
+
}
|
|
46
|
+
return NOT_FOUND;
|
|
47
|
+
}
|
|
48
|
+
/** Does this site run an MCP server? */
|
|
49
|
+
export async function hasMcpSurface(ctx) {
|
|
50
|
+
if (forcedBy(profileFrom(ctx), 'mcp'))
|
|
51
|
+
return { found: true, reason: '--profile mcp' };
|
|
52
|
+
for (const path of ['/.well-known/mcp/server-card.json', '/mcp/server-card', '/.well-known/mcp.json']) {
|
|
53
|
+
if (await exists(ctx, path))
|
|
54
|
+
return { found: true, reason: `a document at ${path}` };
|
|
55
|
+
}
|
|
56
|
+
const catalog = await ctx.fetch(`${ctx.url}/.well-known/ai-catalog.json`);
|
|
57
|
+
if (catalog.ok && /application\/mcp-server-card\+json/.test(catalog.body)) {
|
|
58
|
+
return { found: true, reason: 'an MCP entry in the AI catalog' };
|
|
59
|
+
}
|
|
60
|
+
if (linksTo(ctx, /href\s*=\s*["'][^"']*\/mcp\b/i)) {
|
|
61
|
+
return { found: true, reason: 'navigation referencing an MCP endpoint' };
|
|
62
|
+
}
|
|
63
|
+
return NOT_FOUND;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Is this site agent-facing — something an agent would call rather than only
|
|
67
|
+
* read?
|
|
68
|
+
*
|
|
69
|
+
* An Agent Card describes capabilities another agent can invoke. Most sites do
|
|
70
|
+
* not have any, and asking a restaurant to publish one is noise. A site that
|
|
71
|
+
* runs an MCP server, offers an API, or already publishes a card is a different
|
|
72
|
+
* matter.
|
|
73
|
+
*/
|
|
74
|
+
export async function hasAgentSurface(ctx) {
|
|
75
|
+
if (forcedBy(profileFrom(ctx), 'agent'))
|
|
76
|
+
return { found: true, reason: '--profile agent' };
|
|
77
|
+
for (const path of ['/.well-known/agent-card.json', '/.well-known/agent.json']) {
|
|
78
|
+
if (await exists(ctx, path))
|
|
79
|
+
return { found: true, reason: `a document at ${path}` };
|
|
80
|
+
}
|
|
81
|
+
const catalog = await ctx.fetch(`${ctx.url}/.well-known/ai-catalog.json`);
|
|
82
|
+
if (catalog.ok && /application\/a2a-agent-card\+json/.test(catalog.body)) {
|
|
83
|
+
return { found: true, reason: 'an A2A entry in the AI catalog' };
|
|
84
|
+
}
|
|
85
|
+
const mcp = await hasMcpSurface(ctx);
|
|
86
|
+
if (mcp.found)
|
|
87
|
+
return { found: true, reason: `an MCP surface (${mcp.reason})` };
|
|
88
|
+
const api = await hasApiSurface(ctx);
|
|
89
|
+
if (api.found)
|
|
90
|
+
return { found: true, reason: `an API surface (${api.reason})` };
|
|
91
|
+
return NOT_FOUND;
|
|
92
|
+
}
|
|
93
|
+
/** Does this site have documentation an agent could be taught to follow? */
|
|
94
|
+
export async function hasDocsSurface(ctx) {
|
|
95
|
+
if (forcedBy(profileFrom(ctx), 'docs'))
|
|
96
|
+
return { found: true, reason: '--profile docs' };
|
|
97
|
+
if (linksTo(ctx, /href\s*=\s*["'][^"']*\/(docs|documentation|guides?|reference|developers?)\b/i)) {
|
|
98
|
+
return { found: true, reason: 'navigation into a documentation area' };
|
|
99
|
+
}
|
|
100
|
+
for (const path of ['/llms.txt', '/openapi.json']) {
|
|
101
|
+
if (await exists(ctx, path))
|
|
102
|
+
return { found: true, reason: `a document at ${path}` };
|
|
103
|
+
}
|
|
104
|
+
return NOT_FOUND;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../../src/checks/surface.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tls-https.d.ts","sourceRoot":"","sources":["../../src/checks/tls-https.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"tls-https.d.ts","sourceRoot":"","sources":["../../src/checks/tls-https.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,EAAE,SAIlB,CAAC;AAKF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAqI3E"}
|