pagetrace 0.7.0 → 0.8.1

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
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
  While the version is below 1.0.0, breaking changes ship in a minor release.
8
8
 
9
+ ## [0.8.1] - 2026-09-06
10
+
11
+ ### Fixed
12
+
13
+ - The report summary said "1 findings across 13 pages". Both counts are now
14
+ pluralised properly.
15
+
16
+ ## [0.8.0] - 2026-09-06
17
+
18
+ ### Fixed
19
+
20
+ - `siteUrl` now overrides the crawled origin for an origin crawl, not just a
21
+ `--dir` crawl. Checking a local build or a preview deployment means crawling
22
+ `http://localhost:3000` while every page's canonical points at production, so
23
+ `canonical.offsite` fired on every page and made the check useless in exactly
24
+ the setup it is most wanted. Where you crawl and what the site calls itself are
25
+ separate things; `siteUrl` is now the authority on the latter. Without it the
26
+ crawled origin is still used, so nothing changes for a plain production crawl.
27
+
9
28
  ## [0.7.0] - 2026-09-06
10
29
 
11
30
  ### Changed
@@ -237,6 +256,8 @@ Initial release. `snapshot`, `check` and `audit` commands; filesystem and HTTP
237
256
  crawling; diff classified by transition; absolute, cross-page and hreflang audit
238
257
  rules; pretty, JSON, markdown, GitHub and HTML reporters.
239
258
 
259
+ [0.8.1]: https://github.com/shyamexe/pagetrace/compare/v0.8.0...v0.8.1
260
+ [0.8.0]: https://github.com/shyamexe/pagetrace/compare/v0.7.0...v0.8.0
240
261
  [0.7.0]: https://github.com/shyamexe/pagetrace/compare/v0.6.0...v0.7.0
241
262
  [0.6.0]: https://github.com/shyamexe/pagetrace/compare/v0.5.0...v0.6.0
242
263
  [0.5.0]: https://github.com/shyamexe/pagetrace/compare/v0.4.0...v0.5.0
package/README.md CHANGED
@@ -156,7 +156,7 @@ Alongside the diff, `check` runs absolute rules: missing title, canonical, `h1`,
156
156
  }
