ax-audit 3.6.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.
Files changed (201) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/LICENSE +1 -1
  3. package/README.md +58 -36
  4. package/dist/baseline.d.ts +2 -0
  5. package/dist/baseline.d.ts.map +1 -1
  6. package/dist/baseline.js +42 -4
  7. package/dist/baseline.js.map +1 -1
  8. package/dist/check-ids.d.ts +19 -0
  9. package/dist/check-ids.d.ts.map +1 -0
  10. package/dist/check-ids.js +53 -0
  11. package/dist/check-ids.js.map +1 -0
  12. package/dist/checks/agent-access.d.ts +23 -6
  13. package/dist/checks/agent-access.d.ts.map +1 -1
  14. package/dist/checks/agent-access.js +200 -54
  15. package/dist/checks/agent-access.js.map +1 -1
  16. package/dist/checks/agent-card.d.ts +37 -0
  17. package/dist/checks/agent-card.d.ts.map +1 -0
  18. package/dist/checks/agent-card.js +352 -0
  19. package/dist/checks/agent-card.js.map +1 -0
  20. package/dist/checks/agent-operability.d.ts +66 -0
  21. package/dist/checks/agent-operability.d.ts.map +1 -0
  22. package/dist/checks/agent-operability.js +383 -0
  23. package/dist/checks/agent-operability.js.map +1 -0
  24. package/dist/checks/agent-skills.d.ts +24 -0
  25. package/dist/checks/agent-skills.d.ts.map +1 -0
  26. package/dist/checks/agent-skills.js +316 -0
  27. package/dist/checks/agent-skills.js.map +1 -0
  28. package/dist/checks/ai-catalog.d.ts +28 -0
  29. package/dist/checks/ai-catalog.d.ts.map +1 -0
  30. package/dist/checks/ai-catalog.js +254 -0
  31. package/dist/checks/ai-catalog.js.map +1 -0
  32. package/dist/checks/ai-directives.d.ts +57 -0
  33. package/dist/checks/ai-directives.d.ts.map +1 -0
  34. package/dist/checks/ai-directives.js +263 -0
  35. package/dist/checks/ai-directives.js.map +1 -0
  36. package/dist/checks/api-discovery.d.ts +26 -0
  37. package/dist/checks/api-discovery.d.ts.map +1 -0
  38. package/dist/checks/api-discovery.js +432 -0
  39. package/dist/checks/api-discovery.js.map +1 -0
  40. package/dist/checks/auth-discovery.d.ts +28 -0
  41. package/dist/checks/auth-discovery.d.ts.map +1 -0
  42. package/dist/checks/auth-discovery.js +213 -0
  43. package/dist/checks/auth-discovery.js.map +1 -0
  44. package/dist/checks/commerce-discovery.d.ts +40 -0
  45. package/dist/checks/commerce-discovery.d.ts.map +1 -0
  46. package/dist/checks/commerce-discovery.js +295 -0
  47. package/dist/checks/commerce-discovery.js.map +1 -0
  48. package/dist/checks/content-negotiation.d.ts.map +1 -1
  49. package/dist/checks/content-negotiation.js +135 -20
  50. package/dist/checks/content-negotiation.js.map +1 -1
  51. package/dist/checks/crawl-efficiency.d.ts +13 -1
  52. package/dist/checks/crawl-efficiency.d.ts.map +1 -1
  53. package/dist/checks/crawl-efficiency.js +65 -1
  54. package/dist/checks/crawl-efficiency.js.map +1 -1
  55. package/dist/checks/frontmatter.d.ts +34 -0
  56. package/dist/checks/frontmatter.d.ts.map +1 -0
  57. package/dist/checks/frontmatter.js +100 -0
  58. package/dist/checks/frontmatter.js.map +1 -0
  59. package/dist/checks/html-rendering.d.ts.map +1 -1
  60. package/dist/checks/html-rendering.js +0 -1
  61. package/dist/checks/html-rendering.js.map +1 -1
  62. package/dist/checks/html-utils.d.ts +10 -0
  63. package/dist/checks/html-utils.d.ts.map +1 -1
  64. package/dist/checks/html-utils.js +19 -0
  65. package/dist/checks/html-utils.js.map +1 -1
  66. package/dist/checks/http-headers.d.ts.map +1 -1
  67. package/dist/checks/http-headers.js +82 -10
  68. package/dist/checks/http-headers.js.map +1 -1
  69. package/dist/checks/http-hygiene.d.ts +26 -0
  70. package/dist/checks/http-hygiene.d.ts.map +1 -0
  71. package/dist/checks/http-hygiene.js +257 -0
  72. package/dist/checks/http-hygiene.js.map +1 -0
  73. package/dist/checks/index.d.ts.map +1 -1
  74. package/dist/checks/index.js +24 -8
  75. package/dist/checks/index.js.map +1 -1
  76. package/dist/checks/llms-txt.d.ts +15 -0
  77. package/dist/checks/llms-txt.d.ts.map +1 -1
  78. package/dist/checks/llms-txt.js +162 -2
  79. package/dist/checks/llms-txt.js.map +1 -1
  80. package/dist/checks/mcp-discovery.d.ts +30 -0
  81. package/dist/checks/mcp-discovery.d.ts.map +1 -0
  82. package/dist/checks/mcp-discovery.js +523 -0
  83. package/dist/checks/mcp-discovery.js.map +1 -0
  84. package/dist/checks/meta-tags.d.ts.map +1 -1
  85. package/dist/checks/meta-tags.js +6 -5
  86. package/dist/checks/meta-tags.js.map +1 -1
  87. package/dist/checks/robots-parser.d.ts +110 -0
  88. package/dist/checks/robots-parser.d.ts.map +1 -0
  89. package/dist/checks/robots-parser.js +277 -0
  90. package/dist/checks/robots-parser.js.map +1 -0
  91. package/dist/checks/robots-txt.d.ts +2 -20
  92. package/dist/checks/robots-txt.d.ts.map +1 -1
  93. package/dist/checks/robots-txt.js +219 -120
  94. package/dist/checks/robots-txt.js.map +1 -1
  95. package/dist/checks/rsl.d.ts +0 -2
  96. package/dist/checks/rsl.d.ts.map +1 -1
  97. package/dist/checks/rsl.js +1 -11
  98. package/dist/checks/rsl.js.map +1 -1
  99. package/dist/checks/security-txt.d.ts.map +1 -1
  100. package/dist/checks/security-txt.js +0 -1
  101. package/dist/checks/security-txt.js.map +1 -1
  102. package/dist/checks/seo-basics.d.ts.map +1 -1
  103. package/dist/checks/seo-basics.js +0 -1
  104. package/dist/checks/seo-basics.js.map +1 -1
  105. package/dist/checks/sitemap.d.ts.map +1 -1
  106. package/dist/checks/sitemap.js +0 -1
  107. package/dist/checks/sitemap.js.map +1 -1
  108. package/dist/checks/structured-data.d.ts.map +1 -1
  109. package/dist/checks/structured-data.js +215 -4
  110. package/dist/checks/structured-data.js.map +1 -1
  111. package/dist/checks/structured-fields.d.ts +46 -0
  112. package/dist/checks/structured-fields.d.ts.map +1 -0
  113. package/dist/checks/structured-fields.js +112 -0
  114. package/dist/checks/structured-fields.js.map +1 -0
  115. package/dist/checks/surface.d.ts +59 -0
  116. package/dist/checks/surface.d.ts.map +1 -0
  117. package/dist/checks/surface.js +106 -0
  118. package/dist/checks/surface.js.map +1 -0
  119. package/dist/checks/tls-https.d.ts.map +1 -1
  120. package/dist/checks/tls-https.js +0 -1
  121. package/dist/checks/tls-https.js.map +1 -1
  122. package/dist/checks/usage-policy.d.ts +53 -0
  123. package/dist/checks/usage-policy.d.ts.map +1 -0
  124. package/dist/checks/usage-policy.js +339 -0
  125. package/dist/checks/usage-policy.js.map +1 -0
  126. package/dist/checks/utils.d.ts +25 -1
  127. package/dist/checks/utils.d.ts.map +1 -1
  128. package/dist/checks/utils.js +33 -1
  129. package/dist/checks/utils.js.map +1 -1
  130. package/dist/checks/waf.d.ts +75 -0
  131. package/dist/checks/waf.d.ts.map +1 -0
  132. package/dist/checks/waf.js +203 -0
  133. package/dist/checks/waf.js.map +1 -0
  134. package/dist/checks/webmcp.d.ts +55 -0
  135. package/dist/checks/webmcp.d.ts.map +1 -0
  136. package/dist/checks/webmcp.js +209 -0
  137. package/dist/checks/webmcp.js.map +1 -0
  138. package/dist/checks/well-known.d.ts +38 -0
  139. package/dist/checks/well-known.d.ts.map +1 -0
  140. package/dist/checks/well-known.js +202 -0
  141. package/dist/checks/well-known.js.map +1 -0
  142. package/dist/cli.d.ts +14 -0
  143. package/dist/cli.d.ts.map +1 -1
  144. package/dist/cli.js +124 -4
  145. package/dist/cli.js.map +1 -1
  146. package/dist/constants.d.ts +195 -14
  147. package/dist/constants.d.ts.map +1 -1
  148. package/dist/constants.js +598 -70
  149. package/dist/constants.js.map +1 -1
  150. package/dist/fetcher.d.ts.map +1 -1
  151. package/dist/fetcher.js +44 -14
  152. package/dist/fetcher.js.map +1 -1
  153. package/dist/guide-urls.js +1 -1
  154. package/dist/guide-urls.js.map +1 -1
  155. package/dist/index.d.ts +2 -1
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +1 -0
  158. package/dist/index.js.map +1 -1
  159. package/dist/orchestrator.d.ts.map +1 -1
  160. package/dist/orchestrator.js +5 -1
  161. package/dist/orchestrator.js.map +1 -1
  162. package/dist/reporter/html.d.ts +9 -0
  163. package/dist/reporter/html.d.ts.map +1 -1
  164. package/dist/reporter/html.js +49 -11
  165. package/dist/reporter/html.js.map +1 -1
  166. package/dist/reporter/markdown.d.ts.map +1 -1
  167. package/dist/reporter/markdown.js +36 -6
  168. package/dist/reporter/markdown.js.map +1 -1
  169. package/dist/reporter/terminal.d.ts.map +1 -1
  170. package/dist/reporter/terminal.js +36 -1
  171. package/dist/reporter/terminal.js.map +1 -1
  172. package/dist/scorer.d.ts +10 -0
  173. package/dist/scorer.d.ts.map +1 -1
  174. package/dist/scorer.js +22 -5
  175. package/dist/scorer.js.map +1 -1
  176. package/dist/types.d.ts +90 -3
  177. package/dist/types.d.ts.map +1 -1
  178. package/docs/architecture.md +27 -11
  179. package/docs/checks.md +285 -52
  180. package/docs/cli.md +36 -0
  181. package/docs/concepts.md +27 -13
  182. package/docs/faq.md +18 -6
  183. package/docs/getting-started.md +20 -13
  184. package/docs/roadmap.md +367 -0
  185. package/package.json +13 -5
  186. package/dist/checks/agent-json.d.ts +0 -14
  187. package/dist/checks/agent-json.d.ts.map +0 -1
  188. package/dist/checks/agent-json.js +0 -167
  189. package/dist/checks/agent-json.js.map +0 -1
  190. package/dist/checks/mcp.d.ts +0 -4
  191. package/dist/checks/mcp.d.ts.map +0 -1
  192. package/dist/checks/mcp.js +0 -162
  193. package/dist/checks/mcp.js.map +0 -1
  194. package/dist/checks/openapi.d.ts +0 -4
  195. package/dist/checks/openapi.d.ts.map +0 -1
  196. package/dist/checks/openapi.js +0 -121
  197. package/dist/checks/openapi.js.map +0 -1
  198. package/dist/checks/well-known-ai.d.ts +0 -17
  199. package/dist/checks/well-known-ai.d.ts.map +0 -1
  200. package/dist/checks/well-known-ai.js +0 -123
  201. package/dist/checks/well-known-ai.js.map +0 -1
