ax-audit 3.0.0 → 3.6.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 +76 -0
- package/README.md +61 -221
- package/dist/checks/agent-access.d.ts +16 -0
- package/dist/checks/agent-access.d.ts.map +1 -0
- package/dist/checks/agent-access.js +110 -0
- package/dist/checks/agent-access.js.map +1 -0
- package/dist/checks/content-negotiation.d.ts +4 -0
- package/dist/checks/content-negotiation.d.ts.map +1 -0
- package/dist/checks/content-negotiation.js +138 -0
- package/dist/checks/content-negotiation.js.map +1 -0
- package/dist/checks/crawl-efficiency.d.ts +4 -0
- package/dist/checks/crawl-efficiency.d.ts.map +1 -0
- package/dist/checks/crawl-efficiency.js +122 -0
- package/dist/checks/crawl-efficiency.js.map +1 -0
- package/dist/checks/index.d.ts.map +1 -1
- package/dist/checks/index.js +8 -0
- package/dist/checks/index.js.map +1 -1
- package/dist/checks/robots-txt.d.ts +20 -0
- package/dist/checks/robots-txt.d.ts.map +1 -1
- package/dist/checks/robots-txt.js +111 -3
- package/dist/checks/robots-txt.js.map +1 -1
- package/dist/checks/rsl.d.ts +6 -0
- package/dist/checks/rsl.d.ts.map +1 -0
- package/dist/checks/rsl.js +252 -0
- package/dist/checks/rsl.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -2
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +17 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +42 -1
- package/dist/constants.js.map +1 -1
- package/dist/fetcher.d.ts +7 -3
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/fetcher.js +68 -30
- package/dist/fetcher.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -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 +13 -6
- package/dist/orchestrator.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 +76 -0
- package/dist/reporter/markdown.js.map +1 -0
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +8 -0
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +17 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/api.md +200 -0
- package/docs/architecture.md +88 -0
- package/docs/checks.md +322 -0
- package/docs/ci.md +89 -0
- package/docs/cli.md +67 -0
- package/docs/concepts.md +87 -0
- package/docs/faq.md +77 -0
- package/docs/getting-started.md +101 -0
- package/package.json +2 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { RSL_MIME, RSL_NAMESPACE, RSL_PAYMENT_TYPES, RSL_PERMIT_TYPES, RSL_USAGE_TOKENS, RSL_USER_TOKENS, } from '../constants.js';
|
|
2
|
+
import { guideUrl } from '../guide-urls.js';
|
|
3
|
+
import { buildResult, checkContentType } from './utils.js';
|
|
4
|
+
import { findLinkTags, getAttribute, getTagAttribute } from './html-utils.js';
|
|
5
|
+
import { parseLinkHeader } from './http-headers.js';
|
|
6
|
+
export const meta = {
|
|
7
|
+
id: 'rsl',
|
|
8
|
+
name: 'RSL License',
|
|
9
|
+
description: 'Checks Really Simple Licensing (RSL) discovery and license document validity',
|
|
10
|
+
weight: 0, // Informational in 3.x — will gain weight in v4.0 (score-affecting changes are treated as breaking).
|
|
11
|
+
};
|
|
12
|
+
/** Score when discovery exists but the referenced license document cannot be fetched. */
|
|
13
|
+
const UNREACHABLE_DOC_SCORE = 25;
|
|
14
|
+
/** Extract `License:` directive values from robots.txt (RSL 1.0 §4.4.1). */
|
|
15
|
+
export function parseRobotsLicenseDirectives(text) {
|
|
16
|
+
const values = [];
|
|
17
|
+
for (const line of text.split('\n')) {
|
|
18
|
+
const m = line.trim().match(/^License:\s*(.+)$/i);
|
|
19
|
+
if (m)
|
|
20
|
+
values.push(m[1].trim());
|
|
21
|
+
}
|
|
22
|
+
return values;
|
|
23
|
+
}
|
|
24
|
+
function isAbsoluteUrl(value) {
|
|
25
|
+
try {
|
|
26
|
+
new URL(value);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export default async function check(ctx) {
|
|
34
|
+
const start = performance.now();
|
|
35
|
+
const findings = [];
|
|
36
|
+
let score = 100;
|
|
37
|
+
/* ── Discovery (RSL 1.0 §4.4–4.6) ─────────────────────────────────── */
|
|
38
|
+
const discoveries = [];
|
|
39
|
+
const robotsRes = await ctx.fetch(`${ctx.url}/robots.txt`);
|
|
40
|
+
const directives = robotsRes.ok ? parseRobotsLicenseDirectives(robotsRes.body) : [];
|
|
41
|
+
for (const value of directives) {
|
|
42
|
+
discoveries.push({ mechanism: 'robots.txt License directive', url: value });
|
|
43
|
+
}
|
|
44
|
+
const linkEntries = parseLinkHeader(ctx.headers['link'] ?? '');
|
|
45
|
+
for (const entry of linkEntries) {
|
|
46
|
+
if (entry.params['rel'] === 'license' && (entry.params['type'] ?? '').includes(RSL_MIME)) {
|
|
47
|
+
discoveries.push({ mechanism: 'Link header', url: entry.url });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
for (const tag of findLinkTags(ctx.html, 'license')) {
|
|
51
|
+
const type = getAttribute(tag, 'type');
|
|
52
|
+
const href = getAttribute(tag, 'href');
|
|
53
|
+
if (type !== null && type.toLowerCase().includes(RSL_MIME) && href !== null) {
|
|
54
|
+
discoveries.push({ mechanism: 'HTML <link rel="license">', url: href });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (discoveries.length === 0) {
|
|
58
|
+
findings.push({
|
|
59
|
+
status: 'fail',
|
|
60
|
+
message: 'No RSL license discovery found',
|
|
61
|
+
detail: 'Checked robots.txt License directive, Link header, and <link rel="license" type="application/rsl+xml">',
|
|
62
|
+
hint: 'Declare machine-readable licensing terms for your content with Really Simple Licensing. ' +
|
|
63
|
+
'Add to robots.txt: License: https://your-site.com/license.xml — then publish the RSL document. ' +
|
|
64
|
+
'See https://rslstandard.org.',
|
|
65
|
+
learnMoreUrl: guideUrl(meta.id, 'not-found'),
|
|
66
|
+
});
|
|
67
|
+
return buildResult(meta, 0, findings, start);
|
|
68
|
+
}
|
|
69
|
+
const mechanisms = [...new Set(discoveries.map((d) => d.mechanism))];
|
|
70
|
+
findings.push({
|
|
71
|
+
status: 'pass',
|
|
72
|
+
message: `RSL license discovered via ${mechanisms.join(' + ')} (${discoveries.length} reference(s))`,
|
|
73
|
+
});
|
|
74
|
+
// The robots.txt directive value MUST be an absolute URI (RSL 1.0 §4.4.1).
|
|
75
|
+
const relativeDirectives = directives.filter((d) => !isAbsoluteUrl(d));
|
|
76
|
+
if (relativeDirectives.length > 0) {
|
|
77
|
+
findings.push({
|
|
78
|
+
status: 'warn',
|
|
79
|
+
message: 'robots.txt License directive must be an absolute URI',
|
|
80
|
+
detail: relativeDirectives.join(', '),
|
|
81
|
+
hint: 'Use a fully qualified URL: License: https://your-site.com/license.xml',
|
|
82
|
+
learnMoreUrl: guideUrl(meta.id, 'relative-license-url'),
|
|
83
|
+
});
|
|
84
|
+
score -= 10;
|
|
85
|
+
}
|
|
86
|
+
/* ── Fetch and validate the license document ──────────────────────── */
|
|
87
|
+
const target = discoveries[0];
|
|
88
|
+
const docUrl = isAbsoluteUrl(target.url) ? target.url : new URL(target.url, `${ctx.url}/`).toString();
|
|
89
|
+
const docRes = await ctx.fetch(docUrl);
|
|
90
|
+
if (!docRes.ok) {
|
|
91
|
+
findings.push({
|
|
92
|
+
status: 'fail',
|
|
93
|
+
message: `RSL license document could not be fetched (${docUrl})`,
|
|
94
|
+
detail: `HTTP ${docRes.status || 'network error'}`,
|
|
95
|
+
hint: 'The discovery reference points to a missing document. Publish the RSL XML at the referenced URL.',
|
|
96
|
+
learnMoreUrl: guideUrl(meta.id, 'fetch-failed'),
|
|
97
|
+
});
|
|
98
|
+
return buildResult(meta, Math.min(score, UNREACHABLE_DOC_SCORE), findings, start);
|
|
99
|
+
}
|
|
100
|
+
const ctFinding = checkContentType(docRes, [RSL_MIME], {
|
|
101
|
+
checkId: meta.id,
|
|
102
|
+
resourceLabel: 'RSL license document',
|
|
103
|
+
anchor: 'wrong-content-type',
|
|
104
|
+
});
|
|
105
|
+
if (ctFinding) {
|
|
106
|
+
findings.push(ctFinding);
|
|
107
|
+
score -= 5;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
findings.push({ status: 'pass', message: `RSL document Content-Type OK (${RSL_MIME})` });
|
|
111
|
+
}
|
|
112
|
+
score = validateRslDocument(docRes.body, findings, score);
|
|
113
|
+
return buildResult(meta, score, findings, start);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Regex-based structural validation of an RSL 1.0 document. Not a full XML parse —
|
|
117
|
+
* consistent with the dependency-free approach used across all checks — but covers
|
|
118
|
+
* the conformance points of §2.2 and §3: root element + namespace, <content url>,
|
|
119
|
+
* <license> presence, permits/prohibits vocabulary, and payment types.
|
|
120
|
+
*/
|
|
121
|
+
function validateRslDocument(rawBody, findings, score) {
|
|
122
|
+
const body = rawBody.replace(/<!--[\s\S]*?-->/g, '');
|
|
123
|
+
if (!/<rsl[\s>]/i.test(body)) {
|
|
124
|
+
findings.push({
|
|
125
|
+
status: 'fail',
|
|
126
|
+
message: 'Root <rsl> element not found in license document',
|
|
127
|
+
hint: 'An RSL document must have <rsl xmlns="https://rslstandard.org/rsl"> as its root element.',
|
|
128
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-root'),
|
|
129
|
+
});
|
|
130
|
+
return score - 40;
|
|
131
|
+
}
|
|
132
|
+
const xmlns = getTagAttribute(body, 'rsl', 'xmlns');
|
|
133
|
+
if (xmlns === RSL_NAMESPACE) {
|
|
134
|
+
findings.push({ status: 'pass', message: 'Root <rsl> element with correct namespace' });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
findings.push({
|
|
138
|
+
status: 'warn',
|
|
139
|
+
message: xmlns === null ? 'Missing xmlns on <rsl> root element' : `Wrong RSL namespace: "${xmlns}"`,
|
|
140
|
+
hint: `Declare the default namespace: <rsl xmlns="${RSL_NAMESPACE}">`,
|
|
141
|
+
learnMoreUrl: guideUrl(meta.id, 'wrong-namespace'),
|
|
142
|
+
});
|
|
143
|
+
score -= 15;
|
|
144
|
+
}
|
|
145
|
+
const contentTags = [...body.matchAll(/<content\b([^>]*?)\/?>/gi)].map((m) => m[1]);
|
|
146
|
+
if (contentTags.length === 0) {
|
|
147
|
+
findings.push({
|
|
148
|
+
status: 'warn',
|
|
149
|
+
message: 'No <content> elements found in license document',
|
|
150
|
+
hint: 'Declare at least one <content url="/"> element wrapping a <license>.',
|
|
151
|
+
learnMoreUrl: guideUrl(meta.id, 'no-content-elements'),
|
|
152
|
+
});
|
|
153
|
+
return score - 20;
|
|
154
|
+
}
|
|
155
|
+
// `url` is required on every <content>; an empty value is legal for HTML pages (§3.3).
|
|
156
|
+
const missingUrl = contentTags.filter((attrs) => getAttribute(attrs, 'url') === null).length;
|
|
157
|
+
if (missingUrl > 0) {
|
|
158
|
+
findings.push({
|
|
159
|
+
status: 'warn',
|
|
160
|
+
message: `${missingUrl}/${contentTags.length} <content> element(s) missing the required url attribute`,
|
|
161
|
+
hint: 'Every <content> element must carry a url attribute identifying the licensed asset (url="" is allowed for pages linked via <link rel="license">).',
|
|
162
|
+
learnMoreUrl: guideUrl(meta.id, 'missing-content-url'),
|
|
163
|
+
});
|
|
164
|
+
score -= 10;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
findings.push({ status: 'pass', message: `${contentTags.length} <content> element(s), all with url attribute` });
|
|
168
|
+
}
|
|
169
|
+
if (!/<license[\s>]/i.test(body)) {
|
|
170
|
+
findings.push({
|
|
171
|
+
status: 'warn',
|
|
172
|
+
message: 'No <license> elements found in license document',
|
|
173
|
+
hint: 'Each <content> element must contain at least one <license> element with its terms.',
|
|
174
|
+
learnMoreUrl: guideUrl(meta.id, 'no-license-elements'),
|
|
175
|
+
});
|
|
176
|
+
score -= 15;
|
|
177
|
+
}
|
|
178
|
+
score = validatePermits(body, findings, score);
|
|
179
|
+
score = validatePayments(body, findings, score);
|
|
180
|
+
return score;
|
|
181
|
+
}
|
|
182
|
+
function validatePermits(body, findings, score) {
|
|
183
|
+
const invalidTypes = [];
|
|
184
|
+
const unknownTokens = [];
|
|
185
|
+
const validSummaries = [];
|
|
186
|
+
for (const m of body.matchAll(/<(permits|prohibits)\b([^>]*)>([^<]*)</gi)) {
|
|
187
|
+
const element = m[1].toLowerCase();
|
|
188
|
+
const type = (getAttribute(m[2], 'type') ?? '').toLowerCase();
|
|
189
|
+
const tokens = m[3].trim().split(/\s+/).filter(Boolean);
|
|
190
|
+
if (!RSL_PERMIT_TYPES.includes(type)) {
|
|
191
|
+
invalidTypes.push(`<${element} type="${type || '(none)'}">`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const vocabulary = type === 'usage' ? RSL_USAGE_TOKENS : type === 'user' ? RSL_USER_TOKENS : null;
|
|
195
|
+
const bad = vocabulary !== null
|
|
196
|
+
? tokens.filter((t) => !vocabulary.includes(t.toLowerCase()))
|
|
197
|
+
: tokens.filter((t) => !/^[A-Z]{2}$/.test(t)); // geo: ISO 3166-1 alpha-2
|
|
198
|
+
if (bad.length > 0) {
|
|
199
|
+
unknownTokens.push(`<${element} type="${type}">: ${bad.join(' ')}`);
|
|
200
|
+
}
|
|
201
|
+
else if (tokens.length > 0) {
|
|
202
|
+
validSummaries.push(`${element}[${type}]: ${tokens.join(' ')}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (validSummaries.length > 0) {
|
|
206
|
+
findings.push({ status: 'pass', message: `License terms declared — ${validSummaries.join('; ')}` });
|
|
207
|
+
}
|
|
208
|
+
if (invalidTypes.length > 0) {
|
|
209
|
+
findings.push({
|
|
210
|
+
status: 'warn',
|
|
211
|
+
message: 'permits/prohibits with invalid type attribute',
|
|
212
|
+
detail: invalidTypes.join(', '),
|
|
213
|
+
hint: `Valid types are: ${RSL_PERMIT_TYPES.join(', ')}.`,
|
|
214
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-permits'),
|
|
215
|
+
});
|
|
216
|
+
score -= 5;
|
|
217
|
+
}
|
|
218
|
+
if (unknownTokens.length > 0) {
|
|
219
|
+
findings.push({
|
|
220
|
+
status: 'warn',
|
|
221
|
+
message: 'permits/prohibits with tokens outside the RSL vocabulary',
|
|
222
|
+
detail: unknownTokens.join('; '),
|
|
223
|
+
hint: `Usage tokens: ${RSL_USAGE_TOKENS.join(', ')}. User tokens: ${RSL_USER_TOKENS.join(', ')}. ` +
|
|
224
|
+
'Geo tokens: ISO 3166-1 alpha-2 codes. Pre-1.0 draft tokens (train-ai, train-genai, ai-use, ai-summarize) ' +
|
|
225
|
+
'were replaced in RSL 1.0 by ai-train, ai-input, and ai-index.',
|
|
226
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-permits'),
|
|
227
|
+
});
|
|
228
|
+
score -= 5;
|
|
229
|
+
}
|
|
230
|
+
return score;
|
|
231
|
+
}
|
|
232
|
+
function validatePayments(body, findings, score) {
|
|
233
|
+
const invalid = [];
|
|
234
|
+
for (const m of body.matchAll(/<payment\b([^>]*?)\/?>/gi)) {
|
|
235
|
+
const type = getAttribute(m[1], 'type');
|
|
236
|
+
if (type !== null && !RSL_PAYMENT_TYPES.includes(type.toLowerCase())) {
|
|
237
|
+
invalid.push(type);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (invalid.length > 0) {
|
|
241
|
+
findings.push({
|
|
242
|
+
status: 'warn',
|
|
243
|
+
message: 'payment element(s) with invalid type attribute',
|
|
244
|
+
detail: invalid.join(', '),
|
|
245
|
+
hint: `Valid payment types are: ${RSL_PAYMENT_TYPES.join(', ')}. Omitting type means free.`,
|
|
246
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-payment-type'),
|
|
247
|
+
});
|
|
248
|
+
score -= 5;
|
|
249
|
+
}
|
|
250
|
+
return score;
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=rsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rsl.js","sourceRoot":"","sources":["../../src/checks/rsl.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsBA,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiJxC"}
|
package/dist/cli.js
CHANGED
|
@@ -12,9 +12,11 @@ export function cli(argv) {
|
|
|
12
12
|
.version(VERSION, '-v, --version')
|
|
13
13
|
.argument('<urls...>', 'One or more URLs to audit (e.g., https://example.com)')
|
|
14
14
|
.option('--json', 'Output results as JSON')
|
|
15
|
-
.option('--output <format>', 'Output format: terminal, json, html', 'terminal')
|
|
15
|
+
.option('--output <format>', 'Output format: terminal, json, html, markdown', 'terminal')
|
|
16
16
|
.option('--checks <list>', 'Comma-separated list of checks to run')
|
|
17
17
|
.option('--timeout <ms>', 'Per-request timeout in milliseconds', '10000')
|
|
18
|
+
.option('--retries <n>', 'Retry attempts for transient fetch failures (timeouts, 5xx)', '2')
|
|
19
|
+
.option('--concurrency <n>', 'Max URLs to audit in parallel (batch mode)', '1')
|
|
18
20
|
.option('--verbose', 'Show detailed request and check execution logs')
|
|
19
21
|
.option('--only-failures', 'Only show checks/findings with failures or warnings')
|
|
20
22
|
.option('--save-baseline <path>', 'Save audit result as a baseline JSON file for future comparison')
|
|
@@ -35,6 +37,11 @@ export function cli(argv) {
|
|
|
35
37
|
process.exit(1);
|
|
36
38
|
}
|
|
37
39
|
const format = (options.json ? 'json' : options.output);
|
|
40
|
+
const validFormats = ['terminal', 'json', 'html', 'markdown'];
|
|
41
|
+
if (!validFormats.includes(format)) {
|
|
42
|
+
console.error(`Error: Unknown output format "${format}". Valid: ${validFormats.join(', ')}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
38
45
|
const checks = options.checks ? options.checks.split(',').map((s) => s.trim()) : undefined;
|
|
39
46
|
if (checks) {
|
|
40
47
|
const validIds = allChecks.map((c) => c.meta.id);
|
|
@@ -45,9 +52,20 @@ export function cli(argv) {
|
|
|
45
52
|
process.exit(1);
|
|
46
53
|
}
|
|
47
54
|
}
|
|
55
|
+
const retries = parseInt(options.retries, 10);
|
|
56
|
+
if (isNaN(retries) || retries < 0) {
|
|
57
|
+
console.error('Error: --retries must be a non-negative integer');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const concurrency = parseInt(options.concurrency, 10);
|
|
61
|
+
if (isNaN(concurrency) || concurrency < 1) {
|
|
62
|
+
console.error('Error: --concurrency must be a positive integer');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
48
65
|
const baseOptions = {
|
|
49
66
|
checks,
|
|
50
67
|
timeout: parseInt(options.timeout, 10),
|
|
68
|
+
retries,
|
|
51
69
|
verbose: options.verbose,
|
|
52
70
|
};
|
|
53
71
|
// Load baseline if requested (fail fast before running the audit)
|
|
@@ -96,7 +114,7 @@ export function cli(argv) {
|
|
|
96
114
|
console.error('Error: --baseline is not supported with multiple URLs. Run single-URL audits for baseline comparison.');
|
|
97
115
|
process.exit(1);
|
|
98
116
|
}
|
|
99
|
-
const batch = await batchAudit(urls, baseOptions);
|
|
117
|
+
const batch = await batchAudit(urls, { ...baseOptions, concurrency });
|
|
100
118
|
if (options.onlyFailures) {
|
|
101
119
|
batch.reports = batch.reports.map((r) => applyOnlyFailures(r, true));
|
|
102
120
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -25,6 +25,23 @@ export declare const CORE_AI_CRAWLERS: string[];
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const CHECK_WEIGHTS: Record<string, number>;
|
|
27
27
|
export declare const GRADES: Grade[];
|
|
28
|
+
/**
|
|
29
|
+
* Content Signals Policy vocabulary (https://contentsignals.org, CC0): machine-readable
|
|
30
|
+
* `Content-Signal:` robots.txt directives expressing how content may be used after access.
|
|
31
|
+
* Absence of a signal is neutral — it neither grants nor restricts.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CONTENT_SIGNALS: string[];
|
|
34
|
+
/**
|
|
35
|
+
* Really Simple Licensing 1.0 (https://rslstandard.org/rsl): machine-readable licensing
|
|
36
|
+
* terms for content, discovered via robots.txt `License:`, HTTP `Link: rel="license"`,
|
|
37
|
+
* or `<link rel="license" type="application/rsl+xml">`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const RSL_NAMESPACE = "https://rslstandard.org/rsl";
|
|
40
|
+
export declare const RSL_MIME = "application/rsl+xml";
|
|
41
|
+
export declare const RSL_PERMIT_TYPES: string[];
|
|
42
|
+
export declare const RSL_USAGE_TOKENS: string[];
|
|
43
|
+
export declare const RSL_USER_TOKENS: string[];
|
|
44
|
+
export declare const RSL_PAYMENT_TYPES: string[];
|
|
28
45
|
export declare const AGENT_JSON_REQUIRED_FIELDS: string[];
|
|
29
46
|
export declare const SECURITY_TXT_REQUIRED_FIELDS: string[];
|
|
30
47
|
export declare const SECURITY_HEADERS: SecurityHeader[];
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKxD,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAC3C,eAAO,MAAM,UAAU,QAAqE,CAAC;AAE7F;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKxD,eAAO,MAAM,OAAO,EAAE,MAAoB,CAAC;AAC3C,eAAO,MAAM,UAAU,QAAqE,CAAC;AAE7F;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAuDhD,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,MAAM,EAA8E,CAAC;AAEnH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,EASpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBhD,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,EAKzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,EAAuC,CAAC;AAE5E;;;;GAIG;AACH,eAAO,MAAM,aAAa,gCAAgC,CAAC;AAC3D,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAC9C,eAAO,MAAM,gBAAgB,EAAE,MAAM,EAA6B,CAAC;AACnE,eAAO,MAAM,gBAAgB,EAAE,MAAM,EAAoE,CAAC;AAC1G,eAAO,MAAM,eAAe,EAAE,MAAM,EAA4E,CAAC;AACjH,eAAO,MAAM,iBAAiB,EAAE,MAAM,EASrC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,MAAM,EAA6C,CAAC;AAE7F,eAAO,MAAM,4BAA4B,EAAE,MAAM,EAA2B,CAAC;AAE7E,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAQ5C,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -59,7 +59,16 @@ export const AI_CRAWLERS = {
|
|
|
59
59
|
'NeevaBot',
|
|
60
60
|
'PhindBot',
|
|
61
61
|
],
|
|
62
|
-
fetching: [
|
|
62
|
+
fetching: [
|
|
63
|
+
'FirecrawlAgent',
|
|
64
|
+
'Facebookbot',
|
|
65
|
+
'Bingbot',
|
|
66
|
+
'Goose',
|
|
67
|
+
'AwarioBot',
|
|
68
|
+
'AwarioRssBot',
|
|
69
|
+
'AwarioSmartBot',
|
|
70
|
+
'Google-Agent', // Google's official signed AI-agent UA (identity https://agent.bot.goog), oficializado 2026
|
|
71
|
+
],
|
|
63
72
|
};
|
|
64
73
|
export const ALL_AI_CRAWLERS = [...AI_CRAWLERS.training, ...AI_CRAWLERS.search, ...AI_CRAWLERS.fetching];
|
|
65
74
|
/**
|
|
@@ -97,6 +106,12 @@ export const CHECK_WEIGHTS = {
|
|
|
97
106
|
'tls-https': 5,
|
|
98
107
|
sitemap: 4,
|
|
99
108
|
'well-known-ai': 3,
|
|
109
|
+
// Informational in 3.x: reported but does not affect the overall score.
|
|
110
|
+
// Will gain weight in v4.0 — score-affecting changes are treated as breaking (see CHANGELOG 3.0.0).
|
|
111
|
+
'content-negotiation': 0,
|
|
112
|
+
rsl: 0,
|
|
113
|
+
'agent-access': 0,
|
|
114
|
+
'crawl-efficiency': 0,
|
|
100
115
|
};
|
|
101
116
|
export const GRADES = [
|
|
102
117
|
{ min: 90, label: 'Excellent', color: 'green' },
|
|
@@ -104,6 +119,32 @@ export const GRADES = [
|
|
|
104
119
|
{ min: 50, label: 'Fair', color: 'orange' },
|
|
105
120
|
{ min: 0, label: 'Poor', color: 'red' },
|
|
106
121
|
];
|
|
122
|
+
/**
|
|
123
|
+
* Content Signals Policy vocabulary (https://contentsignals.org, CC0): machine-readable
|
|
124
|
+
* `Content-Signal:` robots.txt directives expressing how content may be used after access.
|
|
125
|
+
* Absence of a signal is neutral — it neither grants nor restricts.
|
|
126
|
+
*/
|
|
127
|
+
export const CONTENT_SIGNALS = ['search', 'ai-input', 'ai-train'];
|
|
128
|
+
/**
|
|
129
|
+
* Really Simple Licensing 1.0 (https://rslstandard.org/rsl): machine-readable licensing
|
|
130
|
+
* terms for content, discovered via robots.txt `License:`, HTTP `Link: rel="license"`,
|
|
131
|
+
* or `<link rel="license" type="application/rsl+xml">`.
|
|
132
|
+
*/
|
|
133
|
+
export const RSL_NAMESPACE = 'https://rslstandard.org/rsl';
|
|
134
|
+
export const RSL_MIME = 'application/rsl+xml';
|
|
135
|
+
export const RSL_PERMIT_TYPES = ['usage', 'user', 'geo'];
|
|
136
|
+
export const RSL_USAGE_TOKENS = ['all', 'ai-all', 'ai-train', 'ai-input', 'ai-index', 'search'];
|
|
137
|
+
export const RSL_USER_TOKENS = ['commercial', 'non-commercial', 'education', 'government', 'personal'];
|
|
138
|
+
export const RSL_PAYMENT_TYPES = [
|
|
139
|
+
'purchase',
|
|
140
|
+
'subscription',
|
|
141
|
+
'training',
|
|
142
|
+
'crawl',
|
|
143
|
+
'use',
|
|
144
|
+
'contribution',
|
|
145
|
+
'attribution',
|
|
146
|
+
'free',
|
|
147
|
+
];
|
|
107
148
|
export const AGENT_JSON_REQUIRED_FIELDS = ['name', 'description', 'url', 'skills'];
|
|
108
149
|
export const SECURITY_TXT_REQUIRED_FIELDS = ['Contact', 'Expires'];
|
|
109
150
|
export const SECURITY_HEADERS = [
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAErF,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAC;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,GAAG,CAAC,OAAO,2CAA2C,CAAC;AAE7F;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,WAAW,GAA6B;IACnD,QAAQ,EAAE;QACR,QAAQ;QACR,WAAW;QACX,YAAY;QACZ,cAAc;QACd,iBAAiB;QACjB,OAAO;QACP,YAAY;QACZ,oBAAoB;QACpB,sBAAsB;QACtB,WAAW;QACX,8BAA8B;QAC9B,mBAAmB;QACnB,WAAW;QACX,QAAQ;QACR,cAAc;QACd,aAAa;QACb,UAAU;QACV,SAAS;QACT,gBAAgB;QAChB,cAAc;QACd,UAAU;QACV,QAAQ;QACR,WAAW;QACX,cAAc;QACd,iBAAiB;KAClB;IACD,MAAM,EAAE;QACN,eAAe;QACf,cAAc;QACd,kBAAkB;QAClB,aAAa;QACb,eAAe;QACf,iBAAiB;QACjB,eAAe;QACf,QAAQ;QACR,UAAU;QACV,uBAAuB;QACvB,QAAQ;QACR,WAAW;QACX,SAAS;QACT,UAAU;QACV,UAAU;KACX;IACD,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/fetcher.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import type { FetchResponse } from './types.js';
|
|
1
|
+
import type { FetchOptions, FetchResponse } from './types.js';
|
|
2
2
|
interface FetcherOptions {
|
|
3
3
|
timeout?: number;
|
|
4
4
|
verbose?: boolean;
|
|
5
|
+
/** Number of retry attempts for transient failures (timeouts, 5xx, network errors). Default 2. */
|
|
6
|
+
retries?: number;
|
|
7
|
+
/** Base delay in ms for exponential backoff between retries. Default 250. */
|
|
8
|
+
retryBaseDelay?: number;
|
|
5
9
|
}
|
|
6
10
|
interface Fetcher {
|
|
7
|
-
fetch: (url: string) => Promise<FetchResponse>;
|
|
11
|
+
fetch: (url: string, options?: FetchOptions) => Promise<FetchResponse>;
|
|
8
12
|
}
|
|
9
|
-
export declare function createFetcher({ timeout, verbose }?: FetcherOptions): Fetcher;
|
|
13
|
+
export declare function createFetcher({ timeout, verbose, retries, retryBaseDelay, }?: FetcherOptions): Fetcher;
|
|
10
14
|
export {};
|
|
11
15
|
//# sourceMappingURL=fetcher.d.ts.map
|
package/dist/fetcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9D,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AASD,UAAU,OAAO;IACf,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACxE;AAqCD,wBAAgB,aAAa,CAAC,EAC5B,OAAe,EACf,OAAe,EACf,OAAW,EACX,cAAoB,GACrB,GAAE,cAAmB,GAAG,OAAO,CA6D/B"}
|
package/dist/fetcher.js
CHANGED
|
@@ -1,22 +1,55 @@
|
|
|
1
1
|
import { USER_AGENT } from './constants.js';
|
|
2
|
-
|
|
2
|
+
/** Transient HTTP status codes worth retrying. */
|
|
3
|
+
const RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
4
|
+
function sleep(ms) {
|
|
5
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
|
+
}
|
|
7
|
+
const DEFAULT_HEADERS = {
|
|
8
|
+
'User-Agent': USER_AGENT,
|
|
9
|
+
Accept: 'text/html, application/json, text/plain, */*',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Merge per-request headers over the fetcher defaults, case-insensitively.
|
|
13
|
+
* A custom `accept` header therefore replaces the default `Accept` instead
|
|
14
|
+
* of being sent alongside it.
|
|
15
|
+
*/
|
|
16
|
+
function mergeHeaders(custom) {
|
|
17
|
+
if (!custom)
|
|
18
|
+
return { ...DEFAULT_HEADERS };
|
|
19
|
+
const merged = { ...DEFAULT_HEADERS };
|
|
20
|
+
for (const [name, value] of Object.entries(custom)) {
|
|
21
|
+
const existing = Object.keys(merged).find((k) => k.toLowerCase() === name.toLowerCase());
|
|
22
|
+
if (existing)
|
|
23
|
+
delete merged[existing];
|
|
24
|
+
merged[name] = value;
|
|
25
|
+
}
|
|
26
|
+
return merged;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a deterministic cache key for a URL + header combination. Headers are
|
|
30
|
+
* lowercased and sorted so logically identical requests share one cache entry,
|
|
31
|
+
* while requests that differ only in headers (e.g. `Accept: text/markdown`)
|
|
32
|
+
* are cached separately — mirroring how `Vary: Accept` works on the wire.
|
|
33
|
+
*/
|
|
34
|
+
function cacheKey(url, options) {
|
|
35
|
+
if (!options?.headers || Object.keys(options.headers).length === 0)
|
|
36
|
+
return url;
|
|
37
|
+
const normalized = Object.entries(options.headers)
|
|
38
|
+
.map(([name, value]) => [name.toLowerCase(), value])
|
|
39
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
40
|
+
return `${url}\u0000${JSON.stringify(normalized)}`;
|
|
41
|
+
}
|
|
42
|
+
export function createFetcher({ timeout = 10000, verbose = false, retries = 2, retryBaseDelay = 250, } = {}) {
|
|
3
43
|
const cache = new Map();
|
|
4
44
|
const log = verbose ? (msg) => console.error(` [verbose] ${msg}`) : () => { };
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
log(`cache hit: ${url}`);
|
|
8
|
-
return cache.get(url);
|
|
9
|
-
}
|
|
10
|
-
log(`fetch: ${url}`);
|
|
45
|
+
/** A single fetch attempt. Never throws — failures become a status-0 result. */
|
|
46
|
+
async function attempt(url, options) {
|
|
11
47
|
const controller = new AbortController();
|
|
12
48
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
13
49
|
try {
|
|
14
50
|
const response = await fetch(url, {
|
|
15
51
|
signal: controller.signal,
|
|
16
|
-
headers:
|
|
17
|
-
'User-Agent': USER_AGENT,
|
|
18
|
-
Accept: 'text/html, application/json, text/plain, */*',
|
|
19
|
-
},
|
|
52
|
+
headers: mergeHeaders(options?.headers),
|
|
20
53
|
redirect: 'follow',
|
|
21
54
|
});
|
|
22
55
|
const body = await response.text();
|
|
@@ -24,36 +57,41 @@ export function createFetcher({ timeout = 10000, verbose = false } = {}) {
|
|
|
24
57
|
response.headers.forEach((value, key) => {
|
|
25
58
|
headers[key.toLowerCase()] = value;
|
|
26
59
|
});
|
|
27
|
-
const result = {
|
|
28
|
-
status: response.status,
|
|
29
|
-
headers,
|
|
30
|
-
body,
|
|
31
|
-
ok: response.ok,
|
|
32
|
-
url: response.url,
|
|
33
|
-
};
|
|
34
60
|
log(` ${response.status} ${response.statusText} (${body.length} bytes)`);
|
|
35
|
-
|
|
36
|
-
return result;
|
|
61
|
+
return { status: response.status, headers, body, ok: response.ok, url: response.url };
|
|
37
62
|
}
|
|
38
63
|
catch (err) {
|
|
39
64
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
40
65
|
const errorMsg = error.name === 'AbortError' ? 'Request timed out' : error.message;
|
|
41
66
|
log(` ERROR: ${errorMsg}`);
|
|
42
|
-
|
|
43
|
-
status: 0,
|
|
44
|
-
headers: {},
|
|
45
|
-
body: '',
|
|
46
|
-
ok: false,
|
|
47
|
-
url,
|
|
48
|
-
error: errorMsg,
|
|
49
|
-
};
|
|
50
|
-
cache.set(url, result);
|
|
51
|
-
return result;
|
|
67
|
+
return { status: 0, headers: {}, body: '', ok: false, url, error: errorMsg };
|
|
52
68
|
}
|
|
53
69
|
finally {
|
|
54
70
|
clearTimeout(timer);
|
|
55
71
|
}
|
|
56
72
|
}
|
|
73
|
+
async function fetchUrl(url, options) {
|
|
74
|
+
const key = cacheKey(url, options);
|
|
75
|
+
if (cache.has(key)) {
|
|
76
|
+
log(`cache hit: ${url}`);
|
|
77
|
+
return cache.get(key);
|
|
78
|
+
}
|
|
79
|
+
log(`fetch: ${url}`);
|
|
80
|
+
let result = await attempt(url, options);
|
|
81
|
+
// Retry transient failures with exponential backoff. A successful response
|
|
82
|
+
// (even a 4xx that isn't in the retry set) short-circuits immediately.
|
|
83
|
+
for (let i = 0; i < retries; i++) {
|
|
84
|
+
const transient = result.status === 0 || RETRYABLE_STATUS.has(result.status);
|
|
85
|
+
if (!transient)
|
|
86
|
+
break;
|
|
87
|
+
const delay = retryBaseDelay * 2 ** i;
|
|
88
|
+
log(` retry ${i + 1}/${retries} after ${delay}ms (status ${result.status})`);
|
|
89
|
+
await sleep(delay);
|
|
90
|
+
result = await attempt(url, options);
|
|
91
|
+
}
|
|
92
|
+
cache.set(key, result);
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
57
95
|
return { fetch: fetchUrl };
|
|
58
96
|
}
|
|
59
97
|
//# sourceMappingURL=fetcher.js.map
|