@pseolint/core 0.4.1 → 0.5.3
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/README.md +264 -169
- package/dist/ai/manifest/diff.d.ts +78 -0
- package/dist/ai/manifest/diff.d.ts.map +1 -0
- package/dist/ai/manifest/diff.js +139 -0
- package/dist/ai/manifest/diff.js.map +1 -0
- package/dist/ai/manifest/index.d.ts +18 -0
- package/dist/ai/manifest/index.d.ts.map +1 -0
- package/dist/ai/manifest/index.js +15 -0
- package/dist/ai/manifest/index.js.map +1 -0
- package/dist/ai/manifest/validate-manifest.d.ts +37 -0
- package/dist/ai/manifest/validate-manifest.d.ts.map +1 -0
- package/dist/ai/manifest/validate-manifest.js +67 -0
- package/dist/ai/manifest/validate-manifest.js.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts +15 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.js +110 -0
- package/dist/ai/manifest/validators/domain-patches.js.map +1 -0
- package/dist/ai/manifest/validators/index.d.ts +5 -0
- package/dist/ai/manifest/validators/index.d.ts.map +1 -0
- package/dist/ai/manifest/validators/index.js +4 -0
- package/dist/ai/manifest/validators/index.js.map +1 -0
- package/dist/ai/manifest/validators/page-changes.d.ts +36 -0
- package/dist/ai/manifest/validators/page-changes.d.ts.map +1 -0
- package/dist/ai/manifest/validators/page-changes.js +221 -0
- package/dist/ai/manifest/validators/page-changes.js.map +1 -0
- package/dist/ai/manifest/validators/types.d.ts +17 -0
- package/dist/ai/manifest/validators/types.d.ts.map +1 -0
- package/dist/ai/manifest/validators/types.js +5 -0
- package/dist/ai/manifest/validators/types.js.map +1 -0
- package/dist/ai/orchestrate.d.ts +74 -0
- package/dist/ai/orchestrate.d.ts.map +1 -0
- package/dist/ai/orchestrate.js +54 -0
- package/dist/ai/orchestrate.js.map +1 -0
- package/dist/ai/orchestrator/budget.d.ts +57 -0
- package/dist/ai/orchestrator/budget.d.ts.map +1 -0
- package/dist/ai/orchestrator/budget.js +114 -0
- package/dist/ai/orchestrator/budget.js.map +1 -0
- package/dist/ai/orchestrator/finish-tool.d.ts +568 -0
- package/dist/ai/orchestrator/finish-tool.d.ts.map +1 -0
- package/dist/ai/orchestrator/finish-tool.js +114 -0
- package/dist/ai/orchestrator/finish-tool.js.map +1 -0
- package/dist/ai/orchestrator/index.d.ts +25 -0
- package/dist/ai/orchestrator/index.d.ts.map +1 -0
- package/dist/ai/orchestrator/index.js +21 -0
- package/dist/ai/orchestrator/index.js.map +1 -0
- package/dist/ai/orchestrator/log.d.ts +24 -0
- package/dist/ai/orchestrator/log.d.ts.map +1 -0
- package/dist/ai/orchestrator/log.js +48 -0
- package/dist/ai/orchestrator/log.js.map +1 -0
- package/dist/ai/orchestrator/page-cache.d.ts +64 -0
- package/dist/ai/orchestrator/page-cache.d.ts.map +1 -0
- package/dist/ai/orchestrator/page-cache.js +127 -0
- package/dist/ai/orchestrator/page-cache.js.map +1 -0
- package/dist/ai/orchestrator/prompt.d.ts +16 -0
- package/dist/ai/orchestrator/prompt.d.ts.map +1 -0
- package/dist/ai/orchestrator/prompt.js +52 -0
- package/dist/ai/orchestrator/prompt.js.map +1 -0
- package/dist/ai/orchestrator/runner.d.ts +65 -0
- package/dist/ai/orchestrator/runner.d.ts.map +1 -0
- package/dist/ai/orchestrator/runner.js +223 -0
- package/dist/ai/orchestrator/runner.js.map +1 -0
- package/dist/ai/orchestrator/session.d.ts +44 -0
- package/dist/ai/orchestrator/session.d.ts.map +1 -0
- package/dist/ai/orchestrator/session.js +64 -0
- package/dist/ai/orchestrator/session.js.map +1 -0
- package/dist/ai/orchestrator/types.d.ts +99 -0
- package/dist/ai/orchestrator/types.d.ts.map +1 -0
- package/dist/ai/orchestrator/types.js +8 -0
- package/dist/ai/orchestrator/types.js.map +1 -0
- package/dist/ai/probes/cache.d.ts +12 -0
- package/dist/ai/probes/cache.d.ts.map +1 -0
- package/dist/ai/probes/cache.js +46 -0
- package/dist/ai/probes/cache.js.map +1 -0
- package/dist/ai/tools/ask-ai-engine.d.ts +77 -0
- package/dist/ai/tools/ask-ai-engine.d.ts.map +1 -0
- package/dist/ai/tools/ask-ai-engine.js +253 -0
- package/dist/ai/tools/ask-ai-engine.js.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts +71 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.js +76 -0
- package/dist/ai/tools/check-domain-crawler-access.js.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts +70 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.js +75 -0
- package/dist/ai/tools/check-domain-llms-txt.js.map +1 -0
- package/dist/ai/tools/check-indexability.d.ts +58 -0
- package/dist/ai/tools/check-indexability.d.ts.map +1 -0
- package/dist/ai/tools/check-indexability.js +64 -0
- package/dist/ai/tools/check-indexability.js.map +1 -0
- package/dist/ai/tools/check-robots.d.ts +68 -0
- package/dist/ai/tools/check-robots.d.ts.map +1 -0
- package/dist/ai/tools/check-robots.js +90 -0
- package/dist/ai/tools/check-robots.js.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts +54 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.js +50 -0
- package/dist/ai/tools/check-rule-answer-first.js.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts +66 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js +51 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts +58 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.js +41 -0
- package/dist/ai/tools/check-rule-citable-facts.js.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts +58 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.js +45 -0
- package/dist/ai/tools/check-rule-content-modularity.js.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts +54 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.js +39 -0
- package/dist/ai/tools/check-rule-faq-coverage.js.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts +54 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.js +45 -0
- package/dist/ai/tools/check-rule-freshness-signals.js.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts +54 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js +44 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts +54 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.js +45 -0
- package/dist/ai/tools/check-rule-missing-author.js.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts +82 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.js +63 -0
- package/dist/ai/tools/check-rule-near-duplicate.js.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts +50 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.js +38 -0
- package/dist/ai/tools/check-rule-required-fields.js.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts +54 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.js +44 -0
- package/dist/ai/tools/check-rule-schema-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts +54 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.js +39 -0
- package/dist/ai/tools/check-rule-summary-bait.js.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts +66 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.js +58 -0
- package/dist/ai/tools/check-rule-thin-content.js.map +1 -0
- package/dist/ai/tools/detect-templates.d.ts +60 -0
- package/dist/ai/tools/detect-templates.d.ts.map +1 -0
- package/dist/ai/tools/detect-templates.js +43 -0
- package/dist/ai/tools/detect-templates.js.map +1 -0
- package/dist/ai/tools/fetch-page.d.ts +70 -0
- package/dist/ai/tools/fetch-page.d.ts.map +1 -0
- package/dist/ai/tools/fetch-page.js +93 -0
- package/dist/ai/tools/fetch-page.js.map +1 -0
- package/dist/ai/tools/fetch-sitemap.d.ts +60 -0
- package/dist/ai/tools/fetch-sitemap.d.ts.map +1 -0
- package/dist/ai/tools/fetch-sitemap.js +116 -0
- package/dist/ai/tools/fetch-sitemap.js.map +1 -0
- package/dist/ai/tools/index.d.ts +1555 -0
- package/dist/ai/tools/index.d.ts.map +1 -0
- package/dist/ai/tools/index.js +119 -0
- package/dist/ai/tools/index.js.map +1 -0
- package/dist/ai/tools/parse-page.d.ts +94 -0
- package/dist/ai/tools/parse-page.d.ts.map +1 -0
- package/dist/ai/tools/parse-page.js +108 -0
- package/dist/ai/tools/parse-page.js.map +1 -0
- package/dist/ai/tools/query-serp.d.ts +113 -0
- package/dist/ai/tools/query-serp.d.ts.map +1 -0
- package/dist/ai/tools/query-serp.js +131 -0
- package/dist/ai/tools/query-serp.js.map +1 -0
- package/dist/ai/tools/sample-template.d.ts +67 -0
- package/dist/ai/tools/sample-template.d.ts.map +1 -0
- package/dist/ai/tools/sample-template.js +75 -0
- package/dist/ai/tools/sample-template.js.map +1 -0
- package/dist/ai/tools/types.d.ts +73 -0
- package/dist/ai/tools/types.d.ts.map +1 -0
- package/dist/ai/tools/types.js +64 -0
- package/dist/ai/tools/types.js.map +1 -0
- package/dist/ai/tools/validate-jsonld.d.ts +62 -0
- package/dist/ai/tools/validate-jsonld.d.ts.map +1 -0
- package/dist/ai/tools/validate-jsonld.js +84 -0
- package/dist/ai/tools/validate-jsonld.js.map +1 -0
- package/dist/auditor.d.ts +16 -1
- package/dist/auditor.d.ts.map +1 -1
- package/dist/auditor.js +862 -88
- package/dist/auditor.js.map +1 -1
- package/dist/backpressure.d.ts.map +1 -1
- package/dist/backpressure.js +10 -3
- package/dist/backpressure.js.map +1 -1
- package/dist/enrich-findings.d.ts.map +1 -1
- package/dist/enrich-findings.js +15 -1
- package/dist/enrich-findings.js.map +1 -1
- package/dist/formatters/bucket-findings.d.ts +43 -0
- package/dist/formatters/bucket-findings.d.ts.map +1 -0
- package/dist/formatters/bucket-findings.js +110 -0
- package/dist/formatters/bucket-findings.js.map +1 -0
- package/dist/formatters/console.d.ts.map +1 -1
- package/dist/formatters/console.js +116 -34
- package/dist/formatters/console.js.map +1 -1
- package/dist/formatters/fixplan.d.ts +13 -0
- package/dist/formatters/fixplan.d.ts.map +1 -0
- package/dist/formatters/fixplan.js +328 -0
- package/dist/formatters/fixplan.js.map +1 -0
- package/dist/formatters/html.d.ts.map +1 -1
- package/dist/formatters/html.js +27 -0
- package/dist/formatters/html.js.map +1 -1
- package/dist/formatters/index.d.ts +2 -0
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +1 -0
- package/dist/formatters/index.js.map +1 -1
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +97 -9
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/page-filter.d.ts +64 -6
- package/dist/page-filter.d.ts.map +1 -1
- package/dist/page-filter.js +124 -3
- package/dist/page-filter.js.map +1 -1
- package/dist/rule-references.d.ts.map +1 -1
- package/dist/rule-references.js +5 -0
- package/dist/rule-references.js.map +1 -1
- package/dist/rules/aeo/answer-first.d.ts.map +1 -1
- package/dist/rules/aeo/answer-first.js +17 -3
- package/dist/rules/aeo/answer-first.js.map +1 -1
- package/dist/rules/aeo/citable-facts.d.ts.map +1 -1
- package/dist/rules/aeo/citable-facts.js +12 -1
- package/dist/rules/aeo/citable-facts.js.map +1 -1
- package/dist/rules/aeo/content-modularity.d.ts.map +1 -1
- package/dist/rules/aeo/content-modularity.js +3 -0
- package/dist/rules/aeo/content-modularity.js.map +1 -1
- package/dist/rules/aeo/crawler-access.d.ts.map +1 -1
- package/dist/rules/aeo/crawler-access.js +6 -0
- package/dist/rules/aeo/crawler-access.js.map +1 -1
- package/dist/rules/aeo/faq-coverage.d.ts.map +1 -1
- package/dist/rules/aeo/faq-coverage.js +4 -0
- package/dist/rules/aeo/faq-coverage.js.map +1 -1
- package/dist/rules/aeo/freshness-signals.d.ts.map +1 -1
- package/dist/rules/aeo/freshness-signals.js +9 -2
- package/dist/rules/aeo/freshness-signals.js.map +1 -1
- package/dist/rules/aeo/llms-txt.d.ts.map +1 -1
- package/dist/rules/aeo/llms-txt.js +6 -1
- package/dist/rules/aeo/llms-txt.js.map +1 -1
- package/dist/rules/aeo/summary-bait.d.ts.map +1 -1
- package/dist/rules/aeo/summary-bait.js +5 -2
- package/dist/rules/aeo/summary-bait.js.map +1 -1
- package/dist/rules/content/heading-structure.d.ts +21 -0
- package/dist/rules/content/heading-structure.d.ts.map +1 -0
- package/dist/rules/content/heading-structure.js +56 -0
- package/dist/rules/content/heading-structure.js.map +1 -0
- package/dist/rules/content/image-alt-text.d.ts +18 -0
- package/dist/rules/content/image-alt-text.d.ts.map +1 -0
- package/dist/rules/content/image-alt-text.js +77 -0
- package/dist/rules/content/image-alt-text.js.map +1 -0
- package/dist/rules/content/missing-author.d.ts.map +1 -1
- package/dist/rules/content/missing-author.js +10 -2
- package/dist/rules/content/missing-author.js.map +1 -1
- package/dist/rules/content/title-uniqueness.d.ts +18 -0
- package/dist/rules/content/title-uniqueness.d.ts.map +1 -0
- package/dist/rules/content/title-uniqueness.js +70 -0
- package/dist/rules/content/title-uniqueness.js.map +1 -0
- package/dist/rules/links/host-section-divergence.d.ts +3 -0
- package/dist/rules/links/host-section-divergence.d.ts.map +1 -0
- package/dist/rules/links/host-section-divergence.js +158 -0
- package/dist/rules/links/host-section-divergence.js.map +1 -0
- package/dist/rules/links/link-depth.d.ts +12 -1
- package/dist/rules/links/link-depth.d.ts.map +1 -1
- package/dist/rules/links/link-depth.js +25 -12
- package/dist/rules/links/link-depth.js.map +1 -1
- package/dist/rules/scope.d.ts.map +1 -1
- package/dist/rules/scope.js +5 -0
- package/dist/rules/scope.js.map +1 -1
- package/dist/rules/spam/doorway-pattern.d.ts.map +1 -1
- package/dist/rules/spam/doorway-pattern.js +27 -4
- package/dist/rules/spam/doorway-pattern.js.map +1 -1
- package/dist/rules/spam/publication-velocity.d.ts +1 -1
- package/dist/rules/spam/publication-velocity.d.ts.map +1 -1
- package/dist/rules/spam/publication-velocity.js +9 -4
- package/dist/rules/spam/publication-velocity.js.map +1 -1
- package/dist/rules/spam/template-coverage.js +1 -1
- package/dist/rules/spam/template-coverage.js.map +1 -1
- package/dist/rules/spam/template-diversity.js +1 -1
- package/dist/rules/spam/template-diversity.js.map +1 -1
- package/dist/rules/spam/thin-content.d.ts.map +1 -1
- package/dist/rules/spam/thin-content.js +9 -1
- package/dist/rules/spam/thin-content.js.map +1 -1
- package/dist/rules/tech/hreflang-consistency.d.ts.map +1 -1
- package/dist/rules/tech/hreflang-consistency.js +33 -4
- package/dist/rules/tech/hreflang-consistency.js.map +1 -1
- package/dist/rules/tech/og-completeness.d.ts +11 -0
- package/dist/rules/tech/og-completeness.d.ts.map +1 -1
- package/dist/rules/tech/og-completeness.js +22 -23
- package/dist/rules/tech/og-completeness.js.map +1 -1
- package/dist/ruleset-version.d.ts +8 -0
- package/dist/ruleset-version.d.ts.map +1 -0
- package/dist/ruleset-version.js +8 -0
- package/dist/ruleset-version.js.map +1 -0
- package/dist/scrape-strategy.d.ts +42 -0
- package/dist/scrape-strategy.d.ts.map +1 -0
- package/dist/scrape-strategy.js +101 -0
- package/dist/scrape-strategy.js.map +1 -0
- package/dist/site-classifier.d.ts +1 -1
- package/dist/site-classifier.d.ts.map +1 -1
- package/dist/site-classifier.js +217 -0
- package/dist/site-classifier.js.map +1 -1
- package/dist/state.d.ts +36 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -1
- package/dist/state.js.map +1 -1
- package/dist/stratified-sample.d.ts +9 -1
- package/dist/stratified-sample.d.ts.map +1 -1
- package/dist/stratified-sample.js +23 -6
- package/dist/stratified-sample.js.map +1 -1
- package/dist/types.d.ts +179 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/url-normalize.d.ts.map +1 -1
- package/dist/url-normalize.js +13 -1
- package/dist/url-normalize.js.map +1 -1
- package/package.json +90 -90
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tech/og-completeness — flags pages missing the core Open Graph metadata
|
|
3
|
+
* that drives social-share previews and is increasingly used by AI Overviews
|
|
4
|
+
* as a fallback summary signal.
|
|
5
|
+
*
|
|
6
|
+
* Required: og:title, og:description, og:image.
|
|
7
|
+
*
|
|
8
|
+
* The rule was referenced in the v0.4.x README without ever shipping. The
|
|
9
|
+
* 2026-05-03 blind-spot audit surfaced it as a tier-1 gap; this is the
|
|
10
|
+
* v0.5.2 fix.
|
|
11
|
+
*/
|
|
1
12
|
export function ogCompletenessRule(pages) {
|
|
2
|
-
const
|
|
13
|
+
const findings = [];
|
|
3
14
|
for (const page of pages) {
|
|
4
15
|
const missing = [];
|
|
5
16
|
if (!page.og.title)
|
|
@@ -8,28 +19,16 @@ export function ogCompletenessRule(pages) {
|
|
|
8
19
|
missing.push("og:description");
|
|
9
20
|
if (!page.og.image)
|
|
10
21
|
missing.push("og:image");
|
|
11
|
-
if (missing.length
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
if (missing.length === 0)
|
|
23
|
+
continue;
|
|
24
|
+
findings.push({
|
|
25
|
+
ruleId: "tech/og-completeness",
|
|
26
|
+
severity: "warning",
|
|
27
|
+
message: `${page.url} is missing Open Graph tags: ${missing.join(", ")}.`,
|
|
28
|
+
pageUrl: page.url,
|
|
29
|
+
fix: `Add the missing meta tags inside <head>: ${missing.map((tag) => `<meta property="${tag}" content="...">`).join(" ")}.`,
|
|
30
|
+
});
|
|
14
31
|
}
|
|
15
|
-
|
|
16
|
-
return [];
|
|
17
|
-
if (incomplete.length === pages.length && pages.length > 3) {
|
|
18
|
-
const allMissing = new Set(incomplete.flatMap((i) => i.missing));
|
|
19
|
-
return [{
|
|
20
|
-
ruleId: "tech/og-completeness",
|
|
21
|
-
severity: "warning",
|
|
22
|
-
message: `All ${incomplete.length} pages are missing Open Graph tags (${Array.from(allMissing).join(", ")}).`,
|
|
23
|
-
fix: `Add Open Graph tags site-wide: ${Array.from(allMissing).join(", ")}.`,
|
|
24
|
-
relatedUrls: incomplete.map((i) => i.url).sort()
|
|
25
|
-
}];
|
|
26
|
-
}
|
|
27
|
-
return incomplete.map((item) => ({
|
|
28
|
-
ruleId: "tech/og-completeness",
|
|
29
|
-
severity: "warning",
|
|
30
|
-
message: `${item.url} is missing ${item.missing.join(", ")}.`,
|
|
31
|
-
pageUrl: item.url,
|
|
32
|
-
fix: `Add the missing Open Graph tags: ${item.missing.join(", ")}.`
|
|
33
|
-
}));
|
|
32
|
+
return findings;
|
|
34
33
|
}
|
|
35
34
|
//# sourceMappingURL=og-completeness.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"og-completeness.js","sourceRoot":"","sources":["../../../src/rules/tech/og-completeness.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,MAAM,
|
|
1
|
+
{"version":3,"file":"og-completeness.js","sourceRoot":"","sources":["../../../src/rules/tech/og-completeness.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,gCAAgC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YACzE,OAAO,EAAE,IAAI,CAAC,GAAG;YACjB,GAAG,EAAE,4CAA4C,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,GAAG,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG;SAC7H,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bump when adding a rule, materially changing rule logic, or changing a default
|
|
3
|
+
* threshold in a way that would change findings on previously-audited pages.
|
|
4
|
+
* Pure refactor → don't bump. Used by change-driven monitoring to invalidate
|
|
5
|
+
* skips when a new rule wouldn't otherwise run on prior-state-only URLs.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CORE_RULESET_VERSION = "15";
|
|
8
|
+
//# sourceMappingURL=ruleset-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruleset-version.d.ts","sourceRoot":"","sources":["../src/ruleset-version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bump when adding a rule, materially changing rule logic, or changing a default
|
|
3
|
+
* threshold in a way that would change findings on previously-audited pages.
|
|
4
|
+
* Pure refactor → don't bump. Used by change-driven monitoring to invalidate
|
|
5
|
+
* skips when a new rule wouldn't otherwise run on prior-state-only URLs.
|
|
6
|
+
*/
|
|
7
|
+
export const CORE_RULESET_VERSION = "15";
|
|
8
|
+
//# sourceMappingURL=ruleset-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ruleset-version.js","sourceRoot":"","sources":["../src/ruleset-version.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { RunState } from "./state.js";
|
|
2
|
+
/** v0.5: shared default age-floor for monitoring. Single source of truth. */
|
|
3
|
+
export declare const DEFAULT_AGE_FLOOR_DAYS = 7;
|
|
4
|
+
export type RefetchReason = "new" | "age" | "ruleset" | "recheck" | "lastmod" | "gsc" | "no-signal" | "watched";
|
|
5
|
+
export type SkipReason = "unchanged";
|
|
6
|
+
export interface ScrapePlan {
|
|
7
|
+
refetch: Map<string, RefetchReason>;
|
|
8
|
+
skip: Map<string, SkipReason>;
|
|
9
|
+
}
|
|
10
|
+
export interface GscDelta {
|
|
11
|
+
impressionsDelta: number;
|
|
12
|
+
clicksDelta: number;
|
|
13
|
+
}
|
|
14
|
+
export interface GscThresholds {
|
|
15
|
+
impressionsPct: number;
|
|
16
|
+
clicksAbsolute: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ScrapeStrategyInputs {
|
|
19
|
+
candidateUrls: readonly string[];
|
|
20
|
+
priorState: RunState | null;
|
|
21
|
+
sitemapLastmodByUrl: ReadonlyMap<string, string>;
|
|
22
|
+
gscDeltasByUrl?: ReadonlyMap<string, GscDelta>;
|
|
23
|
+
gscThresholds?: GscThresholds;
|
|
24
|
+
currentRulesetVersion: string;
|
|
25
|
+
ageFloorDays: number;
|
|
26
|
+
now: Date;
|
|
27
|
+
/**
|
|
28
|
+
* v0.5.3 — caller-supplied "watched pages" list. Any URL appearing here is
|
|
29
|
+
* marked refetch with reason `"watched"` and short-circuits the rest of the
|
|
30
|
+
* matrix (age, ruleset, lastmod, etc.). Watched URLs that aren't already in
|
|
31
|
+
* `candidateUrls` are still added to the audit set — the caller may
|
|
32
|
+
* legitimately watch a page that has been removed from the sitemap and we
|
|
33
|
+
* should still audit it so they find out it's gone.
|
|
34
|
+
*
|
|
35
|
+
* Owned by the caller (e.g. the web app's per-domain DB-backed list); the
|
|
36
|
+
* engine treats it as a transient input override and never persists it on
|
|
37
|
+
* `RunState`.
|
|
38
|
+
*/
|
|
39
|
+
forceRefetchUrls?: ReadonlyArray<string>;
|
|
40
|
+
}
|
|
41
|
+
export declare function planScrapeStrategy(inputs: ScrapeStrategyInputs): ScrapePlan;
|
|
42
|
+
//# sourceMappingURL=scrape-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrape-strategy.d.ts","sourceRoot":"","sources":["../src/scrape-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,6EAA6E;AAC7E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAaxC,MAAM,MAAM,aAAa,GACrB,KAAK,GACL,KAAK,GACL,SAAS,GACT,SAAS,GACT,SAAS,GACT,KAAK,GACL,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC;AAErC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,cAAc,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,IAAI,CAAC;IACV;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC1C;AAyBD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CAgF3E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** v0.5: shared default age-floor for monitoring. Single source of truth. */
|
|
2
|
+
export const DEFAULT_AGE_FLOOR_DAYS = 7;
|
|
3
|
+
/**
|
|
4
|
+
* v0.5: severities that trigger an unconditional recheck under monitoring mode.
|
|
5
|
+
* Open blockers and warnings are re-verified every run; informational findings
|
|
6
|
+
* are carried forward without re-fetching the page. Without this gate the
|
|
7
|
+
* carry-forward path would be dead code on any site with any prior finding,
|
|
8
|
+
* because every URL with findings would round-trip through `recheck` and be
|
|
9
|
+
* fetched anyway. Pre-v0.5 had no recheck distinction (no monitoring); the
|
|
10
|
+
* gate is the load-bearing semantic difference.
|
|
11
|
+
*/
|
|
12
|
+
const RECHECK_SEVERITIES = new Set(["error", "critical", "warning", "warn"]);
|
|
13
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
14
|
+
function gscExceedsThreshold(delta, thresholds) {
|
|
15
|
+
return Math.abs(delta.impressionsDelta) >= thresholds.impressionsPct
|
|
16
|
+
|| Math.abs(delta.clicksDelta) >= thresholds.clicksAbsolute;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Returns true when the URL has at least one prior finding whose severity is
|
|
20
|
+
* in `RECHECK_SEVERITIES`. Informational findings alone do NOT trigger
|
|
21
|
+
* recheck — they're carried forward. Pre-v0.5 state files (or carriers from
|
|
22
|
+
* older runs) only have `findingIds`; for those we can't tell severity, so we
|
|
23
|
+
* assume worst-case and recheck. New runs persist full Finding records, so
|
|
24
|
+
* the severity-gated path applies on the very next monitoring run.
|
|
25
|
+
*/
|
|
26
|
+
function priorFindingsTriggerRecheck(prior) {
|
|
27
|
+
if (prior.findings.length > 0) {
|
|
28
|
+
return prior.findings.some((f) => RECHECK_SEVERITIES.has(f.severity));
|
|
29
|
+
}
|
|
30
|
+
// Fallback: legacy entries with findingIds but no full records — be safe.
|
|
31
|
+
return prior.findingIds.length > 0;
|
|
32
|
+
}
|
|
33
|
+
export function planScrapeStrategy(inputs) {
|
|
34
|
+
const refetch = new Map();
|
|
35
|
+
const skip = new Map();
|
|
36
|
+
// v0.5.3: caller-curated watched pages. A watched URL is always refetched
|
|
37
|
+
// and short-circuits the rest of the matrix so the dashboard can attribute
|
|
38
|
+
// the refetch to the user's explicit request rather than to "new"/"age"/etc.
|
|
39
|
+
// Watched URLs absent from `candidateUrls` (e.g. removed from the sitemap)
|
|
40
|
+
// are also included so the user finds out the page is gone.
|
|
41
|
+
const watchedSet = inputs.forceRefetchUrls && inputs.forceRefetchUrls.length > 0
|
|
42
|
+
? new Set(inputs.forceRefetchUrls)
|
|
43
|
+
: null;
|
|
44
|
+
const visited = new Set();
|
|
45
|
+
const evalOrder = [];
|
|
46
|
+
if (watchedSet) {
|
|
47
|
+
for (const url of watchedSet) {
|
|
48
|
+
if (!visited.has(url)) {
|
|
49
|
+
visited.add(url);
|
|
50
|
+
evalOrder.push(url);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const url of inputs.candidateUrls) {
|
|
55
|
+
if (!visited.has(url)) {
|
|
56
|
+
visited.add(url);
|
|
57
|
+
evalOrder.push(url);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const url of evalOrder) {
|
|
61
|
+
if (watchedSet && watchedSet.has(url)) {
|
|
62
|
+
refetch.set(url, "watched");
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const prior = inputs.priorState?.urls[url];
|
|
66
|
+
if (!prior) {
|
|
67
|
+
refetch.set(url, "new");
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const ageMs = inputs.now.getTime() - Date.parse(prior.fetchedAt);
|
|
71
|
+
if (Number.isFinite(ageMs) && ageMs > inputs.ageFloorDays * MS_PER_DAY) {
|
|
72
|
+
refetch.set(url, "age");
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (prior.rulesetVersion !== inputs.currentRulesetVersion) {
|
|
76
|
+
refetch.set(url, "ruleset");
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (priorFindingsTriggerRecheck(prior)) {
|
|
80
|
+
refetch.set(url, "recheck");
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const lastmod = inputs.sitemapLastmodByUrl.get(url);
|
|
84
|
+
if (lastmod && Date.parse(lastmod) > Date.parse(prior.fetchedAt)) {
|
|
85
|
+
refetch.set(url, "lastmod");
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const gscDelta = inputs.gscDeltasByUrl?.get(url);
|
|
89
|
+
if (gscDelta && inputs.gscThresholds && gscExceedsThreshold(gscDelta, inputs.gscThresholds)) {
|
|
90
|
+
refetch.set(url, "gsc");
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!lastmod && !gscDelta) {
|
|
94
|
+
refetch.set(url, "no-signal");
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
skip.set(url, "unchanged");
|
|
98
|
+
}
|
|
99
|
+
return { refetch, skip };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=scrape-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrape-strategy.js","sourceRoot":"","sources":["../src/scrape-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* - Per-cluster classification (mixed pSEO + marketing).
|
|
20
20
|
* - Per-page applicability tagging on findings.
|
|
21
21
|
*/
|
|
22
|
-
export type SiteType = "programmatic-directory" | "small-marketing" | "blog" | "ecommerce" | "unclear";
|
|
22
|
+
export type SiteType = "programmatic-directory" | "small-marketing" | "blog" | "ecommerce" | "docs" | "unclear";
|
|
23
23
|
export type ClassificationSignal = {
|
|
24
24
|
kind: "sitemap-url-count";
|
|
25
25
|
value: number;
|
|
@@ -1 +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,
|
|
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,MAAM,GACN,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,EAM/C,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiChE;AA8BD,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;AA8KD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CA2HzE"}
|
package/dist/site-classifier.js
CHANGED
|
@@ -25,6 +25,7 @@ export const PSEO_ONLY_RULE_IDS = [
|
|
|
25
25
|
"spam/template-diversity",
|
|
26
26
|
"spam/entity-swap",
|
|
27
27
|
"cannibal/url-pattern",
|
|
28
|
+
"links/host-section-divergence",
|
|
28
29
|
];
|
|
29
30
|
/**
|
|
30
31
|
* Normalize a pathname into a hashable template by replacing path segments
|
|
@@ -71,6 +72,19 @@ export function normalizePathToTemplate(pathname) {
|
|
|
71
72
|
});
|
|
72
73
|
return "/" + out.join("/");
|
|
73
74
|
}
|
|
75
|
+
/** Extract a normalized pathname from a URL string (or raw path). */
|
|
76
|
+
function urlToPath(url) {
|
|
77
|
+
try {
|
|
78
|
+
return new URL(url).pathname || "/";
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
if (typeof url === "string" && url.length > 0) {
|
|
82
|
+
const path = url.split("?")[0].split("#")[0];
|
|
83
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
74
88
|
/** Convert a URL string to its template path (no host, no query). */
|
|
75
89
|
function urlToTemplate(url) {
|
|
76
90
|
try {
|
|
@@ -107,6 +121,178 @@ export function clusterUrlTemplates(urls) {
|
|
|
107
121
|
entries.sort((a, b) => b.count - a.count || a.template.localeCompare(b.template));
|
|
108
122
|
return entries;
|
|
109
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* v0.4.3 — common docs path prefixes. Match is case-insensitive and exact
|
|
126
|
+
* on the FIRST path segment (so `/docs/...` matches but a stray `/somethingdocs`
|
|
127
|
+
* does not). Tuned to the docs frameworks we see most: Docusaurus, Nextra,
|
|
128
|
+
* GitBook, MkDocs, VuePress, mintlify, fumadocs, Astro Starlight.
|
|
129
|
+
*/
|
|
130
|
+
const DOCS_PATH_PREFIXES = [
|
|
131
|
+
"/docs",
|
|
132
|
+
"/doc",
|
|
133
|
+
"/documentation",
|
|
134
|
+
"/api",
|
|
135
|
+
"/api-docs",
|
|
136
|
+
"/api-reference",
|
|
137
|
+
"/reference",
|
|
138
|
+
"/guide",
|
|
139
|
+
"/guides",
|
|
140
|
+
"/learn",
|
|
141
|
+
"/tutorials",
|
|
142
|
+
"/manual",
|
|
143
|
+
"/handbook",
|
|
144
|
+
];
|
|
145
|
+
/**
|
|
146
|
+
* v0.4.3 — common ecommerce path prefixes. Same matching rules as docs:
|
|
147
|
+
* case-insensitive, anchored at the FIRST path segment.
|
|
148
|
+
*/
|
|
149
|
+
const ECOMMERCE_PATH_PREFIXES = [
|
|
150
|
+
"/products",
|
|
151
|
+
"/product",
|
|
152
|
+
"/collections",
|
|
153
|
+
"/collection",
|
|
154
|
+
"/shop",
|
|
155
|
+
"/store",
|
|
156
|
+
"/cart",
|
|
157
|
+
"/checkout",
|
|
158
|
+
"/category",
|
|
159
|
+
"/categories",
|
|
160
|
+
"/p", // Shopify shortlink convention
|
|
161
|
+
];
|
|
162
|
+
function firstSegmentMatches(pathname, prefixes) {
|
|
163
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
164
|
+
if (segments.length === 0)
|
|
165
|
+
return false;
|
|
166
|
+
const first = `/${segments[0].toLowerCase()}`;
|
|
167
|
+
return prefixes.includes(first);
|
|
168
|
+
}
|
|
169
|
+
/** Ratio of URLs whose first path segment matches one of `prefixes`. */
|
|
170
|
+
function pathPrefixRatio(urls, prefixes) {
|
|
171
|
+
if (urls.length === 0)
|
|
172
|
+
return 0;
|
|
173
|
+
let hits = 0;
|
|
174
|
+
let total = 0;
|
|
175
|
+
for (const u of urls) {
|
|
176
|
+
const path = urlToPath(u);
|
|
177
|
+
if (path === null)
|
|
178
|
+
continue;
|
|
179
|
+
total += 1;
|
|
180
|
+
if (firstSegmentMatches(path, prefixes))
|
|
181
|
+
hits += 1;
|
|
182
|
+
}
|
|
183
|
+
if (total === 0)
|
|
184
|
+
return 0;
|
|
185
|
+
return hits / total;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* v0.4.3 — docs site detection. A site is `docs` when its URL distribution
|
|
189
|
+
* is dominated by docs-shaped path prefixes:
|
|
190
|
+
* - 50+ URLs total (docs sites are not tiny — guard against false-positives
|
|
191
|
+
* on a 5-page marketing site with one /docs link)
|
|
192
|
+
* - ≥ 60% of URLs sit under a docs prefix
|
|
193
|
+
* Returns `null` when not enough evidence; otherwise the SiteClassification.
|
|
194
|
+
*/
|
|
195
|
+
function tryClassifyDocs(urls, signals) {
|
|
196
|
+
if (urls.length < 50)
|
|
197
|
+
return null;
|
|
198
|
+
const ratio = pathPrefixRatio(urls, DOCS_PATH_PREFIXES);
|
|
199
|
+
if (ratio < 0.6)
|
|
200
|
+
return null;
|
|
201
|
+
let confidence = 0.7;
|
|
202
|
+
if (ratio >= 0.75)
|
|
203
|
+
confidence = 0.85;
|
|
204
|
+
if (ratio >= 0.9)
|
|
205
|
+
confidence = 0.92;
|
|
206
|
+
if (urls.length >= 200)
|
|
207
|
+
confidence = Math.min(0.95, confidence + 0.03);
|
|
208
|
+
return { type: "docs", confidence, signals, suppressedRules: [] };
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* v0.4.3 — ecommerce site detection. Two paths to a positive classification:
|
|
212
|
+
* - URL count ≥ 50 AND ≥ 70% of URLs match /products/* or /collections/*
|
|
213
|
+
* (high-confidence: this is the canonical Shopify/Woo URL shape)
|
|
214
|
+
* - URL count ≥ 100 AND ≥ 50% match a broader ecommerce-shaped prefix
|
|
215
|
+
* (looser fallback for sites that mix /shop, /store, /category)
|
|
216
|
+
* Returns `null` when not enough evidence.
|
|
217
|
+
*/
|
|
218
|
+
function tryClassifyEcommerce(urls, signals) {
|
|
219
|
+
if (urls.length < 50)
|
|
220
|
+
return null;
|
|
221
|
+
const productsRatio = pathPrefixRatio(urls, ["/products", "/collections"]);
|
|
222
|
+
if (productsRatio >= 0.7) {
|
|
223
|
+
const confidence = productsRatio >= 0.85 ? 0.92 : 0.85;
|
|
224
|
+
return { type: "ecommerce", confidence, signals, suppressedRules: [] };
|
|
225
|
+
}
|
|
226
|
+
const broadRatio = pathPrefixRatio(urls, ECOMMERCE_PATH_PREFIXES);
|
|
227
|
+
if (broadRatio >= 0.5 && urls.length >= 100) {
|
|
228
|
+
const confidence = broadRatio >= 0.7 ? 0.85 : 0.75;
|
|
229
|
+
return { type: "ecommerce", confidence, signals, suppressedRules: [] };
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Locale-code regex for the FIRST path segment. Matches BCP-47-shaped slugs:
|
|
235
|
+
* `/en`, `/de`, `/en-us`, `/zh-hant`, `/pt-br`, etc. Two-letter language code
|
|
236
|
+
* with optional two-letter region. Lowercase only — sites that uppercase
|
|
237
|
+
* locale codes are rare; we don't normalize.
|
|
238
|
+
*/
|
|
239
|
+
const LOCALE_SEGMENT_REGEX = /^[a-z]{2}(?:-[a-z]{2})?$/;
|
|
240
|
+
function isLocalizedRoot(pathname) {
|
|
241
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
242
|
+
if (segments.length === 0)
|
|
243
|
+
return false;
|
|
244
|
+
return LOCALE_SEGMENT_REGEX.test(segments[0]);
|
|
245
|
+
}
|
|
246
|
+
/** Ratio of URLs whose first path segment looks like a locale code. */
|
|
247
|
+
function localizedRatio(urls) {
|
|
248
|
+
if (urls.length === 0)
|
|
249
|
+
return 0;
|
|
250
|
+
let hits = 0;
|
|
251
|
+
let total = 0;
|
|
252
|
+
for (const u of urls) {
|
|
253
|
+
const path = urlToPath(u);
|
|
254
|
+
if (path === null)
|
|
255
|
+
continue;
|
|
256
|
+
total += 1;
|
|
257
|
+
if (isLocalizedRoot(path))
|
|
258
|
+
hits += 1;
|
|
259
|
+
}
|
|
260
|
+
if (total === 0)
|
|
261
|
+
return 0;
|
|
262
|
+
return hits / total;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* v0.4.3-rc2 — localized-marketing detector. Stripe, Vercel, Linear, Cloudflare
|
|
266
|
+
* etc. publish each marketing page under multiple `/[lang]/` prefixes. Their
|
|
267
|
+
* sitemap looks like a programmatic directory to the size+cluster heuristic
|
|
268
|
+
* (10k+ URLs all matching `/:slug/:slug` after normalization), but they are
|
|
269
|
+
* NOT pSEO sites — they're high-quality marketing sites with i18n.
|
|
270
|
+
*
|
|
271
|
+
* Signal: ≥30% of URLs have a first segment that matches `/[a-z]{2}(-[a-z]{2})?/`.
|
|
272
|
+
* Returns small-marketing with 0.75 confidence (lower than ecommerce/docs
|
|
273
|
+
* because some localized pSEO directories DO exist — we'd rather under-classify
|
|
274
|
+
* here than mis-suppress real spam findings).
|
|
275
|
+
*/
|
|
276
|
+
function tryClassifyLocalizedMarketing(urls, signals) {
|
|
277
|
+
const ratio = localizedRatio(urls);
|
|
278
|
+
if (ratio < 0.3)
|
|
279
|
+
return null;
|
|
280
|
+
// Higher confidence when the locale prefix dominates AND the site isn't
|
|
281
|
+
// ALSO matching the docs/ecommerce shape underneath the locale (those
|
|
282
|
+
// would have caught it earlier — by reaching this point we know it's
|
|
283
|
+
// generic marketing).
|
|
284
|
+
let confidence = 0.75;
|
|
285
|
+
if (ratio >= 0.5)
|
|
286
|
+
confidence = 0.82;
|
|
287
|
+
if (ratio >= 0.7)
|
|
288
|
+
confidence = 0.88;
|
|
289
|
+
return {
|
|
290
|
+
type: "small-marketing",
|
|
291
|
+
confidence,
|
|
292
|
+
signals,
|
|
293
|
+
suppressedRules: [...PSEO_ONLY_RULE_IDS],
|
|
294
|
+
};
|
|
295
|
+
}
|
|
110
296
|
/**
|
|
111
297
|
* Classify a site from its URL list + framework signal. Pure function.
|
|
112
298
|
*
|
|
@@ -135,9 +321,36 @@ export function classifySite(input) {
|
|
|
135
321
|
if (urls.length === 0) {
|
|
136
322
|
return { type: "unclear", confidence: 0, signals, suppressedRules: [] };
|
|
137
323
|
}
|
|
324
|
+
// v0.4.3 — try the new high-confidence URL-shape detectors first. These
|
|
325
|
+
// override the legacy size-based heuristics when they fire because URL
|
|
326
|
+
// shape is a stronger signal than raw URL count. Order matters:
|
|
327
|
+
// 1. ecommerce — strongest signal first; /products/* and /collections/*
|
|
328
|
+
// are an extremely specific URL shape that doesn't occur elsewhere.
|
|
329
|
+
// 2. docs — /docs/*, /api/*, /reference/* are nearly as specific.
|
|
330
|
+
// 3. localized-marketing — /[lang]/ first segment indicates i18n marketing
|
|
331
|
+
// (stripe.com, vercel.com, etc.) which v0.4.3-rc1 mis-classified as
|
|
332
|
+
// programmatic-directory because the localized URL count tripped the
|
|
333
|
+
// ≥1000 URL + ≥60% top-3 cluster heuristic.
|
|
334
|
+
// After all three fail, fall through to the legacy size-clustering logic.
|
|
335
|
+
const ecommerce = tryClassifyEcommerce(urls, signals);
|
|
336
|
+
if (ecommerce)
|
|
337
|
+
return ecommerce;
|
|
338
|
+
const docs = tryClassifyDocs(urls, signals);
|
|
339
|
+
if (docs)
|
|
340
|
+
return docs;
|
|
341
|
+
const localized = tryClassifyLocalizedMarketing(urls, signals);
|
|
342
|
+
if (localized)
|
|
343
|
+
return localized;
|
|
138
344
|
// Step 4: synthesize.
|
|
139
345
|
let type = "unclear";
|
|
140
346
|
let confidence = 0;
|
|
347
|
+
// v0.4.3-rc3 — lowered programmatic-directory threshold from 1000 → 500
|
|
348
|
+
// after dogfood showed softschools.com (955 URLs, real pSEO directory)
|
|
349
|
+
// missing the cutoff and classifying as `unclear`. Rebalanced confidence:
|
|
350
|
+
// ≥ 1000 URLs + top3≥60% template ratio → 0.9
|
|
351
|
+
// ≥ 500 URLs + top3≥70% template ratio → 0.78 (slightly lower confidence
|
|
352
|
+
// because the smaller sample is noisier, but still well above the
|
|
353
|
+
// 0.7 profile-application cutoff)
|
|
141
354
|
if (urls.length >= 1000) {
|
|
142
355
|
if (top3Ratio >= 0.6) {
|
|
143
356
|
type = "programmatic-directory";
|
|
@@ -150,6 +363,10 @@ export function classifySite(input) {
|
|
|
150
363
|
confidence = 0.6;
|
|
151
364
|
}
|
|
152
365
|
}
|
|
366
|
+
else if (urls.length >= 500 && top3Ratio >= 0.7) {
|
|
367
|
+
type = "programmatic-directory";
|
|
368
|
+
confidence = 0.78;
|
|
369
|
+
}
|
|
153
370
|
else if (urls.length < 50) {
|
|
154
371
|
// Small site. Detect blog separately from generic small-marketing.
|
|
155
372
|
//
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"site-classifier.js","sourceRoot":"","sources":["../src/site-classifier.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"site-classifier.js","sourceRoot":"","sources":["../src/site-classifier.ts"],"names":[],"mappings":"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"}
|
package/dist/state.d.ts
CHANGED
|
@@ -1,16 +1,51 @@
|
|
|
1
|
-
export declare const STATE_SCHEMA_VERSION =
|
|
1
|
+
export declare const STATE_SCHEMA_VERSION = 2;
|
|
2
2
|
export type RenderMode = "static" | "rendered";
|
|
3
|
+
/**
|
|
4
|
+
* Permissive snapshot of a finding stored in state for carry-forward across
|
|
5
|
+
* delta runs. The canonical Finding type lives in types.ts; state intentionally
|
|
6
|
+
* accepts a wider shape so we can persist whatever fields the engine emitted at
|
|
7
|
+
* audit time without coupling state IO to the rule-result schema.
|
|
8
|
+
*/
|
|
9
|
+
export interface Finding {
|
|
10
|
+
id: string;
|
|
11
|
+
ruleId: string;
|
|
12
|
+
severity: string;
|
|
13
|
+
confidence: string;
|
|
14
|
+
message: string;
|
|
15
|
+
url?: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
3
18
|
export interface UrlStateEntry {
|
|
4
19
|
contentHash: string;
|
|
5
20
|
fetchedAt: string;
|
|
6
21
|
status: number;
|
|
22
|
+
/** Kept for back-compat within v2; derived from `findings`. */
|
|
7
23
|
findingIds: string[];
|
|
24
|
+
/** Full finding records persisted so unchanged URLs can carry findings forward. */
|
|
25
|
+
findings: Finding[];
|
|
26
|
+
/** Ruleset signature at the time this URL was last fetched. */
|
|
27
|
+
rulesetVersion: string;
|
|
28
|
+
/** HTTP `Last-Modified` response header captured at fetch. */
|
|
29
|
+
lastModified?: string;
|
|
30
|
+
/** HTTP `ETag` response header captured at fetch. */
|
|
31
|
+
etag?: string;
|
|
32
|
+
/** Sitemap `<lastmod>` value associated with this URL at the audit. */
|
|
33
|
+
sitemapLastmodAtAudit?: string;
|
|
34
|
+
gscMetricsAtLastRun?: {
|
|
35
|
+
impressions: number;
|
|
36
|
+
clicks: number;
|
|
37
|
+
period: string;
|
|
38
|
+
};
|
|
8
39
|
}
|
|
9
40
|
export interface RunState {
|
|
10
41
|
version: number;
|
|
11
42
|
lastRun: string;
|
|
43
|
+
/** ISO timestamp of the last full (non-delta) audit. */
|
|
44
|
+
lastFullAuditAt: string;
|
|
12
45
|
source: string;
|
|
13
46
|
renderMode: RenderMode;
|
|
47
|
+
/** Ruleset signature at the time this state file was written. */
|
|
48
|
+
rulesetVersion: string;
|
|
14
49
|
urls: Record<string, UrlStateEntry>;
|
|
15
50
|
summary: {
|
|
16
51
|
score: number;
|
package/dist/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mFAAmF;IACnF,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpC,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACpC,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAgCtE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7E"}
|
package/dist/state.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readFile, writeFile, mkdir, rename } from "node:fs/promises";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
|
-
export const STATE_SCHEMA_VERSION =
|
|
4
|
+
export const STATE_SCHEMA_VERSION = 2;
|
|
5
5
|
/**
|
|
6
6
|
* Normalize HTML so content hashing is stable across irrelevant diffs.
|
|
7
7
|
*
|
|
@@ -47,8 +47,10 @@ export async function readState(path) {
|
|
|
47
47
|
throw new Error(`unsupported state version ${state.version} at ${path}, expected ${STATE_SCHEMA_VERSION}`);
|
|
48
48
|
}
|
|
49
49
|
if (typeof state.lastRun !== "string" ||
|
|
50
|
+
typeof state.lastFullAuditAt !== "string" ||
|
|
50
51
|
typeof state.source !== "string" ||
|
|
51
52
|
typeof state.renderMode !== "string" ||
|
|
53
|
+
typeof state.rulesetVersion !== "string" ||
|
|
52
54
|
!state.urls || typeof state.urls !== "object" ||
|
|
53
55
|
!state.summary || typeof state.summary !== "object") {
|
|
54
56
|
throw new Error(`state file at ${path} has malformed shape`);
|