@@ -0,0 +1,110 @@
1
+ /** A `User-agent` group and the rules attached to it. */
2
+ export interface RobotsGroup {
3
+ /** User-agent tokens sharing this group, as written. */
4
+ userAgents: string[];
5
+ allow: string[];
6
+ disallow: string[];
7
+ /** Raw `Content-Signal:` values declared in this group. */
8
+ contentSignals: string[];
9
+ /** Raw `Content-Usage:` values declared in this group. */
10
+ contentUsage: string[];
11
+ /** Group-scoped RSL `License:` values (override the global ones per RSL §4.4.1). */
12
+ licenses: string[];
13
+ crawlDelay?: string;
14
+ }
15
+ /** Everything ax-audit reads out of a robots.txt, parsed once. */
16
+ export interface RobotsTxt {
17
+ groups: RobotsGroup[];
18
+ sitemaps: string[];
19
+ /** Global (out-of-group) RSL `License:` directives. */
20
+ licenses: string[];
21
+ /** `Agentmap:` directives pointing at an ai-catalog / ARD document. */
22
+ agentmaps: string[];
23
+ /** `Content-Signal:` / `Content-Usage:` lines that appeared outside any group. */
24
+ orphanContentSignals: string[];
25
+ orphanContentUsage: string[];
26
+ /** True when Cloudflare's managed-content block markers are present. */
27
+ cloudflareManaged: boolean;
28
+ /** Total non-comment, non-blank lines — used to distinguish empty from absent. */
29
+ ruleLineCount: number;
30
+ }
31
+ /** Backwards-compatible per-bot view derived from the parsed groups. */
32
+ export interface BotEntry {
33
+ name: string;
34
+ /** A full `Disallow: /` applies to this bot. */
35
+ disallowed: boolean;
36
+ /** Any `Disallow:` rule applies to this bot (full or path-scoped). */
37
+ hasRestrictions: boolean;
38
+ hasAllow: boolean;
39
+ }
40
+ /**
41
+ * Parse a robots.txt document. Never throws: unrecognised lines are ignored,
42
+ * which is exactly what RFC 9309 §2.2.4 requires of conforming parsers.
43
+ */
44
+ export declare function parseRobotsTxt(text: string): RobotsTxt;
45
+ /**
46
+ * Flatten parsed groups into one entry per User-agent token, preserving the
47
+ * shape the 3.x checks were written against.
48
+ *
49
+ * A bot named in several groups is merged: `disallowed` is true when any group
50
+ * fully blocks it. RFC 9309 says a crawler picks the most specific matching
51
+ * group, but robots.txt files that name the same token twice are almost always
52
+ * a mistake, so merging surfaces the restriction rather than hiding it.
53
+ */
54
+ export declare function toBotEntries(robots: RobotsTxt): BotEntry[];
55
+ /** Parse text straight into bot entries. Convenience for checks that need nothing else. */
56
+ export declare function parseUserAgents(text: string): BotEntry[];
57
+ /** Every RSL `License:` value in the document, group-scoped ones included. */
58
+ export declare function collectLicenses(robots: RobotsTxt): string[];
59
+ /**
60
+ * Whether robots.txt expresses the intent to block a crawler: an explicit full
61
+ * `Disallow: /` for it, or a wildcard full block with no explicit entry.
62
+ */
63
+ export declare function intentBlocked(entries: BotEntry[], crawler: string): boolean;
64
+ export interface ParsedSignals {
65
+ /** Normalised `name=value` pairs with known names. */
66
+ valid: string[];
67
+ /** Segments not matching `name=value`. */
68
+ malformed: string[];
69
+ /** Well-formed pairs whose name is outside the policy vocabulary. */
70
+ unknown: string[];
71
+ /** Well-formed pairs with a known name but an out-of-vocabulary value. */
72
+ invalidValue: string[];
73
+ }
74
+ /**
75
+ * Parse one `Content-Signal:` value.
76
+ *
77
+ * Accepts the three boolean signals (`search`, `ai-input`, `ai-train` with
78
+ * `yes`/`no`) and the `use` field Cloudflare added on 2026-07-01, whose values
79
+ * are `immediate`, `reference` (the stated default) and `full`. Cloudflare's
80
+ * managed robots.txt writes `Content-signal:` with a lowercase `s` and a space
81
+ * after each comma, while the launch blog uses `Content-Signal:` without
82
+ * spaces; both parse identically here.
83
+ */
84
+ export declare function parseContentSignalValue(raw: string): ParsedSignals;
85
+ export interface ParsedUsage {
86
+ /** Path pattern the preference is scoped to, or `null` for the whole group. */
87
+ path: string | null;
88
+ /** Normalised `token=value` pairs over the AIPREF vocabulary. */
89
+ valid: string[];
90
+ /** Dictionary members outside the AIPREF vocabulary. */
91
+ unknown: string[];
92
+ /** Known tokens with values other than `y`/`n`. */
93
+ invalidValue: string[];
94
+ /** Segments the Structured Fields parser rejected. */
95
+ malformed: string[];
96
+ /**
97
+ * Content Signals / RSL tokens used under `Content-Usage`, e.g. `ai-train=no`
98
+ * where AIPREF expects `train-ai=n`. Reported separately because the two
99
+ * vocabularies are near-mirror images and confusing them is silent breakage.
100
+ */
101
+ crossVocabulary: string[];
102
+ }
103
+ /**
104
+ * Parse one `Content-Usage:` value per draft-ietf-aipref-attach-05 §3:
105
+ * an optional path pattern, whitespace, then a Structured Fields dictionary.
106
+ */
107
+ export declare function parseContentUsageValue(raw: string): ParsedUsage;
108
+ /** Extract every `License:` directive value (RSL 1.0 §4.4.1). */
109
+ export declare function parseRobotsLicenseDirectives(text: string): string[];
110
+ //# sourceMappingURL=robots-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots-parser.d.ts","sourceRoot":"","sources":["../../src/checks/robots-parser.ts"],"names":[],"mappings":"AAgCA,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oFAAoF;IACpF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,kEAAkE;AAClE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,uEAAuE;IACvE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kFAAkF;IAClF,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,wEAAwE;IACxE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kFAAkF;IAClF,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wEAAwE;AACxE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,sEAAsE;IACtE,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CA+FtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE,CA0B1D;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAExD;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,CAE3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAI3E;AAID,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAoClE;AAID,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wDAAwD;IACxD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mDAAmD;IACnD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,sDAAsD;IACtD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;OAIG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAKD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CA0C/D;AAID,iEAAiE;AACjE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnE"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * One robots.txt parser for every check that reads the file.
3
+ *
4
+ * Before 3.7 the group-splitting logic lived in three places (`robots-txt`
5
+ * counted User-agent groups, `rsl` scanned for `License:`, `agent-access`
6
+ * re-derived block intent) and each had its own idea of what closes a group.
7
+ * They now share this module, so a fix to the grouping rules fixes every check.
8
+ *
9
+ * Grouping follows RFC 9309 §2.2.1: consecutive `User-agent` lines accumulate
10
+ * into one group; the first rule line closes the accumulation, and the next
11
+ * `User-agent` starts a fresh group. Directives that are not part of a group
12
+ * (`Sitemap`) are collected globally.
13
+ *
14
+ * Beyond RFC 9309 this parser understands four extensions, all optional and all
15
+ * reported rather than assumed:
16
+ *
17
+ * - `Content-Signal:` — Content Signals Policy (contentsignals.org, CC0), served
18
+ * by Cloudflare's managed robots.txt on millions of zones. Values are
19
+ * `name=yes|no` pairs over `search`, `ai-input`, `ai-train`, plus the `use=`
20
+ * field Cloudflare added on 2026-07-01 (`immediate` | `reference` | `full`).
21
+ * - `Content-Usage:` — IETF AIPREF (draft-ietf-aipref-attach-05, 2026-08-19).
22
+ * An optional path pattern followed by a Structured Fields dictionary over
23
+ * `train-ai` and `search` with `y`/`n` values. Note the token inversion
24
+ * against Content Signals: AIPREF says `train-ai`, Content Signals says
25
+ * `ai-train`. Mixing them up is a real-world bug this parser can surface.
26
+ * - `License:` — Really Simple Licensing 1.0 §4.4.1, global or group-scoped.
27
+ * - `Agentmap:` — the ARD / ai-catalog discovery hint Lighthouse's `ard-schema`
28
+ * audit reads, analogous to `Sitemap:`.
29
+ */
30
+ import { CONTENT_SIGNALS, CONTENT_SIGNAL_USE_VALUES, AIPREF_TOKENS, AIPREF_VALUES } from '../constants.js';
31
+ import { parseDictionary } from './structured-fields.js';
32
+ const GROUP_DIRECTIVES = /^(Disallow|Allow|Crawl-delay|Content-Signal|Content-Usage|License|Noindex|Request-rate):/i;
33
+ /**
34
+ * Parse a robots.txt document. Never throws: unrecognised lines are ignored,
35
+ * which is exactly what RFC 9309 §2.2.4 requires of conforming parsers.
36
+ */
37
+ export function parseRobotsTxt(text) {
38
+ const result = {
39
+ groups: [],
40
+ sitemaps: [],
41
+ licenses: [],
42
+ agentmaps: [],
43
+ orphanContentSignals: [],
44
+ orphanContentUsage: [],
45
+ cloudflareManaged: /#\s*(BEGIN|END)\s+Cloudflare\s+Managed\s+[Cc]ontent/i.test(text),
46
+ ruleLineCount: 0,
47
+ };
48
+ let current = null;
49
+ // True once a rule line has been seen in the current group: the next
50
+ // `User-agent` line then starts a new group instead of joining this one.
51
+ let groupClosed = false;
52
+ for (const rawLine of text.split('\n')) {
53
+ // A comment may follow a value on the same line; strip from the first `#`
54
+ // that is not inside the value we care about. robots.txt has no quoting,
55
+ // so a plain split is correct.
56
+ const line = rawLine.split('#')[0].trim();
57
+ if (!line)
58
+ continue;
59
+ result.ruleLineCount++;
60
+ const ua = line.match(/^User-agent:\s*(.*)$/i);
61
+ if (ua) {
62
+ const name = ua[1].trim();
63
+ if (!name)
64
+ continue;
65
+ if (current === null || groupClosed) {
66
+ current = {
67
+ userAgents: [],
68
+ allow: [],
69
+ disallow: [],
70
+ contentSignals: [],
71
+ contentUsage: [],
72
+ licenses: [],
73
+ };
74
+ result.groups.push(current);
75
+ groupClosed = false;
76
+ }
77
+ current.userAgents.push(name);
78
+ continue;
79
+ }
80
+ const sitemap = line.match(/^Sitemap:\s*(.+)$/i);
81
+ if (sitemap) {
82
+ result.sitemaps.push(sitemap[1].trim());
83
+ continue;
84
+ }
85
+ const agentmap = line.match(/^Agentmap:\s*(.+)$/i);
86
+ if (agentmap) {
87
+ result.agentmaps.push(agentmap[1].trim());
88
+ continue;
89
+ }
90
+ if (!GROUP_DIRECTIVES.test(line))
91
+ continue;
92
+ const [name, ...rest] = line.split(':');
93
+ const directive = name.trim().toLowerCase();
94
+ const value = rest.join(':').trim();
95
+ if (current !== null)
96
+ groupClosed = true;
97
+ switch (directive) {
98
+ case 'disallow':
99
+ current?.disallow.push(value);
100
+ break;
101
+ case 'allow':
102
+ current?.allow.push(value);
103
+ break;
104
+ case 'crawl-delay':
105
+ if (current)
106
+ current.crawlDelay = value;
107
+ break;
108
+ case 'content-signal':
109
+ if (current)
110
+ current.contentSignals.push(value);
111
+ else
112
+ result.orphanContentSignals.push(value);
113
+ break;
114
+ case 'content-usage':
115
+ if (current)
116
+ current.contentUsage.push(value);
117
+ else
118
+ result.orphanContentUsage.push(value);
119
+ break;
120
+ case 'license':
121
+ // RSL §4.4.1: a License inside a group scopes to that group; before any
122
+ // group it applies site-wide.
123
+ if (current)
124
+ current.licenses.push(value);
125
+ else
126
+ result.licenses.push(value);
127
+ break;
128
+ default:
129
+ break;
130
+ }
131
+ }
132
+ return result;
133
+ }
134
+ /**
135
+ * Flatten parsed groups into one entry per User-agent token, preserving the
136
+ * shape the 3.x checks were written against.
137
+ *
138
+ * A bot named in several groups is merged: `disallowed` is true when any group
139
+ * fully blocks it. RFC 9309 says a crawler picks the most specific matching
140
+ * group, but robots.txt files that name the same token twice are almost always
141
+ * a mistake, so merging surfaces the restriction rather than hiding it.
142
+ */
143
+ export function toBotEntries(robots) {
144
+ const byName = new Map();
145
+ for (const group of robots.groups) {
146
+ const fullBlock = group.disallow.some((p) => p === '/');
147
+ const anyDisallow = group.disallow.some((p) => p !== '');
148
+ const anyAllow = group.allow.length > 0;
149
+ for (const name of group.userAgents) {
150
+ const existing = byName.get(name);
151
+ if (existing) {
152
+ existing.disallowed ||= fullBlock;
153
+ existing.hasRestrictions ||= anyDisallow;
154
+ existing.hasAllow ||= anyAllow;
155
+ continue;
156
+ }
157
+ byName.set(name, {
158
+ name,
159
+ disallowed: fullBlock,
160
+ hasRestrictions: anyDisallow,
161
+ hasAllow: anyAllow,
162
+ });
163
+ }
164
+ }
165
+ return [...byName.values()];
166
+ }
167
+ /** Parse text straight into bot entries. Convenience for checks that need nothing else. */
168
+ export function parseUserAgents(text) {
169
+ return toBotEntries(parseRobotsTxt(text));
170
+ }
171
+ /** Every RSL `License:` value in the document, group-scoped ones included. */
172
+ export function collectLicenses(robots) {
173
+ return [...robots.licenses, ...robots.groups.flatMap((g) => g.licenses)];
174
+ }
175
+ /**
176
+ * Whether robots.txt expresses the intent to block a crawler: an explicit full
177
+ * `Disallow: /` for it, or a wildcard full block with no explicit entry.
178
+ */
179
+ export function intentBlocked(entries, crawler) {
180
+ const explicit = entries.find((e) => e.name.toLowerCase() === crawler.toLowerCase());
181
+ if (explicit)
182
+ return explicit.disallowed;
183
+ return entries.find((e) => e.name === '*')?.disallowed ?? false;
184
+ }
185
+ /**
186
+ * Parse one `Content-Signal:` value.
187
+ *
188
+ * Accepts the three boolean signals (`search`, `ai-input`, `ai-train` with
189
+ * `yes`/`no`) and the `use` field Cloudflare added on 2026-07-01, whose values
190
+ * are `immediate`, `reference` (the stated default) and `full`. Cloudflare's
191
+ * managed robots.txt writes `Content-signal:` with a lowercase `s` and a space
192
+ * after each comma, while the launch blog uses `Content-Signal:` without
193
+ * spaces; both parse identically here.
194
+ */
195
+ export function parseContentSignalValue(raw) {
196
+ const result = { valid: [], malformed: [], unknown: [], invalidValue: [] };
197
+ for (const segment of raw.split(',')) {
198
+ const s = segment.trim();
199
+ if (!s)
200
+ continue;
201
+ const m = s.match(/^([a-z][a-z-]*)\s*=\s*([a-z-]+)$/i);
202
+ if (!m) {
203
+ result.malformed.push(s);
204
+ continue;
205
+ }
206
+ const name = m[1].toLowerCase();
207
+ const value = m[2].toLowerCase();
208
+ if (name === 'use') {
209
+ if (CONTENT_SIGNAL_USE_VALUES.includes(value))
210
+ result.valid.push(`use=${value}`);
211
+ else
212
+ result.invalidValue.push(s);
213
+ continue;
214
+ }
215
+ if (!CONTENT_SIGNALS.includes(name)) {
216
+ result.unknown.push(s);
217
+ continue;
218
+ }
219
+ if (value !== 'yes' && value !== 'no') {
220
+ result.invalidValue.push(s);
221
+ continue;
222
+ }
223
+ result.valid.push(`${name}=${value}`);
224
+ }
225
+ return result;
226
+ }
227
+ /** Tokens that belong to a *different* usage vocabulary, flagged when seen under Content-Usage. */
228
+ const FOREIGN_TOKENS = new Set(['ai-train', 'ai-input', 'ai-index', 'ai-all', 'use']);
229
+ /**
230
+ * Parse one `Content-Usage:` value per draft-ietf-aipref-attach-05 §3:
231
+ * an optional path pattern, whitespace, then a Structured Fields dictionary.
232
+ */
233
+ export function parseContentUsageValue(raw) {
234
+ const result = {
235
+ path: null,
236
+ valid: [],
237
+ unknown: [],
238
+ invalidValue: [],
239
+ malformed: [],
240
+ crossVocabulary: [],
241
+ };
242
+ let body = raw.trim();
243
+ // A leading path pattern is present when the first whitespace-delimited token
244
+ // starts with `/` (or `*`, for a bare wildcard pattern).
245
+ const firstSpace = body.search(/\s/);
246
+ if (firstSpace > 0) {
247
+ const head = body.slice(0, firstSpace);
248
+ if (head.startsWith('/') || head.startsWith('*')) {
249
+ result.path = head;
250
+ body = body.slice(firstSpace).trim();
251
+ }
252
+ }
253
+ const dict = parseDictionary(body);
254
+ result.malformed.push(...dict.malformed);
255
+ for (const member of dict.members) {
256
+ if (FOREIGN_TOKENS.has(member.key)) {
257
+ result.crossVocabulary.push(member.raw);
258
+ continue;
259
+ }
260
+ if (!AIPREF_TOKENS.includes(member.key)) {
261
+ result.unknown.push(member.raw);
262
+ continue;
263
+ }
264
+ if (!AIPREF_VALUES.includes(member.value.toLowerCase())) {
265
+ result.invalidValue.push(member.raw);
266
+ continue;
267
+ }
268
+ result.valid.push(`${member.key}=${member.value.toLowerCase()}`);
269
+ }
270
+ return result;
271
+ }
272
+ /* ── RSL License directives ─────────────────────────────────────────────── */
273
+ /** Extract every `License:` directive value (RSL 1.0 §4.4.1). */
274
+ export function parseRobotsLicenseDirectives(text) {
275
+ return collectLicenses(parseRobotsTxt(text));
276
+ }
277
+ //# sourceMappingURL=robots-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots-parser.js","sourceRoot":"","sources":["../../src/checks/robots-parser.ts"],"names":[],"mappings":"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"}
@@ -1,24 +1,6 @@
1
1
  import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
