@forumulate/cli 0.8.0 → 0.10.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 (286) hide show
  1. package/README.md +11 -3
  2. package/dist/api/args.d.ts.map +1 -1
  3. package/dist/api/args.js +1 -0
  4. package/dist/api/args.js.map +1 -1
  5. package/dist/api/command.d.ts +1 -1
  6. package/dist/api/command.d.ts.map +1 -1
  7. package/dist/api/command.js +86 -11
  8. package/dist/api/command.js.map +1 -1
  9. package/dist/api/http.d.ts +8 -0
  10. package/dist/api/http.d.ts.map +1 -1
  11. package/dist/api/http.js +3 -2
  12. package/dist/api/http.js.map +1 -1
  13. package/dist/api/live-spec.d.ts +48 -0
  14. package/dist/api/live-spec.d.ts.map +1 -0
  15. package/dist/api/live-spec.js +72 -0
  16. package/dist/api/live-spec.js.map +1 -0
  17. package/dist/api/operations.json +1 -1
  18. package/dist/api/request.d.ts.map +1 -1
  19. package/dist/api/request.js +25 -1
  20. package/dist/api/request.js.map +1 -1
  21. package/dist/api/send.d.ts +10 -1
  22. package/dist/api/send.d.ts.map +1 -1
  23. package/dist/api/send.js +14 -3
  24. package/dist/api/send.js.map +1 -1
  25. package/dist/api/slim.d.ts +14 -0
  26. package/dist/api/slim.d.ts.map +1 -0
  27. package/dist/api/slim.js +174 -0
  28. package/dist/api/slim.js.map +1 -0
  29. package/dist/cache-command.d.ts +12 -0
  30. package/dist/cache-command.d.ts.map +1 -0
  31. package/dist/cache-command.js +93 -0
  32. package/dist/cache-command.js.map +1 -0
  33. package/dist/check/command.d.ts +48 -0
  34. package/dist/check/command.d.ts.map +1 -0
  35. package/dist/check/command.js +256 -0
  36. package/dist/check/command.js.map +1 -0
  37. package/dist/check/external.d.ts +66 -0
  38. package/dist/check/external.d.ts.map +1 -0
  39. package/dist/check/external.js +177 -0
  40. package/dist/check/external.js.map +1 -0
  41. package/dist/check/markdown-links.d.ts +38 -0
  42. package/dist/check/markdown-links.d.ts.map +1 -0
  43. package/dist/check/markdown-links.js +166 -0
  44. package/dist/check/markdown-links.js.map +1 -0
  45. package/dist/cli.js +42 -7
  46. package/dist/cli.js.map +1 -1
  47. package/dist/commands/completion.d.ts.map +1 -1
  48. package/dist/commands/completion.js +17 -0
  49. package/dist/commands/completion.js.map +1 -1
  50. package/dist/commands/context.d.ts.map +1 -1
  51. package/dist/commands/context.js +6 -2
  52. package/dist/commands/context.js.map +1 -1
  53. package/dist/commands/groups-api.d.ts.map +1 -1
  54. package/dist/commands/groups-api.js +20 -2
  55. package/dist/commands/groups-api.js.map +1 -1
  56. package/dist/commands/groups-docs.d.ts.map +1 -1
  57. package/dist/commands/groups-docs.js +8 -2
  58. package/dist/commands/groups-docs.js.map +1 -1
  59. package/dist/commands/groups-jobs.d.ts +10 -0
  60. package/dist/commands/groups-jobs.d.ts.map +1 -0
  61. package/dist/commands/groups-jobs.js +89 -0
  62. package/dist/commands/groups-jobs.js.map +1 -0
  63. package/dist/commands/groups-org.d.ts.map +1 -1
  64. package/dist/commands/groups-org.js +59 -2
  65. package/dist/commands/groups-org.js.map +1 -1
  66. package/dist/commands/groups-site.d.ts.map +1 -1
  67. package/dist/commands/groups-site.js +47 -10
  68. package/dist/commands/groups-site.js.map +1 -1
  69. package/dist/commands/groups-spaces.d.ts.map +1 -1
  70. package/dist/commands/groups-spaces.js +11 -5
  71. package/dist/commands/groups-spaces.js.map +1 -1
  72. package/dist/commands/groups-types.d.ts.map +1 -1
  73. package/dist/commands/groups-types.js +74 -0
  74. package/dist/commands/groups-types.js.map +1 -1
  75. package/dist/commands/groups.d.ts.map +1 -1
  76. package/dist/commands/groups.js +2 -0
  77. package/dist/commands/groups.js.map +1 -1
  78. package/dist/commands/index.d.ts +9 -0
  79. package/dist/commands/index.d.ts.map +1 -1
  80. package/dist/commands/index.js +18 -3
  81. package/dist/commands/index.js.map +1 -1
  82. package/dist/commands/job-wait.d.ts +64 -0
  83. package/dist/commands/job-wait.d.ts.map +1 -0
  84. package/dist/commands/job-wait.js +91 -0
  85. package/dist/commands/job-wait.js.map +1 -0
  86. package/dist/commands/resource.d.ts +19 -0
  87. package/dist/commands/resource.d.ts.map +1 -1
  88. package/dist/commands/resource.js +65 -3
  89. package/dist/commands/resource.js.map +1 -1
  90. package/dist/content/library.d.ts +8 -0
  91. package/dist/content/library.d.ts.map +1 -1
  92. package/dist/content/library.js +10 -2
  93. package/dist/content/library.js.map +1 -1
  94. package/dist/credentials.d.ts +43 -4
  95. package/dist/credentials.d.ts.map +1 -1
  96. package/dist/credentials.js +67 -4
  97. package/dist/credentials.js.map +1 -1
  98. package/dist/dev/command.d.ts +41 -0
  99. package/dist/dev/command.d.ts.map +1 -0
  100. package/dist/dev/command.js +158 -0
  101. package/dist/dev/command.js.map +1 -0
  102. package/dist/doctor/address-checks.d.ts +56 -0
  103. package/dist/doctor/address-checks.d.ts.map +1 -0
  104. package/dist/doctor/address-checks.js +183 -0
  105. package/dist/doctor/address-checks.js.map +1 -0
  106. package/dist/doctor/boilerplate.d.ts +33 -0
  107. package/dist/doctor/boilerplate.d.ts.map +1 -0
  108. package/dist/doctor/boilerplate.js +78 -0
  109. package/dist/doctor/boilerplate.js.map +1 -0
  110. package/dist/doctor/command.d.ts +18 -0
  111. package/dist/doctor/command.d.ts.map +1 -0
  112. package/dist/doctor/command.js +234 -0
  113. package/dist/doctor/command.js.map +1 -0
  114. package/dist/doctor/crawl.d.ts +49 -0
  115. package/dist/doctor/crawl.d.ts.map +1 -0
  116. package/dist/doctor/crawl.js +210 -0
  117. package/dist/doctor/crawl.js.map +1 -0
  118. package/dist/doctor/extended.d.ts +52 -0
  119. package/dist/doctor/extended.d.ts.map +1 -0
  120. package/dist/doctor/extended.js +150 -0
  121. package/dist/doctor/extended.js.map +1 -0
  122. package/dist/doctor/page-checks.d.ts +42 -0
  123. package/dist/doctor/page-checks.d.ts.map +1 -0
  124. package/dist/doctor/page-checks.js +200 -0
  125. package/dist/doctor/page-checks.js.map +1 -0
  126. package/dist/doctor/probe.d.ts +63 -0
  127. package/dist/doctor/probe.d.ts.map +1 -0
  128. package/dist/doctor/probe.js +170 -0
  129. package/dist/doctor/probe.js.map +1 -0
  130. package/dist/doctor/reader-auth-atlas.d.ts +18 -0
  131. package/dist/doctor/reader-auth-atlas.d.ts.map +1 -0
  132. package/dist/doctor/reader-auth-atlas.js +50 -0
  133. package/dist/doctor/reader-auth-atlas.js.map +1 -0
  134. package/dist/doctor/robots-params.d.ts +36 -0
  135. package/dist/doctor/robots-params.d.ts.map +1 -0
  136. package/dist/doctor/robots-params.js +97 -0
  137. package/dist/doctor/robots-params.js.map +1 -0
  138. package/dist/doctor/site.d.ts +42 -0
  139. package/dist/doctor/site.d.ts.map +1 -0
  140. package/dist/doctor/site.js +82 -0
  141. package/dist/doctor/site.js.map +1 -0
  142. package/dist/doctor.d.ts +21 -0
  143. package/dist/doctor.d.ts.map +1 -1
  144. package/dist/doctor.js +94 -3
  145. package/dist/doctor.js.map +1 -1
  146. package/dist/exit-codes.d.ts +40 -0
  147. package/dist/exit-codes.d.ts.map +1 -0
  148. package/dist/exit-codes.js +66 -0
  149. package/dist/exit-codes.js.map +1 -0
  150. package/dist/help-commands.d.ts +13 -0
  151. package/dist/help-commands.d.ts.map +1 -0
  152. package/dist/help-commands.js +215 -0
  153. package/dist/help-commands.js.map +1 -0
  154. package/dist/help.d.ts +1 -1
  155. package/dist/help.d.ts.map +1 -1
  156. package/dist/help.js +74 -11
  157. package/dist/help.js.map +1 -1
  158. package/dist/io.d.ts +33 -0
  159. package/dist/io.d.ts.map +1 -0
  160. package/dist/io.js +81 -0
  161. package/dist/io.js.map +1 -0
  162. package/dist/preview-comment.d.ts +20 -0
  163. package/dist/preview-comment.d.ts.map +1 -0
  164. package/dist/preview-comment.js +88 -0
  165. package/dist/preview-comment.js.map +1 -0
  166. package/dist/publish/about.d.ts +23 -0
  167. package/dist/publish/about.d.ts.map +1 -0
  168. package/dist/publish/about.js +66 -0
  169. package/dist/publish/about.js.map +1 -0
  170. package/dist/publish/api.d.ts +30 -12
  171. package/dist/publish/api.d.ts.map +1 -1
  172. package/dist/publish/api.js +62 -10
  173. package/dist/publish/api.js.map +1 -1
  174. package/dist/publish/client.d.ts +19 -0
  175. package/dist/publish/client.d.ts.map +1 -0
  176. package/dist/publish/client.js +3 -0
  177. package/dist/publish/client.js.map +1 -0
  178. package/dist/publish/command.d.ts +51 -2
  179. package/dist/publish/command.d.ts.map +1 -1
  180. package/dist/publish/command.js +157 -17
  181. package/dist/publish/command.js.map +1 -1
  182. package/dist/publish/context.d.ts +12 -1
  183. package/dist/publish/context.d.ts.map +1 -1
  184. package/dist/publish/context.js.map +1 -1
  185. package/dist/publish/diff.d.ts +21 -0
  186. package/dist/publish/diff.d.ts.map +1 -0
  187. package/dist/publish/diff.js +96 -0
  188. package/dist/publish/diff.js.map +1 -0
  189. package/dist/publish/docs-apply.d.ts +8 -1
  190. package/dist/publish/docs-apply.d.ts.map +1 -1
  191. package/dist/publish/docs-apply.js +49 -10
  192. package/dist/publish/docs-apply.js.map +1 -1
  193. package/dist/publish/docs-plan.d.ts +16 -3
  194. package/dist/publish/docs-plan.d.ts.map +1 -1
  195. package/dist/publish/docs-plan.js +57 -6
  196. package/dist/publish/docs-plan.js.map +1 -1
  197. package/dist/publish/extras.d.ts +10 -0
  198. package/dist/publish/extras.d.ts.map +1 -1
  199. package/dist/publish/extras.js +54 -2
  200. package/dist/publish/extras.js.map +1 -1
  201. package/dist/publish/frontmatter.d.ts +1 -1
  202. package/dist/publish/frontmatter.d.ts.map +1 -1
  203. package/dist/publish/frontmatter.js +1 -0
  204. package/dist/publish/frontmatter.js.map +1 -1
  205. package/dist/publish/index.d.ts +12 -0
  206. package/dist/publish/index.d.ts.map +1 -0
  207. package/dist/publish/index.js +17 -0
  208. package/dist/publish/index.js.map +1 -0
  209. package/dist/publish/manifest.d.ts.map +1 -1
  210. package/dist/publish/manifest.js +48 -3
  211. package/dist/publish/manifest.js.map +1 -1
  212. package/dist/publish/names.d.ts +28 -0
  213. package/dist/publish/names.d.ts.map +1 -0
  214. package/dist/publish/names.js +80 -0
  215. package/dist/publish/names.js.map +1 -0
  216. package/dist/publish/posts.d.ts.map +1 -1
  217. package/dist/publish/posts.js +46 -13
  218. package/dist/publish/posts.js.map +1 -1
  219. package/dist/publish/preview.d.ts +56 -0
  220. package/dist/publish/preview.d.ts.map +1 -0
  221. package/dist/publish/preview.js +133 -0
  222. package/dist/publish/preview.js.map +1 -0
  223. package/dist/publish/redirects.d.ts +13 -0
  224. package/dist/publish/redirects.d.ts.map +1 -0
  225. package/dist/publish/redirects.js +154 -0
  226. package/dist/publish/redirects.js.map +1 -0
  227. package/dist/publish/reserved.d.ts +49 -0
  228. package/dist/publish/reserved.d.ts.map +1 -0
  229. package/dist/publish/reserved.js +118 -0
  230. package/dist/publish/reserved.js.map +1 -0
  231. package/dist/publish/rewrite.d.ts +12 -0
  232. package/dist/publish/rewrite.d.ts.map +1 -1
  233. package/dist/publish/rewrite.js +22 -0
  234. package/dist/publish/rewrite.js.map +1 -1
  235. package/dist/publish/scan-docs.d.ts +10 -0
  236. package/dist/publish/scan-docs.d.ts.map +1 -0
  237. package/dist/publish/scan-docs.js +160 -0
  238. package/dist/publish/scan-docs.js.map +1 -0
  239. package/dist/publish/scan.d.ts +21 -17
  240. package/dist/publish/scan.d.ts.map +1 -1
  241. package/dist/publish/scan.js +99 -232
  242. package/dist/publish/scan.js.map +1 -1
  243. package/dist/publish/slots.d.ts +39 -0
  244. package/dist/publish/slots.d.ts.map +1 -0
  245. package/dist/publish/slots.js +64 -0
  246. package/dist/publish/slots.js.map +1 -0
  247. package/dist/publish/studio-edits.d.ts +25 -0
  248. package/dist/publish/studio-edits.d.ts.map +1 -0
  249. package/dist/publish/studio-edits.js +53 -0
  250. package/dist/publish/studio-edits.js.map +1 -0
  251. package/dist/publish/tags.d.ts +9 -0
  252. package/dist/publish/tags.d.ts.map +1 -0
  253. package/dist/publish/tags.js +194 -0
  254. package/dist/publish/tags.js.map +1 -0
  255. package/dist/publish/types.d.ts +84 -1
  256. package/dist/publish/types.d.ts.map +1 -1
  257. package/dist/publish/types.js +0 -10
  258. package/dist/publish/types.js.map +1 -1
  259. package/dist/publish-command.d.ts +55 -0
  260. package/dist/publish-command.d.ts.map +1 -0
  261. package/dist/publish-command.js +197 -0
  262. package/dist/publish-command.js.map +1 -0
  263. package/dist/run.d.ts +3 -10
  264. package/dist/run.d.ts.map +1 -1
  265. package/dist/run.js +171 -112
  266. package/dist/run.js.map +1 -1
  267. package/dist/translations/target.d.ts.map +1 -1
  268. package/dist/translations/target.js +2 -2
  269. package/dist/translations/target.js.map +1 -1
  270. package/dist/validate.d.ts +39 -0
  271. package/dist/validate.d.ts.map +1 -0
  272. package/dist/validate.js +166 -0
  273. package/dist/validate.js.map +1 -0
  274. package/dist/version.d.ts +8 -0
  275. package/dist/version.d.ts.map +1 -0
  276. package/dist/version.js +11 -0
  277. package/dist/version.js.map +1 -0
  278. package/dist/whoami.d.ts +41 -0
  279. package/dist/whoami.d.ts.map +1 -0
  280. package/dist/whoami.js +161 -0
  281. package/dist/whoami.js.map +1 -0
  282. package/package.json +2 -2
  283. package/dist/publish-dir.d.ts +0 -54
  284. package/dist/publish-dir.d.ts.map +0 -1
  285. package/dist/publish-dir.js +0 -119
  286. package/dist/publish-dir.js.map +0 -1
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sitemapsFromRobots = sitemapsFromRobots;
4
+ exports.readSitemaps = readSitemaps;
5
+ exports.sample = sample;
6
+ exports.sitemapCrawl = sitemapCrawl;
7
+ exports.groupOf = groupOf;
8
+ exports.cacheClass = cacheClass;
9
+ exports.cacheConsistency = cacheConsistency;
10
+ const probe_1 = require("./probe");
11
+ /**
12
+ * `sitemap-crawl`: every address the site hands a crawler, fetched.
13
+ *
14
+ * The sitemap is the list a search engine trusts most, so an entry that
15
+ * redirects, 404s, names a different canonical or sits on another host is a
16
+ * page the site is asking to have indexed and then refusing to be. A space root
17
+ * that 307s to its first page was listed as itself (FMU-B06); a platform copy
18
+ * that 308s elsewhere named itself canonical (FMU-B01). Each is invisible from
19
+ * the page a person happens to open, and obvious once every listed URL is asked.
20
+ *
21
+ * The pages fetched here are also the SAMPLE the other site-wide checks judge
22
+ * (cache headers, descriptions), so the crawl is done once.
23
+ */
24
+ /** How many sitemap documents (index included) one run will read. */
25
+ const SITEMAP_DOC_LIMIT = 25;
26
+ /** `Sitemap:` lines of robots.txt, else the conventional address. */
27
+ function sitemapsFromRobots(robots, origin) {
28
+ const named = [...robots.matchAll(/^\s*sitemap:\s*(\S+)/gim)].map((m) => m[1]);
29
+ return named.length ? named : [`${origin}/sitemap.xml`];
30
+ }
31
+ function locs(xml) {
32
+ return [...xml.matchAll(/<loc>\s*([^<\s]+)\s*<\/loc>/gi)].map((m) => m[1].replace(/&amp;/g, '&'));
33
+ }
34
+ /**
35
+ * Read sitemaps (following a sitemap index), returning the URL lists per
36
+ * document, so the sample can draw from every space rather than exhaust the
37
+ * first one: a site with a 900-page reference and a 4-page legal space would
38
+ * otherwise never have its legal pages looked at.
39
+ */
40
+ async function readSitemaps(get, start) {
41
+ const lists = [];
42
+ const problems = [];
43
+ const queue = [...new Set(start)];
44
+ const seen = new Set();
45
+ while (queue.length && seen.size < SITEMAP_DOC_LIMIT) {
46
+ const url = queue.shift();
47
+ if (seen.has(url))
48
+ continue;
49
+ seen.add(url);
50
+ const p = await get(url, { accept: 'application/xml,text/xml' });
51
+ if (!p.ok || p.status !== 200) {
52
+ problems.push(`${url} → ${(0, probe_1.describeProbe)(p)}`);
53
+ continue;
54
+ }
55
+ if (/<sitemapindex\b/i.test(p.text))
56
+ queue.push(...locs(p.text));
57
+ else
58
+ lists.push({ sitemap: url, urls: locs(p.text) });
59
+ }
60
+ return { lists, problems };
61
+ }
62
+ /** Up to `limit` URLs, round-robin across the sitemaps so every space is represented. */
63
+ function sample(lists, limit) {
64
+ const out = [];
65
+ const seen = new Set();
66
+ for (let i = 0; out.length < limit; i++) {
67
+ let any = false;
68
+ for (const l of lists) {
69
+ const u = l.urls[i];
70
+ if (u === undefined)
71
+ continue;
72
+ any = true;
73
+ if (!seen.has(u)) {
74
+ seen.add(u);
75
+ out.push(u);
76
+ if (out.length >= limit)
77
+ break;
78
+ }
79
+ }
80
+ if (!any)
81
+ break;
82
+ }
83
+ return out;
84
+ }
85
+ async function sitemapCrawl(get, origin, robots, limit) {
86
+ const title = 'Every URL in the sitemap answers 200, as itself';
87
+ const matters = 'A sitemap entry that redirects, 404s or names another canonical is a page the site asks to have indexed and then disowns; search engines lower their trust in the whole list.';
88
+ const { lists, problems } = await readSitemaps(get, sitemapsFromRobots(robots ?? '', origin));
89
+ if (lists.length === 0) {
90
+ return {
91
+ check: (0, probe_1.check)('sitemap-crawl', title, 'fail', problems.length ? `No sitemap could be read: ${(0, probe_1.some)(problems)}` : 'No sitemap found.', matters),
92
+ pages: [],
93
+ };
94
+ }
95
+ const total = lists.reduce((n, l) => n + l.urls.length, 0);
96
+ const urls = sample(lists, limit);
97
+ const siteHost = (0, probe_1.hostOf)(origin);
98
+ const pages = await (0, probe_1.pool)(urls, 6, (u) => get(u, { accept: 'text/html' }));
99
+ const bad = [...problems];
100
+ for (const p of pages) {
101
+ if ((0, probe_1.hostOf)(p.url) !== siteHost) {
102
+ bad.push(`${p.url} is on another host than the sitemap (${siteHost})`);
103
+ continue;
104
+ }
105
+ if (!p.ok) {
106
+ bad.push(`${p.url} → ${p.error}`);
107
+ continue;
108
+ }
109
+ if (p.status >= 300 && p.status < 400) {
110
+ bad.push(`${p.url} → ${p.status} ${p.headers.get('location') ?? ''} (list the final URL)`);
111
+ continue;
112
+ }
113
+ if (p.status !== 200) {
114
+ bad.push(`${p.url} → ${p.status}`);
115
+ continue;
116
+ }
117
+ const canonical = (0, probe_1.canonicalOf)(p.text, p.url);
118
+ if (canonical && !(0, probe_1.sameUrl)(canonical, p.url))
119
+ bad.push(`${p.url} names canonical ${canonical}`);
120
+ }
121
+ const scope = `${pages.length} of ${total} listed URL${total === 1 ? '' : 's'} across ${lists.length} sitemap${lists.length === 1 ? '' : 's'}`;
122
+ return {
123
+ check: (0, probe_1.check)('sitemap-crawl', title, bad.length ? 'fail' : 'pass', bad.length
124
+ ? `${bad.length} problem(s) in ${scope}: ${(0, probe_1.some)(bad)}`
125
+ : `${scope}: all 200, all self-canonical.`, bad.length ? matters : ''),
126
+ pages,
127
+ };
128
+ }
129
+ /**
130
+ * The space a URL belongs to, for grouping: its first path segment, which is
131
+ * where a path-mounted space lives (`/docs`, `/legal`). Pages at the root of a
132
+ * site domain group together under `/`. Coarse, and that is fine — a
133
+ * difference between two spaces is a choice; a difference inside one is what
134
+ * this is looking for.
135
+ */
136
+ function groupOf(url) {
137
+ try {
138
+ const u = new URL(url);
139
+ const segs = u.pathname.split('/').filter(Boolean);
140
+ // A short reader prefix followed by owner and space (`/p/<org>/<space>/…`)
141
+ // is how a multi-tenant host addresses a space; grouping by `/p` alone
142
+ // would compare every tenant's pages with every other's.
143
+ if (segs.length >= 4 && segs[0].length <= 3)
144
+ return `${u.host}/${segs.slice(0, 3).join('/')}`;
145
+ return `${u.host}/${segs[0] ?? ''}`;
146
+ }
147
+ catch {
148
+ return url;
149
+ }
150
+ }
151
+ /** `public` (a shared cache may keep it) or `private` (it may not), by the directives that decide it. */
152
+ function cacheClass(cc) {
153
+ if (!cc)
154
+ return 'none';
155
+ if (/\b(?:private|no-store)\b/i.test(cc))
156
+ return 'private';
157
+ if (/\b(?:public|s-maxage)\b/i.test(cc))
158
+ return 'public';
159
+ return 'private';
160
+ }
161
+ /** Headers a site may send to say a page is uncached on purpose (and why). */
162
+ const REASON_HEADERS = ['x-forumulate-cache-reason', 'x-cache-reason', 'x-cache-control-reason'];
163
+ /**
164
+ * `cache-consistency`: the pages of one space are cached the same way.
165
+ *
166
+ * Every legal document answered `private, no-cache, no-store` to a reader with
167
+ * no cookie at all, while the legal index beside it was `public, s-maxage=10`
168
+ * (FMU-B05). Neither header is wrong on its own; the difference is the defect —
169
+ * either something is gated and should say so, or a code path forgot the
170
+ * public header and every reader pays a full origin render. A page that sends
171
+ * a reason header is taken at its word.
172
+ */
173
+ function cacheConsistency(pages) {
174
+ const title = 'Pages within a space are cached alike';
175
+ const groups = new Map();
176
+ for (const p of pages) {
177
+ if (!p.ok || p.status !== 200)
178
+ continue;
179
+ if (REASON_HEADERS.some((h) => p.headers.get(h)))
180
+ continue;
181
+ const cc = p.headers.get('cache-control');
182
+ const g = groupOf(p.url);
183
+ groups.set(g, [
184
+ ...(groups.get(g) ?? []),
185
+ { url: p.url, cls: cacheClass(cc), cc: cc ?? '(none)' },
186
+ ]);
187
+ }
188
+ if (groups.size === 0)
189
+ return (0, probe_1.check)('cache-consistency', title, 'skip', 'No sampled pages answered 200.', '');
190
+ const odd = [];
191
+ for (const [g, rows] of groups) {
192
+ const classes = [...new Set(rows.map((r) => r.cls))];
193
+ if (classes.length < 2)
194
+ continue;
195
+ // Every side of the split is named. Which side is the bug is the site's
196
+ // call (usually the private one — a published page has no reason to be),
197
+ // and a "majority" of three legal documents is evidence of nothing.
198
+ const sides = classes.map((cls) => {
199
+ const of = rows.filter((r) => r.cls === cls);
200
+ return `${of.length} ${cls} ("${of[0].cc}": ${(0, probe_1.some)(of.map((r) => r.url), 3)})`;
201
+ });
202
+ odd.push(`${g}: ${sides.join(' vs ')}`);
203
+ }
204
+ return (0, probe_1.check)('cache-consistency', title, odd.length ? 'fail' : 'pass', odd.length
205
+ ? (0, probe_1.some)(odd)
206
+ : `${[...groups.values()].reduce((n, r) => n + r.length, 0)} pages in ${groups.size} space(s), one rule each.`, odd.length
207
+ ? 'A published page answering no-store to an anonymous reader is rendered at the origin for every visit. If it is gated on purpose, say so with an x-forumulate-cache-reason header.'
208
+ : '');
209
+ }
210
+ //# sourceMappingURL=crawl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crawl.js","sourceRoot":"","sources":["../../src/doctor/crawl.ts"],"names":[],"mappings":";;AAqCA,gDAGC;AAcD,oCAqBC;AAGD,wBAkBC;AAED,oCA4DC;AASD,0BAYC;AAGD,gCAKC;AAeD,4CA0CC;AAnPD,mCAUiB;AAEjB;;;;;;;;;;;;GAYG;AAEH,qEAAqE;AACrE,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAQ7B,qEAAqE;AACrE,SAAgB,kBAAkB,CAAC,MAAc,EAAE,MAAc;IAC/D,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IAChF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,cAAc,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAClE,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAChC,GAAQ,EACR,KAAe;IAEf,MAAM,KAAK,GAA0C,EAAE,CAAC;IACxD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,GAAG,iBAAiB,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9C,SAAS;QACX,CAAC;QACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;;YAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,yFAAyF;AACzF,SAAgB,MAAM,CAAC,KAA2B,EAAE,KAAa;IAC/D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,SAAS;gBAAE,SAAS;YAC9B,GAAG,GAAG,IAAI,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACZ,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK;oBAAE,MAAM;YACjC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,GAAG;YAAE,MAAM;IAClB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,GAAQ,EACR,MAAc,EACd,MAA0B,EAC1B,KAAa;IAEb,MAAM,KAAK,GAAG,iDAAiD,CAAC;IAChE,MAAM,OAAO,GACX,+KAA+K,CAAC;IAClL,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,kBAAkB,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9F,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,KAAK,EAAE,IAAA,aAAK,EACV,eAAe,EACf,KAAK,EACL,MAAM,EACN,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,6BAA6B,IAAA,YAAI,EAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,EACrF,OAAO,CACR;YACD,KAAK,EAAE,EAAE;SACV,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAA,cAAM,EAAC,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,IAAA,YAAI,EAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAa,CAAC,GAAG,QAAQ,CAAC,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,IAAA,cAAM,EAAC,CAAC,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,yCAAyC,QAAQ,GAAG,CAAC,CAAC;YACvE,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACV,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;YAC3F,SAAS;QACX,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACrB,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACnC,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,IAAA,mBAAW,EAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,SAAS,IAAI,CAAC,IAAA,eAAO,EAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,oBAAoB,SAAS,EAAE,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,MAAM,OAAO,KAAK,cAAc,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,WAAW,KAAK,CAAC,MAAM,WAAW,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC/I,OAAO;QACL,KAAK,EAAE,IAAA,aAAK,EACV,eAAe,EACf,KAAK,EACL,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC5B,GAAG,CAAC,MAAM;YACR,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,kBAAkB,KAAK,KAAK,IAAA,YAAI,EAAC,GAAG,CAAC,EAAE;YACtD,CAAC,CAAC,GAAG,KAAK,gCAAgC,EAC5C,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAC1B;QACD,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,OAAO,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnD,2EAA2E;QAC3E,uEAAuE;QACvE,yDAAyD;QACzD,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAE,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/F,OAAO,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,yGAAyG;AACzG,SAAgB,UAAU,CAAC,EAAiB;IAC1C,IAAI,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IACvB,IAAI,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,IAAI,0BAA0B,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,MAAM,cAAc,GAAG,CAAC,2BAA2B,EAAE,gBAAgB,EAAE,wBAAwB,CAAC,CAAC;AAEjG;;;;;;;;;GASG;AACH,SAAgB,gBAAgB,CAAC,KAAc;IAC7C,MAAM,KAAK,GAAG,uCAAuC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsD,CAAC;IAC7E,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG;YAAE,SAAS;QACxC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,SAAS;QAC3D,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;YACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACxB,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,QAAQ,EAAE;SACxD,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QACnB,OAAO,IAAA,aAAK,EAAC,mBAAmB,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,EAAE,EAAE,CAAC,CAAC;IACzF,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACjC,wEAAwE;QACxE,yEAAyE;QACzE,oEAAoE;QACpE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAChC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAC7C,OAAO,GAAG,EAAE,CAAC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,CAAE,CAAC,EAAE,MAAM,IAAA,YAAI,EACjD,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EACpB,CAAC,CACF,GAAG,CAAC;QACP,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAA,aAAK,EACV,mBAAmB,EACnB,KAAK,EACL,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC5B,GAAG,CAAC,MAAM;QACR,CAAC,CAAC,IAAA,YAAI,EAAC,GAAG,CAAC;QACX,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa,MAAM,CAAC,IAAI,2BAA2B,EAChH,GAAG,CAAC,MAAM;QACR,CAAC,CAAC,mLAAmL;QACrL,CAAC,CAAC,EAAE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { Check } from '../conformance';
2
+ import { type AddressSet } from './address-checks';
3
+ import { type Get } from './probe';
4
+ /**
5
+ * The site-wide checks added for FMU-D14, run after the single-page ones.
6
+ *
7
+ * Every one of them is a defect an integrator found on a live site after
8
+ * readers did, and every one is judged from the outside, by HTTP alone, so the
9
+ * report is the same whether it is pointed at our platform, a staging mount or
10
+ * any other docs host. The only thing a check knows about "the platform" is
11
+ * its hostname, which is an input (`--platform-host`, else the host of
12
+ * FORUMULATE_URL, else forumulate.com) — never a constant in the logic.
13
+ */
14
+ /** Every check id this file can produce, in report order. `--only` validates against it. */
15
+ export declare const EXTENDED_CHECK_IDS: readonly ["canonical-both-addresses", "sitemap-crawl", "cache-consistency", "root-redirect", "meta-description", "llms-txt", "favicon", "consent-tag", "white-label-leaks", "robots-params"];
16
+ export declare const DEFAULT_PLATFORM_HOST = "forumulate.com";
17
+ /** URLs one run fetches from the sitemaps; enough to see a pattern, few enough for CI. */
18
+ export declare const DEFAULT_SAMPLE_LIMIT = 60;
19
+ export interface ExtendedInput {
20
+ /** The page judged: where the asked-for address landed after redirects. */
21
+ url: string;
22
+ /** The address as given, before any redirect. */
23
+ requestedUrl?: string;
24
+ /** The page's HTML as an anonymous reader got it ('' when it did not answer). */
25
+ html: string;
26
+ /** robots.txt, when it answered 200. */
27
+ robots?: string;
28
+ get: Get;
29
+ platformHost: string;
30
+ /** The platform's API base (`https://forumulate.com/api`), for the primary-address lookup. */
31
+ platformApi?: string;
32
+ /** Other addresses of this page/space, from `--also` or `--site`. */
33
+ addressSets?: AddressSet[];
34
+ /** Space roots to check, from `--site`; derived from the URL otherwise. */
35
+ roots?: string[];
36
+ limit?: number;
37
+ /** Run only these ids (undefined: all). */
38
+ only?: ReadonlySet<string>;
39
+ }
40
+ /** The roots a URL's space is served at: the mount (first segment), or the platform copy's space root. */
41
+ export declare function deriveRoots(url: string, platformHost: string): string[];
42
+ /**
43
+ * The customer's address of a platform-hosted page, asked of the platform.
44
+ *
45
+ * Only for a URL on the platform host in the platform-copy shape: the public
46
+ * primary-domain lookup answers where the space's readers are sent, which is
47
+ * what both copies must name as canonical. Any failure is "unknown", and the
48
+ * check then compares the copies it has with each other.
49
+ */
50
+ export declare function discoverPrimary(get: Get, url: string, platformHost: string, platformApi: string | undefined): Promise<AddressSet | undefined>;
51
+ export declare function extendedChecks(input: ExtendedInput): Promise<Check[]>;
52
+ //# sourceMappingURL=extended.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extended.d.ts","sourceRoot":"","sources":["../../src/doctor/extended.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAiB,KAAK,GAAG,EAAc,MAAM,SAAS,CAAC;AAG9D;;;;;;;;;GASG;AAEH,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,8LAWrB,CAAC;AAEX,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AACtD,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC5B;AASD,0GAA0G;AAC1G,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CASvE;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAuBjC;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAiF3E"}
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_SAMPLE_LIMIT = exports.DEFAULT_PLATFORM_HOST = exports.EXTENDED_CHECK_IDS = void 0;
4
+ exports.deriveRoots = deriveRoots;
5
+ exports.discoverPrimary = discoverPrimary;
6
+ exports.extendedChecks = extendedChecks;
7
+ const address_checks_1 = require("./address-checks");
8
+ const crawl_1 = require("./crawl");
9
+ const page_checks_1 = require("./page-checks");
10
+ const probe_1 = require("./probe");
11
+ const robots_params_1 = require("./robots-params");
12
+ /**
13
+ * The site-wide checks added for FMU-D14, run after the single-page ones.
14
+ *
15
+ * Every one of them is a defect an integrator found on a live site after
16
+ * readers did, and every one is judged from the outside, by HTTP alone, so the
17
+ * report is the same whether it is pointed at our platform, a staging mount or
18
+ * any other docs host. The only thing a check knows about "the platform" is
19
+ * its hostname, which is an input (`--platform-host`, else the host of
20
+ * FORUMULATE_URL, else forumulate.com) — never a constant in the logic.
21
+ */
22
+ /** Every check id this file can produce, in report order. `--only` validates against it. */
23
+ exports.EXTENDED_CHECK_IDS = [
24
+ 'canonical-both-addresses',
25
+ 'sitemap-crawl',
26
+ 'cache-consistency',
27
+ 'root-redirect',
28
+ 'meta-description',
29
+ 'llms-txt',
30
+ 'favicon',
31
+ 'consent-tag',
32
+ 'white-label-leaks',
33
+ 'robots-params',
34
+ ];
35
+ exports.DEFAULT_PLATFORM_HOST = 'forumulate.com';
36
+ /** URLs one run fetches from the sitemaps; enough to see a pattern, few enough for CI. */
37
+ exports.DEFAULT_SAMPLE_LIMIT = 60;
38
+ /**
39
+ * A platform copy's address shape: `/<prefix>/<org>/<space>/<rest>`, where the
40
+ * prefix is a short reader route (`/p/`, `/b/`, `/f/` …). Read only on the
41
+ * platform host, where that shape is the platform's own convention.
42
+ */
43
+ const PLATFORM_COPY = /^\/([a-z]{1,3})\/([^/]+)\/([^/]+)(\/.*)?$/;
44
+ /** The roots a URL's space is served at: the mount (first segment), or the platform copy's space root. */
45
+ function deriveRoots(url, platformHost) {
46
+ const u = new URL(url);
47
+ const path = u.pathname.replace(/\/+$/, '');
48
+ if ((0, probe_1.hostOf)(url) === platformHost.toLowerCase()) {
49
+ const m = PLATFORM_COPY.exec(path);
50
+ if (m)
51
+ return [`${u.origin}/${m[1]}/${m[2]}/${m[3]}`];
52
+ }
53
+ const first = path.split('/').filter(Boolean)[0];
54
+ return [first ? `${u.origin}/${first}` : u.origin];
55
+ }
56
+ /**
57
+ * The customer's address of a platform-hosted page, asked of the platform.
58
+ *
59
+ * Only for a URL on the platform host in the platform-copy shape: the public
60
+ * primary-domain lookup answers where the space's readers are sent, which is
61
+ * what both copies must name as canonical. Any failure is "unknown", and the
62
+ * check then compares the copies it has with each other.
63
+ */
64
+ async function discoverPrimary(get, url, platformHost, platformApi) {
65
+ if (!platformApi || (0, probe_1.hostOf)(url) !== platformHost.toLowerCase())
66
+ return undefined;
67
+ const u = new URL(url);
68
+ const m = PLATFORM_COPY.exec(u.pathname.replace(/\/+$/, ''));
69
+ if (!m)
70
+ return undefined;
71
+ const q = new URLSearchParams({
72
+ org: decodeURIComponent(m[2]),
73
+ space: decodeURIComponent(m[3]),
74
+ });
75
+ const p = await get(`${platformApi.replace(/\/+$/, '')}/public/domains/primary?${q}`, {
76
+ accept: 'application/json',
77
+ });
78
+ if (!p.ok || p.status !== 200)
79
+ return undefined;
80
+ try {
81
+ const primary = JSON.parse(p.text).primary;
82
+ if (!primary?.origin)
83
+ return undefined;
84
+ const expected = `${primary.origin.replace(/\/+$/, '')}${primary.basePath ?? ''}${m[4] ?? ''}`;
85
+ return { expected, urls: [url, expected] };
86
+ }
87
+ catch {
88
+ return undefined;
89
+ }
90
+ }
91
+ async function extendedChecks(input) {
92
+ const want = (id) => !input.only || input.only.has(id);
93
+ const { get, url, html, platformHost } = input;
94
+ const origin = new URL(url).origin;
95
+ const roots = input.roots?.length
96
+ ? input.roots
97
+ : deriveRoots(input.requestedUrl ?? url, platformHost);
98
+ const out = [];
99
+ if (want('canonical-both-addresses')) {
100
+ const sets = [...(input.addressSets ?? [])];
101
+ if (sets.length === 0) {
102
+ // The address the user GAVE: a platform copy that redirects (the legal
103
+ // page went `/p/<org>/legal/<doc>` → `/legal/<org>/<doc>`) has lost the
104
+ // org/space shape by the time it lands.
105
+ const asked = input.requestedUrl ?? url;
106
+ const found = await discoverPrimary(get, asked, platformHost, input.platformApi);
107
+ if (found)
108
+ sets.push(found);
109
+ }
110
+ out.push(await (0, address_checks_1.canonicalBothAddresses)(get, sets));
111
+ }
112
+ // One crawl feeds three checks; it is skipped only when none of them is asked for.
113
+ let pages = [];
114
+ if (want('sitemap-crawl') || want('cache-consistency') || want('meta-description')) {
115
+ const crawl = await (0, crawl_1.sitemapCrawl)(get, origin, input.robots, input.limit ?? exports.DEFAULT_SAMPLE_LIMIT);
116
+ pages = crawl.pages;
117
+ if (want('sitemap-crawl'))
118
+ out.push(crawl.check);
119
+ }
120
+ if (want('cache-consistency'))
121
+ out.push((0, crawl_1.cacheConsistency)(pages));
122
+ if (want('root-redirect'))
123
+ out.push(await (0, page_checks_1.rootRedirect)(get, roots));
124
+ if (want('meta-description')) {
125
+ // The page that was asked about is judged too, even when no sitemap lists it.
126
+ const self = html
127
+ ? [{ ok: true, url, status: 200, headers: new Headers(), text: html }]
128
+ : [];
129
+ const listed = pages.some((p) => p.url === url);
130
+ out.push((0, page_checks_1.metaDescription)(listed ? pages : [...self, ...pages]));
131
+ }
132
+ if (want('llms-txt'))
133
+ out.push(await (0, page_checks_1.llmsTxt)(get, origin, roots.filter((r) => r !== origin), platformHost));
134
+ if (want('favicon')) {
135
+ out.push(html
136
+ ? await (0, page_checks_1.favicon)(get, url, html, roots.filter((r) => r !== origin))
137
+ : (0, probe_1.check)('favicon', 'The favicon resolves to an image', 'skip', 'No HTML to read.', ''));
138
+ }
139
+ if (want('consent-tag'))
140
+ out.push(html
141
+ ? (0, address_checks_1.consentTag)(html)
142
+ : (0, probe_1.check)('consent-tag', 'The consent banner is told the page language', 'skip', 'No HTML to read.', ''));
143
+ if (want('white-label-leaks'))
144
+ out.push(await (0, address_checks_1.whiteLabelLeaks)(get, url, html, platformHost));
145
+ // SEO §1: the Disallow lines for each mount's sorted / filtered copies.
146
+ if (want('robots-params'))
147
+ out.push((0, robots_params_1.robotsParams)(roots, origin, input.robots));
148
+ return out;
149
+ }
150
+ //# sourceMappingURL=extended.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extended.js","sourceRoot":"","sources":["../../src/doctor/extended.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { Check } from '../conformance';
2
+ import { type Get, type Probe } from './probe';
3
+ /**
4
+ * `root-redirect`: a space's root either renders or moves permanently, cheaply.
5
+ *
6
+ * `GET /docs` answered `307` with a 66 KB HTML body and a canonical naming
7
+ * `/docs` (FMU-B06). A 307 says "this is temporary, keep asking me", so a
8
+ * crawler keeps the root as the indexed URL and never settles on the page it
9
+ * lands on; the body is bytes every visitor downloads and throws away. A 301
10
+ * or 308 with an empty body, or the front page rendered in place, are both fine.
11
+ */
12
+ export declare function rootRedirect(get: Get, roots: string[]): Promise<Check>;
13
+ /**
14
+ * `meta-description`: every page says what it is, in words somebody wrote.
15
+ *
16
+ * Checked across the crawl sample, not just the page given, because the
17
+ * preset fallbacks live on the pages nobody opens while testing — a space
18
+ * index, a blog home, a generated reference landing (FMU-B08, FMU-B09).
19
+ */
20
+ export declare function metaDescription(pages: Probe[]): Check;
21
+ /**
22
+ * `favicon`: the icons the page and the host advertise are images.
23
+ *
24
+ * `GET /docs/favicon.ico` on a customer's domain answered a 404 with a 104 KB
25
+ * HTML page (FMU-B17). Browsers, feed readers and link unfurlers ask for these
26
+ * addresses on their own; a 100 KB error page per ask is load, and a missing
27
+ * icon is a blank tab. An asset-shaped path that is not there should be a tiny
28
+ * 404, not the site's whole not-found page.
29
+ */
30
+ export declare function favicon(get: Get, pageUrl: string, html: string, roots: string[]): Promise<Check>;
31
+ /** One llms.txt judged against the llmstxt.org shape. */
32
+ export declare function llmsProblems(text: string, url: string, platformHost?: string): string[];
33
+ /**
34
+ * `llms-txt`: the file an AI agent reads first exists and is shaped for one.
35
+ *
36
+ * The space's llms.txt opened with "Published documentation for API Docs.",
37
+ * listed pages in recent-edit order with no descriptions, and titled a clash
38
+ * "Authentication (ref-authentication)" (FMU-B16). An agent picks pages from
39
+ * this list by their descriptions; without them it fetches at random.
40
+ */
41
+ export declare function llmsTxt(get: Get, origin: string, roots: string[], platformHost?: string): Promise<Check>;
42
+ //# sourceMappingURL=page-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-checks.d.ts","sourceRoot":"","sources":["../../src/doctor/page-checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAUL,KAAK,GAAG,EACR,KAAK,KAAK,EACX,MAAM,SAAS,CAAC;AAKjB;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CA4C5E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,KAAK,CAuBrD;AAID;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,KAAK,CAAC,CAyChB;AAKD,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BvF;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,KAAK,CAAC,CA8BhB"}