ax-audit 3.0.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to ax-audit are documented here.
4
4
 
5
+ ## [3.1.0] - 2026-06-06
6
+
7
+ ### Added
8
+
9
+ - **content-negotiation check (informational)**: probes the homepage with `Accept: text/markdown` to detect Markdown for Agents support — the pattern implemented by Cloudflare and Vercel and requested by Claude Code, Cursor, and OpenCode. Validates the negotiated `Content-Type`, that the body is actual Markdown (not a relabeled HTML document), `Vary: Accept` presence (shared-cache correctness), and reports the size reduction vs the HTML representation. Falls back to detecting `<link rel="alternate" type="text/markdown">` for partial credit.
10
+ - **Per-request fetch headers**: `CheckContext.fetch` now accepts an optional `{ headers }` argument. Custom headers merge case-insensitively over the defaults, and the in-memory cache keys on URL + normalized headers, mirroring `Vary` semantics on the wire. New exported type: `FetchOptions`.
11
+ - **31 new tests** (229 total): content-negotiation suite (19), fetcher integration suite against a real local HTTP server (9), and scorer coverage for weight-0 checks (3).
12
+
13
+ ### Fixed
14
+
15
+ - **Scorer division by zero**: `calculateOverallScore` returned `NaN` when every selected check had weight 0 (e.g. `--checks content-negotiation`). It now falls back to a plain average, and returns 0 for empty input.
16
+
17
+ ### Scoring
18
+
19
+ - The new check carries **weight 0 in 3.x**: it runs and reports findings but does not affect the overall score, so existing scores and baselines are unchanged. It will gain weight in v4.0, consistent with treating score-affecting changes as breaking (see 3.0.0).
20
+
5
21
  ## [3.0.0] - 2026-04-30
6
22
 
7
23
  ### Added — five new checks (full agent-optimization coverage)
package/README.md CHANGED
@@ -66,6 +66,9 @@ AI agents and LLMs are increasingly crawling, indexing, and interacting with web
66
66
  | **TLS / HTTPS** | HTTPS, HTTP→HTTPS redirect, HSTS with `preload` + `includeSubDomains` | 5% |
67
67
  | **Sitemap** | `sitemap.xml` (or `Sitemap:` from robots.txt) — XML validity, `<lastmod>` coverage, freshness, sitemap-index handling | 4% |
68
68
  | **AI Well-Known** | Emerging files: `/.well-known/ai.txt`, `genai.txt`, `ai-plugin.json`, `agents.json`, `nlweb.json` | 3% |
69
+ | **Content Negotiation** | Markdown for agents — `Accept: text/markdown` negotiation, `Vary: Accept`, `rel="alternate"` fallback | 0%* |
70
+
71
+ \* **Content Negotiation** is informational in 3.x: it runs and reports findings but does not affect the overall score. It will gain weight in v4.0.
69
72
 
70
73
  ## Install
71
74
 
@@ -263,6 +266,7 @@ Fail on regressions using a committed baseline:
263
266
  | `tls-https` | HTTPS + HTTP→HTTPS redirect + HSTS preload |
264
267
  | `sitemap` | sitemap.xml validation + freshness |
265
268
  | `well-known-ai` | Emerging AI discovery files |
269
+ | `content-negotiation` | Markdown via `Accept: text/markdown` (informational) |
266
270
 
267
271
  ## Testing
268
272
 
@@ -270,7 +274,7 @@ Fail on regressions using a committed baseline:
270
274
  npm test