2
  export declare const meta: CheckMeta;
3
- export interface BotEntry {
4
- name: string;
5
- disallowed: boolean;
6
- hasRestrictions: boolean;
7
- hasAllow: boolean;
8
- }
3
+ export { parseUserAgents, intentBlocked } from './robots-parser.js';
4
+ export type { BotEntry } from './robots-parser.js';
9
5
  export default function check(ctx: CheckContext): Promise<CheckResult>;
10
- export declare function parseUserAgents(text: string): BotEntry[];
11
- interface ContentSignalDecl {
12
- /** User-agent names of the group this declaration belongs to (empty = outside any group). */
13
- userAgents: string[];
14
- /** Raw directive value, e.g. "search=yes, ai-train=no". */
15
- raw: string;
16
- }
17
- /**
18
- * Extract `Content-Signal:` declarations and the User-agent group each belongs to.
19
- * Mirrors the grouping rules of `parseUserAgents`: consecutive User-agent lines form
20
- * one group; any directive line closes the group.
21
- */
22
- export declare function parseContentSignalDecls(text: string): ContentSignalDecl[];
23
- export {};
24
6
  //# sourceMappingURL=robots-txt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"robots-txt.d.ts","sourceRoot":"","sources":["../../src/checks/robots-txt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkI3E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAwCxD;AAID,UAAU,iBAAiB;IACzB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAgCzE"}
1
+ {"version":3,"file":"robots-txt.d.ts","sourceRoot":"","sources":["../../src/checks/robots-txt.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAUjF,eAAO,MAAM,IAAI,EAAE,SAIlB,CAAC;AAIF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACpE,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAqJ3E"}