157
157
  ```
158
158
 
159
- `siteUrl` is only needed for a `--dir` crawl, and only to detect canonicals pointing at another host a staging hostname leaking into production canonicals. A `--url` crawl infers it.
159
+ `siteUrl` is what the site calls itself, which is not always where you are crawling it. It is what `canonical.offsite` compares against, so set it when checking a `--dir` build, and when crawling a local build or a preview deployment whose pages carry production canonicals. A plain crawl of production infers it.
160
160
 
161
161
  Every finding has a stable `code`. Set any code to `error`, `warn`, `info`, or `off`.
162
162
 
package/dist/cli.cjs CHANGED
@@ -1030,9 +1030,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
1030
1030
  const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(import_picocolors.default.dim(" \xB7 "));
1031
1031
  lines.push(import_picocolors.default.dim("\u2500".repeat(width)));
1032
1032
  lines.push(`${import_picocolors.default.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
1033
+ const found = instances.error + instances.warn + instances.info;
1033
1034
  lines.push(
1034
1035
  import_picocolors.default.dim(
1035
- `${instances.error + instances.warn + instances.info} findings across ${meta.pageCount} pages`
1036
+ `${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
1036
1037
  )
1037
1038
  );
1038
1039
  lines.push("");
@@ -1451,7 +1452,11 @@ async function snapshotFromOrigin(origin, options = {}) {
1451
1452
  const base = new URL(origin);
1452
1453
  const agents = options.aiAgents ?? DEFAULT_AI_AGENTS;
1453
1454
  const timeout = options.timeout;
1454
- const site = { origin: base.origin, robotsTxt: null, llmsTxt: null };
1455
+ const site = {
1456
+ origin: options.siteUrl ? new URL(options.siteUrl).origin : base.origin,
1457
+ robotsTxt: null,
1458
+ llmsTxt: null
1459
+ };
1455
1460
  const limit = options.limit ?? 200;
1456
1461
  const robots = await fetchText(new URL("/robots.txt", base).href, timeout);
1457
1462
  if (robots !== null) site.robotsTxt = extractRobotsTxt(robots, agents);
@@ -1641,7 +1646,7 @@ cli.command("audit", "Audit a site as it stands, with explanations and fixes").o
1641
1646
  }
1642
1647
  });
1643
1648
  cli.help();
1644
- cli.version("0.7.0");
1649
+ cli.version("0.8.1");
1645
1650
  async function main() {
1646
1651
  try {
1647
1652
  cli.parse(process.argv, { run: false });
package/dist/cli.js CHANGED
@@ -1007,9 +1007,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
1007
1007
  const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(pc.dim(" \xB7 "));
1008
1008
  lines.push(pc.dim("\u2500".repeat(width)));
1009
1009
  lines.push(`${pc.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
1010
+ const found = instances.error + instances.warn + instances.info;
1010
1011
  lines.push(
1011
1012
  pc.dim(
1012
- `${instances.error + instances.warn + instances.info} findings across ${meta.pageCount} pages`
1013
+ `${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
1013
1014
  )
1014
1015
  );
1015
1016
  lines.push("");
@@ -1428,7 +1429,11 @@ async function snapshotFromOrigin(origin, options = {}) {
1428
1429
  const base = new URL(origin);
1429
1430
  const agents = options.aiAgents ?? DEFAULT_AI_AGENTS;
1430
1431
  const timeout = options.timeout;
1431
- const site = { origin: base.origin, robotsTxt: null, llmsTxt: null };
1432
+ const site = {
1433
+ origin: options.siteUrl ? new URL(options.siteUrl).origin : base.origin,
1434
+ robotsTxt: null,
1435
+ llmsTxt: null
1436
+ };
1432
1437
  const limit = options.limit ?? 200;
1433
1438
  const robots = await fetchText(new URL("/robots.txt", base).href, timeout);
1434
1439
  if (robots !== null) site.robotsTxt = extractRobotsTxt(robots, agents);
@@ -1618,7 +1623,7 @@ cli.command("audit", "Audit a site as it stands, with explanations and fixes").o
1618
1623
  }
1619
1624
  });
1620
1625
  cli.help();
1621
- cli.version("0.7.0");
1626
+ cli.version("0.8.1");
1622
1627
  async function main() {
1623
1628
  try {
1624
1629
  cli.parse(process.argv, { run: false });
package/dist/index.cjs CHANGED
@@ -1275,9 +1275,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
1275
1275
  const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(import_picocolors.default.dim(" \xB7 "));
1276
1276
  lines.push(import_picocolors.default.dim("\u2500".repeat(width)));
1277
1277
  lines.push(`${import_picocolors.default.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
1278
+ const found = instances.error + instances.warn + instances.info;
1278
1279
  lines.push(
1279
1280
  import_picocolors.default.dim(
1280
- `${instances.error + instances.warn + instances.info} findings across ${meta.pageCount} pages`
1281
+ `${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
1281
1282
  )
1282
1283
  );
1283
1284
  lines.push("");
@@ -1490,7 +1491,11 @@ async function snapshotFromOrigin(origin, options = {}) {
1490
1491
  const base = new URL(origin);
1491
1492
  const agents = options.aiAgents ?? DEFAULT_AI_AGENTS;
1492
1493
  const timeout = options.timeout;
1493
- const site = { origin: base.origin, robotsTxt: null, llmsTxt: null };
1494
+ const site = {
1495
+ origin: options.siteUrl ? new URL(options.siteUrl).origin : base.origin,
1496
+ robotsTxt: null,
1497
+ llmsTxt: null
1498
+ };
1494
1499
  const limit = options.limit ?? 200;
1495
1500
  const robots = await fetchText(new URL("/robots.txt", base).href, timeout);
1496
1501
  if (robots !== null) site.robotsTxt = extractRobotsTxt(robots, agents);
package/dist/index.d.cts CHANGED
@@ -94,8 +94,10 @@ interface Config {
94
94
  /** Minimum word count before a page is flagged as thin. */
95
95
  minWordCount?: number;
96
96
  /**
97
- * The site's own origin, e.g. "https://example.com". Lets a --dir crawl detect
98
- * canonicals pointing at another host; an origin crawl infers it.
97
+ * The site's own origin, e.g. "https://example.com". Used to detect canonicals
98
+ * pointing at another host. A --dir crawl has no other source for it, and an
99
+ * origin crawl of a local build or preview deployment needs it to override the
100
+ * URL being crawled, since those serve production canonicals.
99
101
  */
100
102
  siteUrl?: string;
101
103
  }
package/dist/index.d.ts CHANGED
@@ -94,8 +94,10 @@ interface Config {
94
94
  /** Minimum word count before a page is flagged as thin. */
95
95
  minWordCount?: number;
96
96
  /**
97
- * The site's own origin, e.g. "https://example.com". Lets a --dir crawl detect
98
- * canonicals pointing at another host; an origin crawl infers it.
97
+ * The site's own origin, e.g. "https://example.com". Used to detect canonicals
98
+ * pointing at another host. A --dir crawl has no other source for it, and an
99
+ * origin crawl of a local build or preview deployment needs it to override the
100
+ * URL being crawled, since those serve production canonicals.
99
101
  */
100
102
  siteUrl?: string;
101
103
  }
package/dist/index.js CHANGED
@@ -1204,9 +1204,10 @@ function formatAuditPretty(groups, meta, columns = 80) {
1204
1204
  const counted = ["error", "warn", "info"].filter((s) => issues[s] > 0).map((s) => BADGE[s](`${issues[s]} ${issues[s] === 1 ? SINGULAR[s] : PLURAL[s]}`)).join(pc.dim(" \xB7 "));
1205
1205
  lines.push(pc.dim("\u2500".repeat(width)));
1206
1206
  lines.push(`${pc.bold(`${total} issue${total === 1 ? "" : "s"}`)} ${counted}`);
1207
+ const found = instances.error + instances.warn + instances.info;
1207
1208
  lines.push(
1208
1209
  pc.dim(
1209
- `${instances.error + instances.warn + instances.info} findings across ${meta.pageCount} pages`
1210
+ `${found} finding${found === 1 ? "" : "s"} across ${meta.pageCount} page${meta.pageCount === 1 ? "" : "s"}`
1210
1211
  )
1211
1212
  );
1212
1213
  lines.push("");
@@ -1419,7 +1420,11 @@ async function snapshotFromOrigin(origin, options = {}) {
1419
1420
  const base = new URL(origin);
1420
1421
  const agents = options.aiAgents ?? DEFAULT_AI_AGENTS;
1421
1422
  const timeout = options.timeout;
1422
- const site = { origin: base.origin, robotsTxt: null, llmsTxt: null };
1423
+ const site = {
1424
+ origin: options.siteUrl ? new URL(options.siteUrl).origin : base.origin,
1425
+ robotsTxt: null,
1426
+ llmsTxt: null
1427
+ };
1423
1428
  const limit = options.limit ?? 200;
1424
1429
  const robots = await fetchText(new URL("/robots.txt", base).href, timeout);
1425
1430
  if (robots !== null) site.robotsTxt = extractRobotsTxt(robots, agents);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pagetrace",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "Baseline your site's SEO and AEO surface, diff every build against it, and fail CI on regressions.",
5
5
  "main": "./dist/index.cjs",
6
6
  "scripts": {