271
275
  ```
272
276
 
273
- 198 tests covering all 14 checks, the scorer, baseline comparison, HTML parsing utilities, and edge cases. Uses Node.js built-in test runner (`node:test`), no extra test dependencies.
277
+ 229 tests covering all 15 checks, the scorer, the HTTP fetcher (against a real local server), baseline comparison, HTML parsing utilities, and edge cases. Uses Node.js built-in test runner (`node:test`), no extra test dependencies.
274
278
 
275
279
  ## Tech Stack
276
280
 
@@ -0,0 +1,4 @@
1
+ import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
+ export declare const meta: CheckMeta;
3
+ export default function check(ctx: CheckContext): Promise<CheckResult>;
4
+ //# sourceMappingURL=content-negotiation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-negotiation.d.ts","sourceRoot":"","sources":["../../src/checks/content-negotiation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAIjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAyBF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAuH3E"}
@@ -0,0 +1,138 @@
1
+ import { guideUrl } from '../guide-urls.js';
2
+ import { buildResult } from './utils.js';
3
+ import { findLinkTags, getAttribute } from './html-utils.js';
4
+ export const meta = {
5
+ id: 'content-negotiation',
6
+ name: 'Content Negotiation',
7
+ description: 'Checks whether the homepage serves Markdown to AI agents via Accept: text/markdown',
8
+ weight: 0, // Informational in 3.x — will gain weight in v4.0 (score-affecting changes are treated as breaking).
9
+ };
10
+ /** Markdown sent by agents that support content negotiation (Claude Code, Cursor, OpenCode). */
11
+ const MARKDOWN_ACCEPT = 'text/markdown';
12
+ /** Score when Markdown is not negotiated but a `<link rel="alternate" type="text/markdown">` exists. */
13
+ const ALTERNATE_ONLY_SCORE = 40;
14
+ /**
15
+ * Detect an HTML document masquerading as Markdown. Markdown may legally
16
+ * contain inline HTML, so this only flags full documents (doctype / <html> /
17
+ * <head> at the start), not embedded tags.
18
+ */
19
+ function looksLikeHtmlDocument(body) {
20
+ return /^\s*(?:<!doctype\s+html|<html[\s>]|<head[\s>])/i.test(body);
21
+ }
22
+ /** Find `<link rel="alternate" type="text/markdown">` tags in the homepage HTML. */
23
+ function findMarkdownAlternates(html) {
24
+ return findLinkTags(html, 'alternate').filter((tag) => {
25
+ const type = getAttribute(tag, 'type');
26
+ return type !== null && type.toLowerCase().includes('text/markdown');
27
+ });
28
+ }
29
+ export default async function check(ctx) {
30
+ const start = performance.now();
31
+ const findings = [];
32
+ const res = await ctx.fetch(ctx.url, { headers: { Accept: MARKDOWN_ACCEPT } });
33
+ if (res.status === 0) {
34
+ findings.push({
35
+ status: 'fail',
36
+ message: 'Could not fetch homepage with "Accept: text/markdown"',
37
+ detail: res.error ?? 'Network error',
38
+ learnMoreUrl: guideUrl(meta.id, 'fetch-error'),
39
+ });
40
+ return buildResult(meta, 0, findings, start);
41
+ }
42
+ const contentType = (res.headers['content-type'] ?? '').toLowerCase();
43
+ const servesMarkdown = res.ok && contentType.includes(MARKDOWN_ACCEPT);
44
+ if (!servesMarkdown) {
45
+ findings.push({
46
+ status: 'fail',
47
+ message: 'Homepage does not serve Markdown via content negotiation',
48
+ detail: res.status === 406
49
+ ? 'Server responded 406 Not Acceptable to "Accept: text/markdown"'
50
+ : `Got ${contentType.split(';')[0] || 'no Content-Type'} (HTTP ${res.status}) for "Accept: text/markdown"`,
51
+ hint: 'Serve a Markdown representation of your pages when agents request "Accept: text/markdown". ' +
52
+ 'Agents like Claude Code and Cursor ask for it, and Markdown cuts token usage by ~80% vs HTML. ' +
53
+ 'Cloudflare ("Markdown for Agents") and Vercel can enable this without code changes.',
54
+ learnMoreUrl: guideUrl(meta.id, res.status === 406 ? 'http-406' : 'not-supported'),
55
+ });
56
+ const alternates = findMarkdownAlternates(ctx.html);
57
+ if (alternates.length > 0) {
58
+ findings.push({
59
+ status: 'pass',
60
+ message: `Markdown alternate advertised via <link rel="alternate" type="text/markdown"> (${alternates.length} link tag(s))`,
61
+ detail: 'Discoverable, but agents must perform an extra fetch instead of negotiating the same URL.',
62
+ });
63
+ return buildResult(meta, ALTERNATE_ONLY_SCORE, findings, start);
64
+ }
65
+ findings.push({
66
+ status: 'warn',
67
+ message: 'No <link rel="alternate" type="text/markdown"> fallback found on the homepage',
68
+ hint: 'If you cannot enable content negotiation, advertise a Markdown version with ' +
69
+ '<link rel="alternate" type="text/markdown" href="/index.md"> so agents can discover it.',
70
+ learnMoreUrl: guideUrl(meta.id, 'no-alternate'),
71
+ });
72
+ return buildResult(meta, 0, findings, start);
73
+ }
74
+ let score = 100;
75
+ findings.push({
76
+ status: 'pass',
77
+ message: 'Homepage serves Markdown via content negotiation (Accept: text/markdown)',
78
+ });
79
+ if (res.body.trim().length === 0) {
80
+ findings.push({
81
+ status: 'warn',
82
+ message: 'Markdown response body is empty',
83
+ hint: 'Return the page content as Markdown — an empty body gives agents nothing to work with.',
84
+ learnMoreUrl: guideUrl(meta.id, 'empty-body'),
85
+ });
86
+ score -= 30;
87
+ }
88
+ else if (looksLikeHtmlDocument(res.body)) {
89
+ findings.push({
90
+ status: 'warn',
91
+ message: 'Response is labeled text/markdown but the body is an HTML document',
92
+ hint: 'Convert the page to actual Markdown instead of relabeling the HTML response.',
93
+ learnMoreUrl: guideUrl(meta.id, 'mislabeled-content-type'),
94
+ });
95
+ score -= 25;
96
+ }
97
+ else {
98
+ findings.push({ status: 'pass', message: 'Response body is Markdown, not an HTML document' });
99
+ }
100
+ const vary = (res.headers['vary'] ?? '').toLowerCase();
101
+ const variesOnAccept = vary
102
+ .split(',')
103
+ .map((v) => v.trim())
104
+ .some((v) => v === 'accept' || v === '*');
105
+ if (variesOnAccept) {
106
+ findings.push({ status: 'pass', message: 'Vary: Accept present (caches keep HTML and Markdown apart)' });
107
+ }
108
+ else {
109
+ findings.push({
110
+ status: 'warn',
111
+ message: 'Vary header does not include "Accept"',
112
+ detail: vary ? `Vary: ${res.headers['vary']}` : 'No Vary header',
113
+ hint: 'Send "Vary: Accept" when the same URL serves both HTML and Markdown, ' +
114
+ 'otherwise shared caches and CDNs may serve Markdown to browsers (or HTML to agents).',
115
+ learnMoreUrl: guideUrl(meta.id, 'missing-vary'),
116
+ });
117
+ score -= 15;
118
+ }
119
+ if (ctx.html.length > 0 && res.body.length > 0) {
120
+ const reduction = Math.round((1 - res.body.length / ctx.html.length) * 100);
121
+ if (reduction > 0) {
122
+ findings.push({
123
+ status: 'pass',
124
+ message: `Markdown is ~${reduction}% lighter than the HTML representation (${res.body.length} vs ${ctx.html.length} bytes)`,
125
+ });
126
+ }
127
+ else {
128
+ findings.push({
129
+ status: 'warn',
130
+ message: `Markdown response is not smaller than the HTML representation (${res.body.length} vs ${ctx.html.length} bytes)`,
131
+ hint: 'Strip navigation, boilerplate, and markup remnants from the Markdown output — its purpose is token efficiency.',
132
+ learnMoreUrl: guideUrl(meta.id, 'not-smaller'),
133
+ });
134
+ }
135
+ }
136
+ return buildResult(meta, score, findings, start);
137
+ }
138
+ //# sourceMappingURL=content-negotiation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-negotiation.js","sourceRoot":"","sources":["../../src/checks/content-negotiation.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB/C,eAAO,MAAM,MAAM,EAAE,WAAW,EAe/B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkB/C,eAAO,MAAM,MAAM,EAAE,WAAW,EAgB/B,CAAC"}
@@ -12,6 +12,7 @@ import sitemap, { meta as sitemapMeta } from './sitemap.js';
12
12
  import seoBasics, { meta as seoBasicsMeta } from './seo-basics.js';
13
13
  import tlsHttps, { meta as tlsHttpsMeta } from './tls-https.js';
14
14
  import wellKnownAi, { meta as wellKnownAiMeta } from './well-known-ai.js';
15
+ import contentNegotiation, { meta as contentNegotiationMeta } from './content-negotiation.js';
15
16
  export const checks = [
16
17
  { run: llmsTxt, meta: llmsTxtMeta },
17
18
  { run: robotsTxt, meta: robotsTxtMeta },
@@ -27,5 +28,6 @@ export const checks = [
27
28
  { run: seoBasics, meta: seoBasicsMeta },
28
29
  { run: tlsHttps, meta: tlsHttpsMeta },
29
30
  { run: wellKnownAi, meta: wellKnownAiMeta },
31
+ { run: contentNegotiation, meta: contentNegotiationMeta },
30
32
  ];
31
33
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAEA,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,cAAc,EAAE,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,QAAQ,EAAE,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,GAAG,EAAE,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,aAAa,EAAE,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,QAAQ,EAAE,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1E,MAAM,CAAC,MAAM,MAAM,GAAkB;IACnC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE;IACjD,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACrC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3B,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC/C,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACrC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;CAC5C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAEA,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,cAAc,EAAE,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,QAAQ,EAAE,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,GAAG,EAAE,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,aAAa,EAAE,EAAE,IAAI,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,OAAO,EAAE,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,SAAS,EAAE,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,QAAQ,EAAE,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,WAAW,EAAE,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,kBAAkB,EAAE,EAAE,IAAI,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAE9F,MAAM,CAAC,MAAM,MAAM,GAAkB;IACnC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE;IACjD,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACrC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3B,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC/C,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;IACnC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACrC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,EAAE,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,sBAAsB,EAAE;CAC1D,CAAC"}
@@ -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,CA8ChD,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,CAehD,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,EAKzB,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"}
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,CA8ChD,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,CAkBhD,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,EAKzB,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
@@ -97,6 +97,9 @@ export const CHECK_WEIGHTS = {
97
97
  'tls-https': 5,
98
98
  sitemap: 4,
99
99
  'well-known-ai': 3,
100
+ // Informational in 3.x: reported but does not affect the overall score.
101
+ // Will gain weight in v4.0 — score-affecting changes are treated as breaking (see CHANGELOG 3.0.0).
102
+ 'content-negotiation': 0,
100
103
  };
101
104
  export const GRADES = [
102
105
  { min: 90, label: 'Excellent', color: 'green' },
@@ -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,CAAC,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,CAAC;CAC/G,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAa,CAAC,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AAEnH;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAa;IACxC,QAAQ;IACR,WAAW;IACX,cAAc;IACd,kBAAkB;IAClB,iBAAiB;IACjB,eAAe;IACf,eAAe;IACf,OAAO;CACR,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,UAAU,EAAE,EAAE;IACd,YAAY,EAAE,EAAE;IAChB,gBAAgB,EAAE,CAAC;IACnB,iBAAiB,EAAE,CAAC;IACpB,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,GAAG,EAAE,CAAC;IACN,YAAY,EAAE,CAAC;IACf,cAAc,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC;IACd,OAAO,EAAE,CAAC;IACV,WAAW,EAAE,CAAC;IACd,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/C,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC3C,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC3C,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE;CACxC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAa,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAE7F,MAAM,CAAC,MAAM,4BAA4B,GAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,gBAAgB,GAAqB;IAChD,EAAE,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,2BAA2B,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzF,EAAE,IAAI,EAAE,wBAAwB,EAAE,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE;IACnF,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,EAAE;IACtE,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE;IACxE,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,EAAE;IACtE,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC5E,EAAE,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,yBAAyB,EAAE,QAAQ,EAAE,KAAK,EAAE;CACvF,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
package/dist/fetcher.d.ts CHANGED
@@ -1,10 +1,10 @@
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
5
  }
6
6
  interface Fetcher {
7
- fetch: (url: string) => Promise<FetchResponse>;
7
+ fetch: (url: string, options?: FetchOptions) => Promise<FetchResponse>;
8
8
  }
9
9
  export declare function createFetcher({ timeout, verbose }?: FetcherOptions): Fetcher;
10
10
  export {};
@@ -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;AAEhD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,OAAO;IACf,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAChD;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAe,EAAE,OAAe,EAAE,GAAE,cAAmB,GAAG,OAAO,CA8DhG"}
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;CACnB;AAED,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,EAAE,OAAe,EAAE,OAAe,EAAE,GAAE,cAAmB,GAAG,OAAO,CA4DhG"}
package/dist/fetcher.js CHANGED
@@ -1,11 +1,47 @@
1
1
  import { USER_AGENT } from './constants.js';
2
+ const DEFAULT_HEADERS = {
3
+ 'User-Agent': USER_AGENT,
4
+ Accept: 'text/html, application/json, text/plain, */*',
5
+ };
6
+ /**
7
+ * Merge per-request headers over the fetcher defaults, case-insensitively.
8
+ * A custom `accept` header therefore replaces the default `Accept` instead
9
+ * of being sent alongside it.
10
+ */
11
+ function mergeHeaders(custom) {
12
+ if (!custom)
13
+ return { ...DEFAULT_HEADERS };
14
+ const merged = { ...DEFAULT_HEADERS };
15
+ for (const [name, value] of Object.entries(custom)) {
16
+ const existing = Object.keys(merged).find((k) => k.toLowerCase() === name.toLowerCase());
17
+ if (existing)
18
+ delete merged[existing];
19
+ merged[name] = value;
20
+ }
21
+ return merged;
22
+ }
23
+ /**
24
+ * Build a deterministic cache key for a URL + header combination. Headers are
25
+ * lowercased and sorted so logically identical requests share one cache entry,
26
+ * while requests that differ only in headers (e.g. `Accept: text/markdown`)
27
+ * are cached separately — mirroring how `Vary: Accept` works on the wire.
28
+ */
29
+ function cacheKey(url, options) {
30
+ if (!options?.headers || Object.keys(options.headers).length === 0)
31
+ return url;
32
+ const normalized = Object.entries(options.headers)
33
+ .map(([name, value]) => [name.toLowerCase(), value])
34
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
35
+ return `${url}\u0000${JSON.stringify(normalized)}`;
36
+ }
2
37
  export function createFetcher({ timeout = 10000, verbose = false } = {}) {
3
38
  const cache = new Map();
4
39
  const log = verbose ? (msg) => console.error(` [verbose] ${msg}`) : () => { };
5
- async function fetchUrl(url) {
6
- if (cache.has(url)) {
40
+ async function fetchUrl(url, options) {
41
+ const key = cacheKey(url, options);
42
+ if (cache.has(key)) {
7
43
  log(`cache hit: ${url}`);
8
- return cache.get(url);
44
+ return cache.get(key);
9
45
  }
10
46
  log(`fetch: ${url}`);
11
47
  const controller = new AbortController();
@@ -13,10 +49,7 @@ export function createFetcher({ timeout = 10000, verbose = false } = {}) {
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();
@@ -32,7 +65,7 @@ export function createFetcher({ timeout = 10000, verbose = false } = {}) {
32
65
  url: response.url,
33
66
  };
34
67
  log(` ${response.status} ${response.statusText} (${body.length} bytes)`);
35
- cache.set(url, result);
68
+ cache.set(key, result);
36
69
  return result;
37
70
  }
38
71
  catch (err) {
@@ -47,7 +80,7 @@ export function createFetcher({ timeout = 10000, verbose = false } = {}) {
47
80
  url,
48
81
  error: errorMsg,
49
82
  };
50
- cache.set(url, result);
83
+ cache.set(key, result);
51
84
  return result;
52
85
  }
53
86
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../src/fetcher.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { audit, batchAudit } from './orchestrator.js';
2
2
  export { calculateOverallScore, getGrade } from './scorer.js';
3
3
  export { checks } from './checks/index.js';
4
4
  export { saveBaseline, loadBaseline, diffBaseline, toBaselineData } from './baseline.js';
5
- export type { AuditOptions, AuditReport, BaselineData, BaselineDiff, BatchAuditReport, CheckDiff, CheckResult, CheckMeta, CheckContext, CheckModule, Finding, FindingStatus, FetchResponse, Grade, OutputFormat, } from './types.js';
5
+ export type { AuditOptions, AuditReport, BaselineData, BaselineDiff, BatchAuditReport, CheckDiff, CheckResult, CheckMeta, CheckContext, CheckModule, Finding, FindingStatus, FetchOptions, FetchResponse, Grade, OutputFormat, } from './types.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzF,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,OAAO,EACP,aAAa,EACb,aAAa,EACb,KAAK,EACL,YAAY,GACb,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEzF,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,OAAO,EACP,aAAa,EACb,YAAY,EACZ,aAAa,EACb,KAAK,EACL,YAAY,GACb,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEhE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAgBxF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAK7C"}
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEhE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAwBxF;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAK7C"}
package/dist/scorer.js CHANGED
@@ -7,6 +7,14 @@ export function calculateOverallScore(results, metas) {
7
7
  weightMap[m.id] = m.weight ?? CHECK_WEIGHTS[m.id] ?? 10;
8
8
  totalWeight += weightMap[m.id];
9
9
  }
10
+ // All selected checks are informational (weight 0) — e.g. `--checks content-negotiation`.
11
+ // Fall back to a plain average instead of dividing by zero.
12
+ if (totalWeight === 0) {
13
+ if (results.length === 0)
14
+ return 0;
15
+ const sum = results.reduce((acc, r) => acc + r.score, 0);
16
+ return clampScore(Math.round(sum / results.length));
17
+ }
10
18
  let weightedSum = 0;
11
19
  for (const r of results) {
12
20
  const weight = weightMap[r.id] ?? 0;
@@ -1 +1 @@
1
- {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,MAAM,UAAU,qBAAqB,CAAC,OAAsB,EAAE,KAAkB;IAC9E,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACxD,WAAW,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACpC,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC;IAC1C,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;IACvC,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,MAAM,UAAU,qBAAqB,CAAC,OAAsB,EAAE,KAAkB;IAC9E,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QACxD,WAAW,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,0FAA0F;IAC1F,4DAA4D;IAC5D,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACzD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACpC,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC;IAC1C,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;IACvC,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACnC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -28,9 +28,18 @@ export interface FetchResponse {
28
28
  url: string;
29
29
  error?: string;
30
30
  }
31
+ /** Per-request options for the audit fetcher. */
32
+ export interface FetchOptions {
33
+ /**
34
+ * Extra request headers. Merged over the fetcher defaults, so a custom
35
+ * `Accept` (e.g. `text/markdown` for content-negotiation probes) replaces
36
+ * the default one. Header names are case-insensitive.
37
+ */
38
+ headers?: Record<string, string>;
39
+ }
31
40
  export interface CheckContext {
32
41
  url: string;
33
- fetch: (url: string) => Promise<FetchResponse>;
42
+ fetch: (url: string, options?: FetchOptions) => Promise<FetchResponse>;
34
43
  html: string;
35
44
  headers: Record<string, string>;
36
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ax-audit",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Audit websites for AI Agent Experience (AX) readiness. Lighthouse for AI Agents.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",