@pseolint/core 0.3.1 → 0.4.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 (76) hide show
  1. package/README.md +49 -1
  2. package/dist/ai/triage.d.ts.map +1 -1
  3. package/dist/ai/triage.js +8 -1
  4. package/dist/ai/triage.js.map +1 -1
  5. package/dist/auditor.d.ts.map +1 -1
  6. package/dist/auditor.js +495 -130
  7. package/dist/auditor.js.map +1 -1
  8. package/dist/backpressure.d.ts +68 -0
  9. package/dist/backpressure.d.ts.map +1 -0
  10. package/dist/backpressure.js +81 -0
  11. package/dist/backpressure.js.map +1 -0
  12. package/dist/cache.d.ts +73 -0
  13. package/dist/cache.d.ts.map +1 -1
  14. package/dist/cache.js +258 -19
  15. package/dist/cache.js.map +1 -1
  16. package/dist/enrich-findings.d.ts.map +1 -1
  17. package/dist/enrich-findings.js +1 -14
  18. package/dist/enrich-findings.js.map +1 -1
  19. package/dist/fetch-observer.d.ts +97 -0
  20. package/dist/fetch-observer.d.ts.map +1 -0
  21. package/dist/fetch-observer.js +124 -0
  22. package/dist/fetch-observer.js.map +1 -0
  23. package/dist/formatters/console.d.ts +7 -9
  24. package/dist/formatters/console.d.ts.map +1 -1
  25. package/dist/formatters/console.js +218 -254
  26. package/dist/formatters/console.js.map +1 -1
  27. package/dist/formatters/html.d.ts +5 -1
  28. package/dist/formatters/html.d.ts.map +1 -1
  29. package/dist/formatters/html.js +352 -570
  30. package/dist/formatters/html.js.map +1 -1
  31. package/dist/formatters/index.d.ts +4 -1
  32. package/dist/formatters/index.d.ts.map +1 -1
  33. package/dist/formatters/index.js +1 -1
  34. package/dist/formatters/index.js.map +1 -1
  35. package/dist/formatters/json.d.ts +11 -1
  36. package/dist/formatters/json.d.ts.map +1 -1
  37. package/dist/formatters/json.js +5 -1
  38. package/dist/formatters/json.js.map +1 -1
  39. package/dist/formatters/markdown.d.ts +7 -1
  40. package/dist/formatters/markdown.d.ts.map +1 -1
  41. package/dist/formatters/markdown.js +77 -70
  42. package/dist/formatters/markdown.js.map +1 -1
  43. package/dist/index.d.ts +13 -8
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +6 -7
  46. package/dist/index.js.map +1 -1
  47. package/dist/rule-references.d.ts.map +1 -1
  48. package/dist/rule-references.js +0 -6
  49. package/dist/rule-references.js.map +1 -1
  50. package/dist/rules/content/unique-value.d.ts.map +1 -1
  51. package/dist/rules/content/unique-value.js +1 -0
  52. package/dist/rules/content/unique-value.js.map +1 -1
  53. package/dist/rules/scope.d.ts.map +1 -1
  54. package/dist/rules/scope.js +6 -14
  55. package/dist/rules/scope.js.map +1 -1
  56. package/dist/rules/tech/robots-sitemap-presence.d.ts +9 -1
  57. package/dist/rules/tech/robots-sitemap-presence.d.ts.map +1 -1
  58. package/dist/rules/tech/robots-sitemap-presence.js +14 -5
  59. package/dist/rules/tech/robots-sitemap-presence.js.map +1 -1
  60. package/dist/safe-mode-preset.d.ts +27 -0
  61. package/dist/safe-mode-preset.d.ts.map +1 -0
  62. package/dist/safe-mode-preset.js +54 -0
  63. package/dist/safe-mode-preset.js.map +1 -0
  64. package/dist/site-classifier.d.ts +83 -0
  65. package/dist/site-classifier.d.ts.map +1 -0
  66. package/dist/site-classifier.js +205 -0
  67. package/dist/site-classifier.js.map +1 -0
  68. package/dist/ssrf-guard.d.ts +96 -0
  69. package/dist/ssrf-guard.d.ts.map +1 -0
  70. package/dist/ssrf-guard.js +268 -0
  71. package/dist/ssrf-guard.js.map +1 -0
  72. package/dist/types.d.ts +171 -19
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/types.js +2 -1
  75. package/dist/types.js.map +1 -1
  76. package/package.json +2 -2
@@ -10,26 +10,22 @@ export const RULE_SCOPE = {
10
10
  "spam/template-coverage": "corpus",
11
11
  // content
12
12
  "content/unique-value": "corpus",
13
- "content/heading-uniqueness": "corpus",
14
13
  "content/meta-uniqueness": "corpus",
15
14
  "content/missing-author": "page",
16
15
  "content/eeat-signals": "page",
17
- // links (all need the global link graph)
16
+ // links
18
17
  "links/orphan-pages": "corpus",
19
18
  "links/dead-ends": "corpus",
20
19
  "links/cluster-connectivity": "corpus",
21
- "links/hub-pages": "corpus",
22
20
  "links/link-depth": "corpus",
23
21
  "links/unreachable-from-root": "corpus",
24
- "links/hub-pages-skipped": "corpus",
25
- // tech (per-page except sitemap / robots / canonical-consistency which need knownUrls)
22
+ // tech
26
23
  "tech/canonical-consistency": "corpus",
27
24
  "tech/canonical-noindex-conflict": "page",
28
25
  "tech/robots-noindex-conflict": "corpus",
29
26
  "tech/sitemap-completeness": "corpus",
30
27
  "tech/redirect-chain": "page",
31
28
  "tech/soft-404": "page",
32
- "tech/og-completeness": "page",
33
29
  "tech/hreflang-consistency": "corpus",
34
30
  "tech/robots-compliance": "corpus",
35
31
  "tech/robots-sitemap-presence": "corpus",
@@ -37,26 +33,22 @@ export const RULE_SCOPE = {
37
33
  "schema/json-ld-valid": "page",
38
34
  "schema/required-fields": "page",
39
35
  "schema/consistency": "corpus",
40
- // cannibal (cross-page by definition)
41
- "cannibal/title-overlap": "corpus",
42
- "cannibal/keyword-collision": "corpus",
36
+ // cannibal — only url-pattern survives in v0.4 (title-overlap and
37
+ // keyword-collision dropped due to high false-positive rates; see
38
+ // 2026-04-29 v0.4 redesign spec §4.3).
43
39
  "cannibal/url-pattern": "corpus",
44
40
  // data binding
45
41
  "data/missing-binding": "page",
46
42
  "data/identical-across-pages": "corpus",
47
43
  // audit-internal
48
44
  "audit/duplicate-url": "corpus",
49
- // AEO (Answer Engine Optimization) — forward-compatible entries for rules
50
- // shipping from a parallel core-engine change. `llms-txt` and `crawler-access`
51
- // are site-wide (need host config / robots surface); the rest evaluate a
52
- // single page's content structure and must run in daily diff-audits.
45
+ // AEO (Answer Engine Optimization).
53
46
  "aeo/llms-txt": "corpus",
54
47
  "aeo/crawler-access": "corpus",
55
48
  "aeo/freshness-signals": "page",
56
49
  "aeo/faq-coverage": "page",
57
50
  "aeo/answer-first": "page",
58
51
  "aeo/citable-facts": "page",
59
- "aeo/non-replicable-value": "page",
60
52
  "aeo/content-modularity": "page",
61
53
  "aeo/summary-bait": "page",
62
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/rules/scope.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,UAAU,GAA8B;IACnD,OAAO;IACP,qBAAqB,EAAE,QAAQ;IAC/B,kBAAkB,EAAE,QAAQ;IAC5B,mBAAmB,EAAE,MAAM;IAC3B,wBAAwB,EAAE,QAAQ;IAClC,yBAAyB,EAAE,QAAQ;IACnC,2BAA2B,EAAE,QAAQ;IACrC,sBAAsB,EAAE,QAAQ;IAChC,wBAAwB,EAAE,QAAQ;IAElC,UAAU;IACV,sBAAsB,EAAE,QAAQ;IAChC,4BAA4B,EAAE,QAAQ;IACtC,yBAAyB,EAAE,QAAQ;IACnC,wBAAwB,EAAE,MAAM;IAChC,sBAAsB,EAAE,MAAM;IAE9B,yCAAyC;IACzC,oBAAoB,EAAE,QAAQ;IAC9B,iBAAiB,EAAE,QAAQ;IAC3B,4BAA4B,EAAE,QAAQ;IACtC,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,6BAA6B,EAAE,QAAQ;IACvC,yBAAyB,EAAE,QAAQ;IAEnC,uFAAuF;IACvF,4BAA4B,EAAE,QAAQ;IACtC,iCAAiC,EAAE,MAAM;IACzC,8BAA8B,EAAE,QAAQ;IACxC,2BAA2B,EAAE,QAAQ;IACrC,qBAAqB,EAAE,MAAM;IAC7B,eAAe,EAAE,MAAM;IACvB,sBAAsB,EAAE,MAAM;IAC9B,2BAA2B,EAAE,QAAQ;IACrC,wBAAwB,EAAE,QAAQ;IAClC,8BAA8B,EAAE,QAAQ;IAExC,SAAS;IACT,sBAAsB,EAAE,MAAM;IAC9B,wBAAwB,EAAE,MAAM;IAChC,oBAAoB,EAAE,QAAQ;IAE9B,sCAAsC;IACtC,wBAAwB,EAAE,QAAQ;IAClC,4BAA4B,EAAE,QAAQ;IACtC,sBAAsB,EAAE,QAAQ;IAEhC,eAAe;IACf,sBAAsB,EAAE,MAAM;IAC9B,6BAA6B,EAAE,QAAQ;IAEvC,iBAAiB;IACjB,qBAAqB,EAAE,QAAQ;IAE/B,0EAA0E;IAC1E,+EAA+E;IAC/E,yEAAyE;IACzE,qEAAqE;IACrE,cAAc,EAAE,QAAQ;IACxB,oBAAoB,EAAE,QAAQ;IAC9B,uBAAuB,EAAE,MAAM;IAC/B,kBAAkB,EAAE,MAAM;IAC1B,kBAAkB,EAAE,MAAM;IAC1B,mBAAmB,EAAE,MAAM;IAC3B,0BAA0B,EAAE,MAAM;IAClC,wBAAwB,EAAE,MAAM;IAChC,kBAAkB,EAAE,MAAM;CAC3B,CAAC;AAEF,4GAA4G;AAC5G,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,MAAM,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/rules/scope.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,UAAU,GAA8B;IACnD,OAAO;IACP,qBAAqB,EAAE,QAAQ;IAC/B,kBAAkB,EAAE,QAAQ;IAC5B,mBAAmB,EAAE,MAAM;IAC3B,wBAAwB,EAAE,QAAQ;IAClC,yBAAyB,EAAE,QAAQ;IACnC,2BAA2B,EAAE,QAAQ;IACrC,sBAAsB,EAAE,QAAQ;IAChC,wBAAwB,EAAE,QAAQ;IAElC,UAAU;IACV,sBAAsB,EAAE,QAAQ;IAChC,yBAAyB,EAAE,QAAQ;IACnC,wBAAwB,EAAE,MAAM;IAChC,sBAAsB,EAAE,MAAM;IAE9B,QAAQ;IACR,oBAAoB,EAAE,QAAQ;IAC9B,iBAAiB,EAAE,QAAQ;IAC3B,4BAA4B,EAAE,QAAQ;IACtC,kBAAkB,EAAE,QAAQ;IAC5B,6BAA6B,EAAE,QAAQ;IAEvC,OAAO;IACP,4BAA4B,EAAE,QAAQ;IACtC,iCAAiC,EAAE,MAAM;IACzC,8BAA8B,EAAE,QAAQ;IACxC,2BAA2B,EAAE,QAAQ;IACrC,qBAAqB,EAAE,MAAM;IAC7B,eAAe,EAAE,MAAM;IACvB,2BAA2B,EAAE,QAAQ;IACrC,wBAAwB,EAAE,QAAQ;IAClC,8BAA8B,EAAE,QAAQ;IAExC,SAAS;IACT,sBAAsB,EAAE,MAAM;IAC9B,wBAAwB,EAAE,MAAM;IAChC,oBAAoB,EAAE,QAAQ;IAE9B,kEAAkE;IAClE,kEAAkE;IAClE,uCAAuC;IACvC,sBAAsB,EAAE,QAAQ;IAEhC,eAAe;IACf,sBAAsB,EAAE,MAAM;IAC9B,6BAA6B,EAAE,QAAQ;IAEvC,iBAAiB;IACjB,qBAAqB,EAAE,QAAQ;IAE/B,oCAAoC;IACpC,cAAc,EAAE,QAAQ;IACxB,oBAAoB,EAAE,QAAQ;IAC9B,uBAAuB,EAAE,MAAM;IAC/B,kBAAkB,EAAE,MAAM;IAC1B,kBAAkB,EAAE,MAAM;IAC1B,mBAAmB,EAAE,MAAM;IAC3B,wBAAwB,EAAE,MAAM;IAChC,kBAAkB,EAAE,MAAM;CAC3B,CAAC;AAEF,4GAA4G;AAC5G,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,MAAM,CAAC;AACrD,CAAC"}
@@ -6,7 +6,15 @@ export declare function robotsSitemapPresenceRule(source: string): Promise<RuleR
6
6
  */
7
7
  /** Parse `Crawl-delay: N` from the `User-agent: *` block. Returns seconds, or 0 if unset. */
8
8
  export declare function parseCrawlDelaySeconds(robotsTxt: string): number;
9
- export declare function parseDisallowPatterns(robotsTxt: string): string[];
9
+ /**
10
+ * Parse Disallow patterns for the given user-agents. Merges the `User-agent: *`
11
+ * block with any named UA blocks; a hostile site that specifically disallows
12
+ * `pseolint` without a wildcard still gets honored.
13
+ *
14
+ * The default UA list (`["*"]`) preserves the pre-v0.3.2 behavior for callers
15
+ * that don't opt into UA-specific matching.
16
+ */
17
+ export declare function parseDisallowPatterns(robotsTxt: string, userAgents?: readonly string[]): string[];
10
18
  /**
11
19
  * Returns true if `urlPath` (e.g. "/blog/post") is blocked by a single Disallow pattern.
12
20
  *
@@ -1 +1 @@
1
- {"version":3,"file":"robots-sitemap-presence.d.ts","sourceRoot":"","sources":["../../../src/rules/tech/robots-sitemap-presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAc7D,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAqDrF;AAED;;;GAGG;AACH,6FAA6F;AAC7F,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmBhE;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BjE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA8B5E;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EAAE,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,gBAAgB,EAAE,MAAM,GACvB,UAAU,EAAE,CA+Bd"}
1
+ {"version":3,"file":"robots-sitemap-presence.d.ts","sourceRoot":"","sources":["../../../src/rules/tech/robots-sitemap-presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAc7D,wBAAsB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAqDrF;AAED;;;GAGG;AACH,6FAA6F;AAC7F,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmBhE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,SAAS,MAAM,EAAU,GAAG,MAAM,EAAE,CA+BxG;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA8B5E;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EAAE,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,gBAAgB,EAAE,MAAM,GACvB,UAAU,EAAE,CA+Bd"}
@@ -86,10 +86,19 @@ export function parseCrawlDelaySeconds(robotsTxt) {
86
86
  }
87
87
  return 0;
88
88
  }
89
- export function parseDisallowPatterns(robotsTxt) {
89
+ /**
90
+ * Parse Disallow patterns for the given user-agents. Merges the `User-agent: *`
91
+ * block with any named UA blocks; a hostile site that specifically disallows
92
+ * `pseolint` without a wildcard still gets honored.
93
+ *
94
+ * The default UA list (`["*"]`) preserves the pre-v0.3.2 behavior for callers
95
+ * that don't opt into UA-specific matching.
96
+ */
97
+ export function parseDisallowPatterns(robotsTxt, userAgents = ["*"]) {
90
98
  const lines = robotsTxt.split(/\r?\n/);
91
99
  const patterns = [];
92
- let inWildcardBlock = false;
100
+ const uaSet = new Set(userAgents.map((u) => u.toLowerCase()));
101
+ let inMatchingBlock = false;
93
102
  for (const rawLine of lines) {
94
103
  const line = rawLine.trim();
95
104
  // Skip comments and blank lines
@@ -97,11 +106,11 @@ export function parseDisallowPatterns(robotsTxt) {
97
106
  continue;
98
107
  // Detect User-agent directive
99
108
  if (/^user-agent\s*:/i.test(line)) {
100
- const value = line.replace(/^user-agent\s*:\s*/i, "").trim();
101
- inWildcardBlock = value === "*";
109
+ const value = line.replace(/^user-agent\s*:\s*/i, "").trim().toLowerCase();
110
+ inMatchingBlock = uaSet.has(value);
102
111
  continue;
103
112
  }
104
- if (!inWildcardBlock)
113
+ if (!inMatchingBlock)
105
114
  continue;
106
115
  if (/^disallow\s*:/i.test(line)) {
107
116
  const value = line.replace(/^disallow\s*:\s*/i, "").trim();
@@ -1 +1 @@
1
- {"version":3,"file":"robots-sitemap-presence.js","sourceRoot":"","sources":["../../../src/rules/tech/robots-sitemap-presence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"robots-sitemap-presence.js","sourceRoot":"","sources":["../../../src/rules/tech/robots-sitemap-presence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { SafeMode, AuditOptions } from "./types.js";
2
+ export type SafeModePreset = {
3
+ concurrency?: number;
4
+ sampleSize?: number;
5
+ guardSsrf?: boolean;
6
+ respectRobotsTxt?: boolean;
7
+ followRedirects?: boolean;
8
+ maxCrawlDiscovered?: number;
9
+ maxFetchBytes?: number;
10
+ };
11
+ export type SafeModeKey = SafeMode | "__none";
12
+ /**
13
+ * Presets that flip several safety defaults at once. Individual options on
14
+ * AuditOptions override the preset when explicitly set. `__none` is the
15
+ * sentinel key used when no preset is selected — all fields undefined so the
16
+ * `??` chain falls through to hard-coded defaults.
17
+ */
18
+ export declare const SAFE_MODE_PRESETS: Record<SafeModeKey, SafeModePreset>;
19
+ /**
20
+ * Pick the preset key for a given source + options combination.
21
+ *
22
+ * explicit `safeMode` → that preset
23
+ * autoDevPreset !== false && localhost URL → "dev"
24
+ * otherwise → "__none"
25
+ */
26
+ export declare function resolveSafeModeKey(source: string, options?: Pick<AuditOptions, "safeMode" | "autoDevPreset">): SafeModeKey;
27
+ //# sourceMappingURL=safe-mode-preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-mode-preset.d.ts","sourceRoot":"","sources":["../src/safe-mode-preset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGzD,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,WAAW,EAAE,cAAc,CA6BjE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,eAAe,CAAC,GACzD,WAAW,CAKb"}
@@ -0,0 +1,54 @@
1
+ import { isLocalhostUrl } from "./ssrf-guard.js";
2
+ /**
3
+ * Presets that flip several safety defaults at once. Individual options on
4
+ * AuditOptions override the preset when explicitly set. `__none` is the
5
+ * sentinel key used when no preset is selected — all fields undefined so the
6
+ * `??` chain falls through to hard-coded defaults.
7
+ */
8
+ export const SAFE_MODE_PRESETS = {
9
+ saas: {
10
+ // Hosted-service defaults. Assume user-submitted URLs are hostile.
11
+ guardSsrf: true,
12
+ respectRobotsTxt: true,
13
+ followRedirects: true,
14
+ maxCrawlDiscovered: 2000,
15
+ maxFetchBytes: 10_000_000,
16
+ },
17
+ cli: {
18
+ // Local / dev defaults. User auditing their own or local site.
19
+ guardSsrf: false,
20
+ respectRobotsTxt: true,
21
+ followRedirects: true,
22
+ maxCrawlDiscovered: 5000,
23
+ maxFetchBytes: 52_428_800,
24
+ },
25
+ dev: {
26
+ // Localhost probe. A cache-cold dev server can amplify every crawled URL
27
+ // into a chain of DB queries — keep the first pass tiny and reversible.
28
+ concurrency: 1,
29
+ sampleSize: 25,
30
+ guardSsrf: false,
31
+ respectRobotsTxt: true,
32
+ followRedirects: true,
33
+ maxCrawlDiscovered: 50,
34
+ maxFetchBytes: 52_428_800,
35
+ },
36
+ __none: {},
37
+ };
38
+ /**
39
+ * Pick the preset key for a given source + options combination.
40
+ *
41
+ * explicit `safeMode` → that preset
42
+ * autoDevPreset !== false && localhost URL → "dev"
43
+ * otherwise → "__none"
44
+ */
45
+ export function resolveSafeModeKey(source, options) {
46
+ if (options?.safeMode)
47
+ return options.safeMode;
48
+ if (options?.autoDevPreset === false)
49
+ return "__none";
50
+ if (isLocalhostUrl(source))
51
+ return "dev";
52
+ return "__none";
53
+ }
54
+ //# sourceMappingURL=safe-mode-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-mode-preset.js","sourceRoot":"","sources":["../src/safe-mode-preset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAcjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAwC;IACpE,IAAI,EAAE;QACJ,mEAAmE;QACnE,SAAS,EAAE,IAAI;QACf,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;QACxB,aAAa,EAAE,UAAU;KAC1B;IACD,GAAG,EAAE;QACH,+DAA+D;QAC/D,SAAS,EAAE,KAAK;QAChB,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;QACxB,aAAa,EAAE,UAAU;KAC1B;IACD,GAAG,EAAE;QACH,yEAAyE;QACzE,wEAAwE;QACxE,WAAW,EAAE,CAAC;QACd,UAAU,EAAE,EAAE;QACd,SAAS,EAAE,KAAK;QAChB,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,EAAE;QACtB,aAAa,EAAE,UAAU;KAC1B;IACD,MAAM,EAAE,EAAE;CACX,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,OAA0D;IAE1D,IAAI,OAAO,EAAE,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC/C,IAAI,OAAO,EAAE,aAAa,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC;IACtD,IAAI,cAAc,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * v0.4 Site Classifier — runs BEFORE rules to gate which rule set applies.
3
+ *
4
+ * Today the engine runs every rule against every audited site regardless of
5
+ * whether the site is actually programmatic-SEO. A 23-page marketing site
6
+ * gets pSEO-targeted findings that don't apply; a 50,000-page directory
7
+ * gets the same audit shape as a small blog. This pre-flight classifier
8
+ * decides which "kind" of site we're auditing and emits a list of ruleIds
9
+ * that the dispatcher will skip when site type is small-marketing/blog.
10
+ *
11
+ * Heuristics (v1, ships in v0.4):
12
+ * - Sitemap URL count: <50 = bias small/blog; ≥1000 = bias programmatic.
13
+ * - URL-pattern clustering: normalize numeric/slug segments; if top-3
14
+ * templates cover ≥60% of URLs → strong programmatic signal.
15
+ * - Framework signal: pass-through from dev-server detection.
16
+ *
17
+ * Deferred to v0.4.1+ (per spec §4.11):
18
+ * - DOM-skeleton hashing across pages.
19
+ * - Per-cluster classification (mixed pSEO + marketing).
20
+ * - Per-page applicability tagging on findings.
21
+ */
22
+ export type SiteType = "programmatic-directory" | "small-marketing" | "blog" | "ecommerce" | "unclear";
23
+ export type ClassificationSignal = {
24
+ kind: "sitemap-url-count";
25
+ value: number;
26
+ } | {
27
+ kind: "url-pattern-cluster-coverage";
28
+ topTemplate: string;
29
+ pages: number;
30
+ ratio: number;
31
+ } | {
32
+ kind: "framework-detected";
33
+ value: "nextjs" | "vite" | "astro" | "unknown";
34
+ };
35
+ export interface SiteClassification {
36
+ type: SiteType;
37
+ /** 0–1 confidence. Below 0.6 → treat as `unclear` and run all rules. */
38
+ confidence: number;
39
+ /** Ordered observations that fed the classification. UI surfaces these. */
40
+ signals: ClassificationSignal[];
41
+ /**
42
+ * RuleIds suppressed because of this classification. The dispatcher
43
+ * checks this list before invoking each rule.
44
+ *
45
+ * Empty array when type is `programmatic-directory`, `ecommerce`, or
46
+ * `unclear` — those run all rules.
47
+ */
48
+ suppressedRules: string[];
49
+ }
50
+ /** Rules suppressed for non-pSEO sites (small-marketing / blog). */
51
+ export declare const PSEO_ONLY_RULE_IDS: readonly string[];
52
+ /**
53
+ * Normalize a pathname into a hashable template by replacing path segments
54
+ * that look like values with type placeholders.
55
+ *
56
+ * Examples:
57
+ * /california/los-angeles/plumbers → /:slug/:slug/:slug
58
+ * /blog/hello-world → /blog/:slug
59
+ * /post/12345 → /post/:n
60
+ * / → /
61
+ */
62
+ export declare function normalizePathToTemplate(pathname: string): string;
63
+ /** Compute template-cluster ratios from a URL list. Returns top entries first. */
64
+ export declare function clusterUrlTemplates(urls: string[]): Array<{
65
+ template: string;
66
+ count: number;
67
+ ratio: number;
68
+ }>;
69
+ export interface ClassifySiteInput {
70
+ /** All discovered URLs (sitemap + crawl). Unfiltered. */
71
+ urls: string[];
72
+ /** Framework detected via dev-server response headers, if any. */
73
+ framework?: "nextjs" | "vite" | "astro" | "unknown";
74
+ }
75
+ /**
76
+ * Classify a site from its URL list + framework signal. Pure function.
77
+ *
78
+ * Contract: callers must pass the FULL discovered URL list (sitemap +
79
+ * crawl), not the post-sample list. The classifier needs the raw size
80
+ * signal to distinguish a 5000-page directory from a 25-page sample of one.
81
+ */
82
+ export declare function classifySite(input: ClassifySiteInput): SiteClassification;
83
+ //# sourceMappingURL=site-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-classifier.d.ts","sourceRoot":"","sources":["../src/site-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,QAAQ,GAChB,wBAAwB,GACxB,iBAAiB,GACjB,MAAM,GACN,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC5C;IACE,IAAI,EAAE,8BAA8B,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAK/C,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiChE;AAiBD,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB7G;AAED,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACrD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CA6FzE"}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * v0.4 Site Classifier — runs BEFORE rules to gate which rule set applies.
3
+ *
4
+ * Today the engine runs every rule against every audited site regardless of
5
+ * whether the site is actually programmatic-SEO. A 23-page marketing site
6
+ * gets pSEO-targeted findings that don't apply; a 50,000-page directory
7
+ * gets the same audit shape as a small blog. This pre-flight classifier
8
+ * decides which "kind" of site we're auditing and emits a list of ruleIds
9
+ * that the dispatcher will skip when site type is small-marketing/blog.
10
+ *
11
+ * Heuristics (v1, ships in v0.4):
12
+ * - Sitemap URL count: <50 = bias small/blog; ≥1000 = bias programmatic.
13
+ * - URL-pattern clustering: normalize numeric/slug segments; if top-3
14
+ * templates cover ≥60% of URLs → strong programmatic signal.
15
+ * - Framework signal: pass-through from dev-server detection.
16
+ *
17
+ * Deferred to v0.4.1+ (per spec §4.11):
18
+ * - DOM-skeleton hashing across pages.
19
+ * - Per-cluster classification (mixed pSEO + marketing).
20
+ * - Per-page applicability tagging on findings.
21
+ */
22
+ /** Rules suppressed for non-pSEO sites (small-marketing / blog). */
23
+ export const PSEO_ONLY_RULE_IDS = [
24
+ "spam/template-coverage",
25
+ "spam/template-diversity",
26
+ "spam/entity-swap",
27
+ "cannibal/url-pattern",
28
+ ];
29
+ /**
30
+ * Normalize a pathname into a hashable template by replacing path segments
31
+ * that look like values with type placeholders.
32
+ *
33
+ * Examples:
34
+ * /california/los-angeles/plumbers → /:slug/:slug/:slug
35
+ * /blog/hello-world → /blog/:slug
36
+ * /post/12345 → /post/:n
37
+ * / → /
38
+ */
39
+ export function normalizePathToTemplate(pathname) {
40
+ // Drop trailing slash for consistency, but keep "/" itself.
41
+ let p = pathname || "/";
42
+ if (p.length > 1 && p.endsWith("/"))
43
+ p = p.slice(0, -1);
44
+ if (!p.startsWith("/"))
45
+ p = "/" + p;
46
+ const segments = p.split("/").slice(1); // drop leading empty
47
+ if (segments.length === 0 || (segments.length === 1 && segments[0] === "")) {
48
+ return "/";
49
+ }
50
+ const out = segments.map((seg) => {
51
+ if (seg === "")
52
+ return "";
53
+ // Pure numeric segment.
54
+ if (/^\d+$/.test(seg))
55
+ return ":n";
56
+ // Slug-like: lowercase letters/digits/hyphens with at least one
57
+ // hyphen-separated multi-word structure (e.g. "los-angeles",
58
+ // "hello-world"). Pure single-word segments like "about", "blog",
59
+ // "tools" are kept as literals so collection roots don't collide
60
+ // with their detail-page templates.
61
+ if (/^[a-z0-9]+(?:-[a-z0-9]+)+$/.test(seg)) {
62
+ return ":slug";
63
+ }
64
+ // Long lowercase letter-only segments (>= 12 chars) are treated as
65
+ // slugs even without hyphens — covers concatenated-word URLs like
66
+ // /chicagoplumbers without hyphens.
67
+ if (seg.length >= 12 && /^[a-z]+$/.test(seg)) {
68
+ return ":slug";
69
+ }
70
+ return seg;
71
+ });
72
+ return "/" + out.join("/");
73
+ }
74
+ /** Convert a URL string to its template path (no host, no query). */
75
+ function urlToTemplate(url) {
76
+ try {
77
+ const u = new URL(url);
78
+ return normalizePathToTemplate(u.pathname);
79
+ }
80
+ catch {
81
+ // Treat as a raw path.
82
+ if (typeof url === "string" && url.length > 0) {
83
+ const path = url.split("?")[0].split("#")[0];
84
+ return normalizePathToTemplate(path);
85
+ }
86
+ return null;
87
+ }
88
+ }
89
+ /** Compute template-cluster ratios from a URL list. Returns top entries first. */
90
+ export function clusterUrlTemplates(urls) {
91
+ const counts = new Map();
92
+ let total = 0;
93
+ for (const url of urls) {
94
+ const t = urlToTemplate(url);
95
+ if (t === null)
96
+ continue;
97
+ counts.set(t, (counts.get(t) ?? 0) + 1);
98
+ total += 1;
99
+ }
100
+ if (total === 0)
101
+ return [];
102
+ const entries = Array.from(counts.entries()).map(([template, count]) => ({
103
+ template,
104
+ count,
105
+ ratio: count / total,
106
+ }));
107
+ entries.sort((a, b) => b.count - a.count || a.template.localeCompare(b.template));
108
+ return entries;
109
+ }
110
+ /**
111
+ * Classify a site from its URL list + framework signal. Pure function.
112
+ *
113
+ * Contract: callers must pass the FULL discovered URL list (sitemap +
114
+ * crawl), not the post-sample list. The classifier needs the raw size
115
+ * signal to distinguish a 5000-page directory from a 25-page sample of one.
116
+ */
117
+ export function classifySite(input) {
118
+ const urls = Array.isArray(input.urls) ? input.urls : [];
119
+ const framework = input.framework ?? "unknown";
120
+ const signals = [];
121
+ signals.push({ kind: "sitemap-url-count", value: urls.length });
122
+ const clusters = clusterUrlTemplates(urls);
123
+ const top = clusters[0];
124
+ const top3Ratio = clusters.slice(0, 3).reduce((sum, c) => sum + c.ratio, 0);
125
+ if (top) {
126
+ signals.push({
127
+ kind: "url-pattern-cluster-coverage",
128
+ topTemplate: top.template,
129
+ pages: top.count,
130
+ ratio: top.ratio,
131
+ });
132
+ }
133
+ signals.push({ kind: "framework-detected", value: framework });
134
+ // Empty list → unclear (no signal to act on).
135
+ if (urls.length === 0) {
136
+ return { type: "unclear", confidence: 0, signals, suppressedRules: [] };
137
+ }
138
+ // Step 4: synthesize.
139
+ let type = "unclear";
140
+ let confidence = 0;
141
+ if (urls.length >= 1000) {
142
+ if (top3Ratio >= 0.6) {
143
+ type = "programmatic-directory";
144
+ confidence = 0.9;
145
+ }
146
+ else {
147
+ // Lots of pages but no clear template clustering — likely ecommerce
148
+ // (varied product URLs) or a sprawling content site.
149
+ type = "ecommerce";
150
+ confidence = 0.6;
151
+ }
152
+ }
153
+ else if (urls.length < 50) {
154
+ // Small site. Detect blog separately from generic small-marketing.
155
+ //
156
+ // Note on clustering for tiny sites: in our normalization, top-level
157
+ // pages like /about, /pricing, /contact all collapse to /:slug, so
158
+ // ratio-based clustering misfires below ~10 URLs. We require the top
159
+ // template to be deeper than one segment (so /:slug doesn't trigger)
160
+ // before treating clustering as a programmatic signal at small scale.
161
+ const blogTemplate = clusters.find((c) => c.template.startsWith("/blog/") || c.template === "/blog" || c.template === "/blog/:slug");
162
+ const topIsDeepCluster = top !== undefined &&
163
+ top.template.split("/").filter(Boolean).length >= 2 &&
164
+ top.ratio >= 0.6;
165
+ if (blogTemplate && blogTemplate.ratio >= 0.4) {
166
+ type = "blog";
167
+ confidence = 0.85;
168
+ }
169
+ else if (!topIsDeepCluster) {
170
+ // Tiny site without a deep dominant template — marketing pages.
171
+ type = "small-marketing";
172
+ confidence = 0.85;
173
+ }
174
+ else {
175
+ // Tiny site WITH a deep dominant template — likely a templated
176
+ // micro-site (rare, but possible). Don't claim it's pSEO from such a
177
+ // tiny sample. Keep `unclear` so all rules run; the rules themselves
178
+ // will decide.
179
+ type = "unclear";
180
+ confidence = 0.5;
181
+ }
182
+ }
183
+ else {
184
+ // Medium tier (50–999 URLs). Use clustering to decide.
185
+ if (top3Ratio >= 0.6) {
186
+ type = "programmatic-directory";
187
+ confidence = 0.7;
188
+ }
189
+ else {
190
+ // No clear pattern in the medium tier. Could be marketing site or
191
+ // mid-sized content. Default to unclear so we don't over-suppress.
192
+ type = "unclear";
193
+ confidence = 0.5;
194
+ }
195
+ }
196
+ // Framework-aware nudge: a small Next.js site is almost certainly a
197
+ // marketing or blog site, not a pSEO directory. We've already excluded
198
+ // pSEO via the size check, so this is mostly a confidence bump.
199
+ if (framework === "nextjs" && urls.length < 50 && (type === "small-marketing" || type === "blog")) {
200
+ confidence = Math.min(0.95, confidence + 0.05);
201
+ }
202
+ const suppressedRules = type === "small-marketing" || type === "blog" ? [...PSEO_ONLY_RULE_IDS] : [];
203
+ return { type, confidence, signals, suppressedRules };
204
+ }
205
+ //# sourceMappingURL=site-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-classifier.js","sourceRoot":"","sources":["../src/site-classifier.ts"],"names":[],"mappings":"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"}