@cogenta/seo 0.2.0 → 0.3.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.
@@ -0,0 +1,33 @@
1
+ import { queryTokens } from '@cogenta/schema';
2
+ export type ContentCheckId = 'keywordInTitle' | 'keywordInDescription' | 'keywordInFirstSentence' | 'keywordDensity' | 'sentenceLength' | 'subheadings' | 'contentLength';
3
+ export interface ContentCheck {
4
+ readonly id: ContentCheckId;
5
+ readonly passed: boolean;
6
+ /**
7
+ * A number a caller may want to render next to the check
8
+ * (`keywordDensity`'s percentage, `sentenceLength`'s longest sentence word
9
+ * count, `contentLength`'s word count) — never itself the score, and never
10
+ * shown with false precision by this file (a caller renders it as an
11
+ * integer, not a decimal).
12
+ */
13
+ readonly detail?: number;
14
+ }
15
+ export type ContentScoreLevel = 'red' | 'orange' | 'green';
16
+ export interface ContentAnalysisInput {
17
+ readonly title: string;
18
+ readonly description?: string;
19
+ /** Empty/absent skips the four keyword-dependent checks — see this file's own module comment. */
20
+ readonly focusKeyword?: string;
21
+ /** A contract-A rich text document (`RichTextDocument`-shaped), or anything else — parsed defensively, like `extractRichText`. */
22
+ readonly body: unknown;
23
+ }
24
+ export interface ContentAnalysisResult {
25
+ readonly checks: readonly ContentCheck[];
26
+ readonly score: ContentScoreLevel;
27
+ readonly passedCount: number;
28
+ readonly totalCount: number;
29
+ }
30
+ export declare function analyseContent(input: ContentAnalysisInput): ContentAnalysisResult;
31
+ /** `queryTokens` re-exported for callers that want the same word-matching Cogenta's search already uses on top of a raw analysis result — not used internally by `analyseContent` itself, kept here only so a consumer never has to add its own `@cogenta/schema` dependency just to tokenize a suggestion. */
32
+ export { queryTokens };
33
+ //# sourceMappingURL=content-analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-analysis.d.ts","sourceRoot":"","sources":["../src/content-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAiJjE,MAAM,MAAM,cAAc,GACtB,gBAAgB,GAChB,sBAAsB,GACtB,wBAAwB,GACxB,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,eAAe,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,iGAAiG;IACjG,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,kIAAkI;IAClI,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAUD,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CA0DjF;AAED,+SAA+S;AAC/S,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,141 @@
1
+ import { condense, foldText, queryTokens } from '@cogenta/schema';
2
+ function isRecord(value) {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ }
5
+ /** Contract A's `RICH_TEXT_STYLES` minus `'normal'`/`'blockquote'` — the two that read as a subheading in an outline. Duplicated rather than imported from `@cogenta/schema`'s `rich-text.ts` (`RICH_TEXT_STYLES`): importing three literals is not worth a dependency edge this file does not otherwise need, the same call `seo.tsx`'s own `ROBOTS_DISALLOW_ALL_PATTERN` comment makes for a one-regex duplication. */
6
+ const HEADING_STYLES = new Set(['h2', 'h3', 'h4']);
7
+ function textOf(node) {
8
+ const children = node.children;
9
+ if (!Array.isArray(children))
10
+ return '';
11
+ const parts = [];
12
+ for (const child of children) {
13
+ if (!isRecord(child))
14
+ continue;
15
+ const span = child;
16
+ if (typeof span.text === 'string')
17
+ parts.push(span.text);
18
+ }
19
+ return parts.join('');
20
+ }
21
+ /** Defensively `unknown`, like `extractRichText` — an entry mid-edit in the admin can hold anything the editor has not saved yet. */
22
+ function parseBody(body) {
23
+ if (!Array.isArray(body))
24
+ return { blocks: [], headingCount: 0 };
25
+ const blocks = [];
26
+ let headingCount = 0;
27
+ for (const node of body) {
28
+ if (!isRecord(node) || node._type !== 'block')
29
+ continue;
30
+ const block = node;
31
+ const text = condense(textOf(block));
32
+ if (text.length === 0)
33
+ continue;
34
+ const heading = typeof block.style === 'string' && HEADING_STYLES.has(block.style);
35
+ blocks.push({ text, heading });
36
+ if (heading)
37
+ headingCount += 1;
38
+ }
39
+ return { blocks, headingCount };
40
+ }
41
+ /** Words per sentence beyond which a sentence is flagged — Yoast's own published readability threshold (20 words), the closest thing this space has to an industry convention. */
42
+ const MAX_SENTENCE_WORDS = 20;
43
+ /** Below this, an article is short enough that going without a subheading is not itself a problem — `subheadings` is skipped rather than failed. */
44
+ const SHORT_CONTENT_WORDS = 300;
45
+ /** The minimum word count `contentLength` asks for — the same 300-word floor most of these tools converge on for "a real article", not a Cogenta invention. */
46
+ const MIN_CONTENT_WORDS = 300;
47
+ /** Keyword density band `keywordDensity` passes within, expressed as a percentage of total words — TruSEO's own published target range. Below it reads as "barely used"; above it reads as stuffing. */
48
+ const MIN_KEYWORD_DENSITY = 0.5;
49
+ const MAX_KEYWORD_DENSITY = 2.5;
50
+ const SENTENCE_SPLIT_PATTERN = /[^.!?]+[.!?]*/gu;
51
+ function sentencesOf(text) {
52
+ return (text.match(SENTENCE_SPLIT_PATTERN) ?? [])
53
+ .map((sentence) => sentence.trim())
54
+ .filter((sentence) => sentence.length > 0);
55
+ }
56
+ function wordCountOf(text) {
57
+ return text.trim() === '' ? 0 : text.trim().split(/\s+/u).length;
58
+ }
59
+ /** First sentence of the first *prose* block — a heading is not a sentence, so it is skipped in favour of the first `'normal'`/`'blockquote'` block, falling back to the very first block at all when the body is nothing but headings. */
60
+ function firstSentenceOf(blocks) {
61
+ const first = blocks.find((block) => !block.heading) ?? blocks[0];
62
+ if (first === undefined)
63
+ return '';
64
+ const sentences = sentencesOf(first.text);
65
+ return sentences[0] ?? first.text;
66
+ }
67
+ /** How many times `needle` occurs in `haystack`, both already folded — a plain substring count, not a word-boundary regex, so a multi-word keyword phrase ("guide de voyage") is counted as one unit exactly as `foldText`/`queryTokens` already treat phrases in `@cogenta/schema`'s own search layer. */
68
+ function occurrencesOf(haystack, needle) {
69
+ if (needle === '')
70
+ return 0;
71
+ let count = 0;
72
+ let index = haystack.indexOf(needle);
73
+ while (index !== -1) {
74
+ count += 1;
75
+ index = haystack.indexOf(needle, index + needle.length);
76
+ }
77
+ return count;
78
+ }
79
+ function scoreFor(passedCount, totalCount) {
80
+ if (totalCount === 0)
81
+ return 'red';
82
+ const ratio = passedCount / totalCount;
83
+ if (ratio >= 0.8)
84
+ return 'green';
85
+ if (ratio >= 0.5)
86
+ return 'orange';
87
+ return 'red';
88
+ }
89
+ export function analyseContent(input) {
90
+ const { blocks, headingCount } = parseBody(input.body);
91
+ const bodyText = condense(blocks.map((block) => block.text).join(' '));
92
+ const wordCount = wordCountOf(bodyText);
93
+ const checks = [];
94
+ const focusKeyword = (input.focusKeyword ?? '').trim();
95
+ if (focusKeyword !== '') {
96
+ const foldedKeyword = foldText(focusKeyword);
97
+ checks.push({
98
+ id: 'keywordInTitle',
99
+ passed: foldText(input.title).includes(foldedKeyword),
100
+ });
101
+ checks.push({
102
+ id: 'keywordInDescription',
103
+ passed: input.description !== undefined && foldText(input.description).includes(foldedKeyword),
104
+ });
105
+ checks.push({
106
+ id: 'keywordInFirstSentence',
107
+ passed: foldText(firstSentenceOf(blocks)).includes(foldedKeyword),
108
+ });
109
+ const foldedBody = foldText(bodyText);
110
+ const occurrences = occurrencesOf(foldedBody, foldedKeyword);
111
+ const density = wordCount === 0 ? 0 : (occurrences / wordCount) * 100;
112
+ checks.push({
113
+ id: 'keywordDensity',
114
+ passed: density >= MIN_KEYWORD_DENSITY && density <= MAX_KEYWORD_DENSITY,
115
+ detail: Math.round(density * 10) / 10,
116
+ });
117
+ }
118
+ const sentenceLengths = sentencesOf(bodyText).map(wordCountOf);
119
+ const longestSentence = sentenceLengths.length === 0 ? 0 : Math.max(...sentenceLengths);
120
+ checks.push({
121
+ id: 'sentenceLength',
122
+ passed: longestSentence <= MAX_SENTENCE_WORDS,
123
+ detail: longestSentence,
124
+ });
125
+ checks.push({
126
+ id: 'subheadings',
127
+ passed: wordCount < SHORT_CONTENT_WORDS || headingCount > 0,
128
+ detail: headingCount,
129
+ });
130
+ checks.push({
131
+ id: 'contentLength',
132
+ passed: wordCount >= MIN_CONTENT_WORDS,
133
+ detail: wordCount,
134
+ });
135
+ const passedCount = checks.filter((check) => check.passed).length;
136
+ const totalCount = checks.length;
137
+ return { checks, score: scoreFor(passedCount, totalCount), passedCount, totalCount };
138
+ }
139
+ /** `queryTokens` re-exported for callers that want the same word-matching Cogenta's search already uses on top of a raw analysis result — not used internally by `analyseContent` itself, kept here only so a consumer never has to add its own `@cogenta/schema` dependency just to tokenize a suggestion. */
140
+ export { queryTokens };
141
+ //# sourceMappingURL=content-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-analysis.js","sourceRoot":"","sources":["../src/content-analysis.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -15,23 +15,29 @@
15
15
  * ping, and never touches the database — it is safe inside the render sandbox
16
16
  * (rule R5).
17
17
  */
18
+ export type { ContentAnalysisInput, ContentAnalysisResult, ContentCheck, ContentCheckId, ContentScoreLevel, } from './content-analysis.js';
19
+ export { analyseContent } from './content-analysis.js';
18
20
  export type { FeedInput, FeedItem, FeedItemsOptions } from './feeds.js';
19
21
  export { feedItemsFor, renderAtomFeed, renderRssFeed, toRfc822 } from './feeds.js';
20
22
  export type { HreflangAlternate, TranslationFamily } from './hreflang.js';
21
23
  export { alternatesFor, buildHreflangMap, groupTranslationFamilies } from './hreflang.js';
22
24
  export type { IndexableOptions } from './indexable.js';
23
- export { indexableResources, isIndexable, isPublished } from './indexable.js';
25
+ export { indexableResources, isIndexable, isPublished, isSeoNoindexed } from './indexable.js';
24
26
  export type { IndexNowFetch, IndexNowOptions, IndexNowResult } from './indexnow.js';
25
27
  export { INDEXNOW_MAX_URLS, indexNowKeyFile, pingIndexNow } from './indexnow.js';
26
28
  export type { JsonLdObject, JsonLdOptions, JsonLdValue } from './json-ld.js';
27
29
  export { buildJsonLd, renderJsonLdScript, schemaTypeFor } from './json-ld.js';
30
+ export type { LinkAssistantReport, LinkSuggestion, OrphanEntry } from './link-assistant.js';
31
+ export { analyseInternalLinks } from './link-assistant.js';
28
32
  export type { LlmsTxtLink, LlmsTxtOptions, LlmsTxtSection, LlmsTxtSectionsOptions, } from './llms-txt.js';
29
33
  export { llmsTxtSectionsFor, renderLlmsTxt } from './llms-txt.js';
30
34
  export type { MetadataOptions, MetaTag } from './metadata.js';
31
35
  export { buildMetaTags, escapeHtmlAttribute, escapeHtmlText, renderMetaTags, } from './metadata.js';
32
36
  export type { RobotsGroup, RobotsOptions } from './robots.js';
33
- export { renderRobotsTxt } from './robots.js';
34
- export type { ChangeFrequency, SitemapFile, SitemapOptions, SitemapUrl } from './sitemap.js';
37
+ export { renderRobotsTxt, robotsRuleDisallowsEverything } from './robots.js';
38
+ export type { SearchAnalyticsQueryOptions, SearchConsoleFetch, SearchConsoleMetricsRow, SearchConsoleOAuthOptions, SearchConsoleTokens, } from './search-console.js';
39
+ export { buildAuthorizationUrl, exchangeAuthorizationCode, fetchSearchAnalytics, refreshAccessToken, } from './search-console.js';
40
+ export type { ChangeFrequency, SitemapCollectionOverride, SitemapFile, SitemapOptions, SitemapUrl, } from './sitemap.js';
35
41
  export { buildSitemap, SITEMAP_MAX_BYTES, SITEMAP_MAX_URLS, sitemapUrlsFor, } from './sitemap.js';
36
42
  export type { SeoImage, SeoReference, SeoResolvers, SeoResource, SeoSite } from './types.js';
37
43
  export { absoluteUrl, canonicalUrl, hasRoute, normaliseBaseUrl, routeParams } from './url.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAClF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AACzF,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7E,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAChF,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC7E,YAAY,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,sBAAsB,GACvB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACjE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC5F,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC5F,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7F,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAClF,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AACzF,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC7F,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAChF,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC7E,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,YAAY,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,sBAAsB,GACvB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACjE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAA;AAC5E,YAAY,EACV,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EACV,eAAe,EACf,yBAAyB,EACzB,WAAW,EACX,cAAc,EACd,UAAU,GACX,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC5F,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7F,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,UAAU,CAAA"}
package/dist/index.js CHANGED
@@ -15,14 +15,17 @@
15
15
  * ping, and never touches the database — it is safe inside the render sandbox
16
16
  * (rule R5).
17
17
  */
18
+ export { analyseContent } from './content-analysis.js';
18
19
  export { feedItemsFor, renderAtomFeed, renderRssFeed, toRfc822 } from './feeds.js';
19
20
  export { alternatesFor, buildHreflangMap, groupTranslationFamilies } from './hreflang.js';
20
- export { indexableResources, isIndexable, isPublished } from './indexable.js';
21
+ export { indexableResources, isIndexable, isPublished, isSeoNoindexed } from './indexable.js';
21
22
  export { INDEXNOW_MAX_URLS, indexNowKeyFile, pingIndexNow } from './indexnow.js';
22
23
  export { buildJsonLd, renderJsonLdScript, schemaTypeFor } from './json-ld.js';
24
+ export { analyseInternalLinks } from './link-assistant.js';
23
25
  export { llmsTxtSectionsFor, renderLlmsTxt } from './llms-txt.js';
24
26
  export { buildMetaTags, escapeHtmlAttribute, escapeHtmlText, renderMetaTags, } from './metadata.js';
25
- export { renderRobotsTxt } from './robots.js';
27
+ export { renderRobotsTxt, robotsRuleDisallowsEverything } from './robots.js';
28
+ export { buildAuthorizationUrl, exchangeAuthorizationCode, fetchSearchAnalytics, refreshAccessToken, } from './search-console.js';
26
29
  export { buildSitemap, SITEMAP_MAX_BYTES, SITEMAP_MAX_URLS, sitemapUrlsFor, } from './sitemap.js';
27
30
  export { absoluteUrl, canonicalUrl, hasRoute, normaliseBaseUrl, routeParams } from './url.js';
28
31
  export { escapeXmlAttribute, escapeXmlText, renderXmlDocument, renderXmlElement, stripIllegalXmlChars, } from './xml.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAElF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE7E,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEhF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAO7E,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEjE,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE7F,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAElF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AAEzF,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE7F,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEhF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAO1D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEjE,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,GACf,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,eAAe,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAA;AAQ5E,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAQ5B,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE7F,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,UAAU,CAAA"}
@@ -16,7 +16,18 @@ export interface IndexableOptions {
16
16
  }
17
17
  export declare function isPublished(entry: ContentEntry, options?: IndexableOptions): boolean;
18
18
  /**
19
- * Published **and** reachable at a URL.
19
+ * Whether a collection declares the conventional `seoNoindex` override field
20
+ * (fiche 13, Task 0 § decision (a) — an ordinary boolean field, never a
21
+ * contract A addition) and this entry has it switched on.
22
+ *
23
+ * Reading it here, in the one gate every output already goes through, is what
24
+ * makes the pitfall this fiche names explicit unavoidable: a page that carries
25
+ * `noindex` in its `<head>` and still lists itself in `/sitemap.xml` is asking
26
+ * a crawler to ignore a URL it is handed in the same breath.
27
+ */
28
+ export declare function isSeoNoindexed(resource: SeoResource): boolean;
29
+ /**
30
+ * Published, not marked `seoNoindex`, and reachable at a URL.
20
31
  *
21
32
  * A published entry in a collection with no `routing` has nothing to put in a
22
33
  * sitemap, and an entry whose route parameters are incomplete — a slug that was
@@ -1 +1 @@
1
- {"version":3,"file":"indexable.d.ts","sourceRoot":"","sources":["../src/indexable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGtD;;;;;;;;;GASG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CACpB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAiCxF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAGT;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,OAAO,GAAE,gBAAqB,GAC7B,SAAS,WAAW,EAAE,CAExB"}
1
+ {"version":3,"file":"indexable.d.ts","sourceRoot":"","sources":["../src/indexable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGtD;;;;;;;;;GASG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CACpB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAiCxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAI7D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAIT;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,OAAO,GAAE,gBAAqB,GAC7B,SAAS,WAAW,EAAE,CAExB"}
package/dist/indexable.js CHANGED
@@ -34,7 +34,23 @@ export function isPublished(entry, options = {}) {
34
34
  return at <= (options.now ?? new Date()).getTime();
35
35
  }
36
36
  /**
37
- * Published **and** reachable at a URL.
37
+ * Whether a collection declares the conventional `seoNoindex` override field
38
+ * (fiche 13, Task 0 § decision (a) — an ordinary boolean field, never a
39
+ * contract A addition) and this entry has it switched on.
40
+ *
41
+ * Reading it here, in the one gate every output already goes through, is what
42
+ * makes the pitfall this fiche names explicit unavoidable: a page that carries
43
+ * `noindex` in its `<head>` and still lists itself in `/sitemap.xml` is asking
44
+ * a crawler to ignore a URL it is handed in the same breath.
45
+ */
46
+ export function isSeoNoindexed(resource) {
47
+ const field = resource.collection.fields.seoNoindex;
48
+ if (field === undefined || field.kind !== 'boolean')
49
+ return false;
50
+ return resource.entry.values.seoNoindex === true;
51
+ }
52
+ /**
53
+ * Published, not marked `seoNoindex`, and reachable at a URL.
38
54
  *
39
55
  * A published entry in a collection with no `routing` has nothing to put in a
40
56
  * sitemap, and an entry whose route parameters are incomplete — a slug that was
@@ -43,6 +59,8 @@ export function isPublished(entry, options = {}) {
43
59
  export function isIndexable(site, resource, options = {}) {
44
60
  if (!isPublished(resource.entry, options))
45
61
  return false;
62
+ if (isSeoNoindexed(resource))
63
+ return false;
46
64
  return canonicalUrl(site, resource) !== null;
47
65
  }
48
66
  /** The indexable subset of a list, in the order given. */
@@ -1 +1 @@
1
- {"version":3,"file":"indexable.js","sourceRoot":"","sources":["../src/indexable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAkBvC,MAAM,UAAU,WAAW,CAAC,KAAmB,EAAE,OAAO,GAAqB,EAAE;IAC7E,0EAA0E;IAC1E,yEAAyE;IACzE,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAE9C,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,0CAA0C;IAC1C,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAE7C,mEAAmE;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,0EAA0E;IAC1E,uEAAuE;IACvE,6EAA6E;IAC7E,0EAA0E;IAC1E,wDAAwD;IACxD,EAAE;IACF,yEAAyE;IACzE,4EAA4E;IAC5E,6EAA6E;IAC7E,2CAA2C;IAC3C,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAE3C,4EAA4E;IAC5E,6EAA6E;IAC7E,cAAc;IACd,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAA;IAElC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAa,EACb,QAAqB,EACrB,OAAO,GAAqB,EAAE;IAE9B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,OAAO,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAA;AAC9C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAChC,IAAa,EACb,SAAiC,EACjC,OAAO,GAAqB,EAAE;IAE9B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;AAC7E,CAAC"}
1
+ {"version":3,"file":"indexable.js","sourceRoot":"","sources":["../src/indexable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAkBvC,MAAM,UAAU,WAAW,CAAC,KAAmB,EAAE,OAAO,GAAqB,EAAE;IAC7E,0EAA0E;IAC1E,yEAAyE;IACzE,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAE9C,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,0CAA0C;IAC1C,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IAE7C,mEAAmE;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,0EAA0E;IAC1E,uEAAuE;IACvE,6EAA6E;IAC7E,0EAA0E;IAC1E,wDAAwD;IACxD,EAAE;IACF,yEAAyE;IACzE,4EAA4E;IAC5E,6EAA6E;IAC7E,2CAA2C;IAC3C,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAE3C,4EAA4E;IAC5E,6EAA6E;IAC7E,cAAc;IACd,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAA;IAElC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA;AACpD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,QAAqB;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAA;IACnD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACjE,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,KAAK,IAAI,CAAA;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAa,EACb,QAAqB,EACrB,OAAO,GAAqB,EAAE;IAE9B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1C,OAAO,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAA;AAC9C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAChC,IAAa,EACb,SAAiC,EACjC,OAAO,GAAqB,EAAE;IAE9B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;AAC7E,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { SeoResource } from './types.js';
2
+ /**
3
+ * Internal link assistant (fiche 70, task 2) — AIOSEO's Link Assistant,
4
+ * without the "recommandation IA" framing: this file finds **candidates**
5
+ * from real, already-published content, never invents an anchor or writes
6
+ * anything (R6 — a suggestion is displayed, never applied automatically; see
7
+ * this file's own test for the orphan/candidate boundary).
8
+ *
9
+ * **Reuses the graph contract A already lets you build.** `extractLinks`
10
+ * (`@cogenta/schema`) was written for the broken-link crawler (L14 task 3)
11
+ * and already walks every shape a link can take — a rich-text `markDefs`
12
+ * `internalLink`, a contract-B action `target`, a plain `url` field — so this
13
+ * file adds nothing new to what counts as "a link"; it only asks a different
14
+ * question of the same graph: not "does this lead somewhere real" but "does
15
+ * anything lead *here*".
16
+ *
17
+ * **Pure, and deliberately not a crawler of its own.** `@cogenta/seo` never
18
+ * touches a database (see this package's own `index.ts` module comment,
19
+ * rule R5) — the caller (`createSeoRouter`'s new `GET
20
+ * /api/seo/link-suggestions` route) does the actual reading through the
21
+ * permission-checked gateway and hands this file the resulting resources, the
22
+ * same shape `SeoDiagnostics` itself is built from.
23
+ */
24
+ export interface OrphanEntry {
25
+ readonly collection: string;
26
+ readonly id: string;
27
+ readonly title: string;
28
+ }
29
+ export interface LinkSuggestion {
30
+ readonly collection: string;
31
+ readonly id: string;
32
+ readonly title: string;
33
+ /** How many meaningful title words this candidate shares with the subject entry — a ranking signal, never a score shown as a percentage (the same "no false precision" rule `content-analysis.ts` follows). */
34
+ readonly sharedWordCount: number;
35
+ }
36
+ export interface LinkAssistantReport {
37
+ readonly orphans: readonly OrphanEntry[];
38
+ /** Up to five candidates per entry, keyed by `"collection/id"`. An entry with no plausible candidate is simply absent from the map. */
39
+ readonly suggestionsByEntry: ReadonlyMap<string, readonly LinkSuggestion[]>;
40
+ }
41
+ /**
42
+ * Every published, routed resource this site has (across every collection,
43
+ * not only the one an admin is looking at) is what makes "orphan" mean
44
+ * something real: an entry linked only from a *different* collection's page
45
+ * — a homepage's "Latest article" block, say — must not be reported as
46
+ * orphaned just because nothing in its own collection happens to link it.
47
+ * The caller narrows which entries are *reported* to one collection; the
48
+ * graph itself is never narrowed, or the answer would lie.
49
+ */
50
+ export declare function analyseInternalLinks(resources: readonly SeoResource[]): LinkAssistantReport;
51
+ //# sourceMappingURL=link-assistant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-assistant.d.ts","sourceRoot":"","sources":["../src/link-assistant.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+MAA+M;IAC/M,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAA;IACxC,uIAAuI;IACvI,QAAQ,CAAC,kBAAkB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC,CAAA;CAC5E;AAQD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,WAAW,EAAE,GAAG,mBAAmB,CAuE3F"}
@@ -0,0 +1,80 @@
1
+ import { extractLinks, queryTokens, titleOf } from '@cogenta/schema';
2
+ const MAX_SUGGESTIONS = 5;
3
+ function keyOf(collection, id) {
4
+ return `${collection}/${id}`;
5
+ }
6
+ /**
7
+ * Every published, routed resource this site has (across every collection,
8
+ * not only the one an admin is looking at) is what makes "orphan" mean
9
+ * something real: an entry linked only from a *different* collection's page
10
+ * — a homepage's "Latest article" block, say — must not be reported as
11
+ * orphaned just because nothing in its own collection happens to link it.
12
+ * The caller narrows which entries are *reported* to one collection; the
13
+ * graph itself is never narrowed, or the answer would lie.
14
+ */
15
+ export function analyseInternalLinks(resources) {
16
+ const known = new Set(resources.map((resource) => keyOf(resource.collection.name, resource.entry.id)));
17
+ const inbound = new Set();
18
+ for (const resource of resources) {
19
+ const from = keyOf(resource.collection.name, resource.entry.id);
20
+ for (const link of extractLinks(resource.entry)) {
21
+ if (link.kind !== 'entry')
22
+ continue;
23
+ const target = keyOf(link.collection, link.id);
24
+ // A page linking to itself does not un-orphan it — the question this
25
+ // report answers is "does anything *else* lead here".
26
+ if (target === from)
27
+ continue;
28
+ if (known.has(target))
29
+ inbound.add(target);
30
+ }
31
+ }
32
+ const orphans = [];
33
+ for (const resource of resources) {
34
+ const key = keyOf(resource.collection.name, resource.entry.id);
35
+ if (inbound.has(key))
36
+ continue;
37
+ orphans.push({
38
+ collection: resource.collection.name,
39
+ id: resource.entry.id,
40
+ title: titleOf(resource.collection, resource.entry),
41
+ });
42
+ }
43
+ const byCollection = new Map();
44
+ for (const resource of resources) {
45
+ const list = byCollection.get(resource.collection.name);
46
+ if (list === undefined)
47
+ byCollection.set(resource.collection.name, [resource]);
48
+ else
49
+ list.push(resource);
50
+ }
51
+ const suggestionsByEntry = new Map();
52
+ for (const resource of resources) {
53
+ const subjectTitle = titleOf(resource.collection, resource.entry);
54
+ const subjectWords = new Set(queryTokens(subjectTitle));
55
+ if (subjectWords.size === 0)
56
+ continue;
57
+ const siblings = byCollection.get(resource.collection.name) ?? [];
58
+ const candidates = [];
59
+ for (const sibling of siblings) {
60
+ if (sibling.entry.id === resource.entry.id)
61
+ continue;
62
+ const siblingTitle = titleOf(sibling.collection, sibling.entry);
63
+ const sharedWordCount = new Set(queryTokens(siblingTitle).filter((word) => subjectWords.has(word))).size;
64
+ if (sharedWordCount === 0)
65
+ continue;
66
+ candidates.push({
67
+ collection: sibling.collection.name,
68
+ id: sibling.entry.id,
69
+ title: siblingTitle,
70
+ sharedWordCount,
71
+ });
72
+ }
73
+ candidates.sort((a, b) => b.sharedWordCount - a.sharedWordCount || a.title.localeCompare(b.title));
74
+ if (candidates.length > 0) {
75
+ suggestionsByEntry.set(keyOf(resource.collection.name, resource.entry.id), candidates.slice(0, MAX_SUGGESTIONS));
76
+ }
77
+ }
78
+ return { orphans, suggestionsByEntry };
79
+ }
80
+ //# sourceMappingURL=link-assistant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-assistant.js","sourceRoot":"","sources":["../src/link-assistant.ts"],"names":[],"mappings":"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"}
@@ -32,7 +32,7 @@ export interface MetadataOptions extends IndexableOptions {
32
32
  readonly resolvers?: SeoResolvers;
33
33
  /** The family's alternates, from `buildHreflangMap`. */
34
34
  readonly alternates?: readonly HreflangAlternate[];
35
- /** Overrides the derived title. */
35
+ /** Overrides the derived title, and the entry's own `seoTitle` field. Used for pages that are not one entry. */
36
36
  readonly title?: string;
37
37
  readonly description?: string;
38
38
  /** Overrides the derived social image. */
@@ -43,6 +43,24 @@ export interface MetadataOptions extends IndexableOptions {
43
43
  */
44
44
  readonly noindex?: boolean;
45
45
  readonly types?: Readonly<Record<string, string>>;
46
+ /**
47
+ * `%title% — %site%`-style template applied to a **derived** title (fiche
48
+ * 13, Task 3). Never applied to an explicit `seoTitle` override or to
49
+ * `options.title`: an editor who types a full SEO title, or a caller who
50
+ * passes one in, means it verbatim — the admin's own character counter
51
+ * counts exactly what was typed, and a silently appended suffix would make
52
+ * that counter lie.
53
+ */
54
+ readonly titleTemplate?: string;
55
+ /** `titleTemplate`, keyed by collection name. Takes precedence over `titleTemplate` when both apply. */
56
+ readonly collectionTitleTemplates?: Readonly<Record<string, string>>;
57
+ /**
58
+ * Used only when neither `options.image` nor the resource's own
59
+ * `seoImage`/first `media` field resolves to anything — a site-wide
60
+ * default social card (fiche 21 task 3's "Réseaux sociaux" tab), never a
61
+ * per-entry override. A page that has its own image always wins.
62
+ */
63
+ readonly fallbackImage?: SeoImage;
46
64
  }
47
65
  export declare function buildMetaTags(site: SeoSite, resource: SeoResource, options?: MetadataOptions): readonly MetaTag[];
48
66
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGtD,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAG9E;;;;;;;;;GASG;AAEH,MAAM,MAAM,OAAO,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClF;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAErD,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,YAAY,CAAA;IACjC,wDAAwD;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAClD,mCAAmC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAClD;AAwDD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,eAAoB,GAC5B,SAAS,OAAO,EAAE,CA6GpB;AAUD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAkBD,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAE/D"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGtD,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAG9E;;;;;;;;;GASG;AAEH,MAAM,MAAM,OAAO,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClF;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAErD,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,YAAY,CAAA;IACjC,wDAAwD;IACxD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAClD,gHAAgH;IAChH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjD;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,wGAAwG;IACxG,QAAQ,CAAC,wBAAwB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAA;CAClC;AAmHD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,eAAoB,GAC5B,SAAS,OAAO,EAAE,CAgIpB;AAUD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAkBD,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAE/D"}
package/dist/metadata.js CHANGED
@@ -1,9 +1,20 @@
1
1
  import { condense } from '@cogenta/schema';
2
- import { isPublished } from './indexable.js';
2
+ import { isPublished, isSeoNoindexed } from './indexable.js';
3
3
  import { schemaTypeFor } from './json-ld.js';
4
- import { canonicalUrl } from './url.js';
4
+ import { absoluteUrl, canonicalUrl } from './url.js';
5
5
  const TITLE_FIELDS = ['title', 'name', 'label', 'heading'];
6
6
  const DESCRIPTION_FIELDS = ['excerpt', 'description', 'summary', 'subtitle', 'teaser'];
7
+ /**
8
+ * The conventional SEO override fields (fiche 13, Task 0 § decision (a)).
9
+ *
10
+ * Checked *before* the derived candidates above, and only ever matched when
11
+ * the collection actually declares a field of this name — an ordinary field
12
+ * a site's own schema adds, never a contract A addition. A collection that
13
+ * does not declare `seoTitle` behaves exactly as it did before this fiche.
14
+ */
15
+ const SEO_TITLE_FIELDS = ['seoTitle'];
16
+ const SEO_DESCRIPTION_FIELDS = ['seoDescription'];
17
+ const SEO_IMAGE_FIELDS = ['seoImage'];
7
18
  /** Google truncates a description near 160 characters; longer is wasted bytes. */
8
19
  const MAX_DESCRIPTION = 160;
9
20
  function pickString(resource, candidates) {
@@ -23,10 +34,34 @@ function truncate(value, limit) {
23
34
  const lastSpace = cut.lastIndexOf(' ');
24
35
  return `${(lastSpace > limit / 2 ? cut.slice(0, lastSpace) : cut).trimEnd()}…`;
25
36
  }
37
+ /**
38
+ * The `titleTemplate` in force for this collection: a per-collection override
39
+ * first, then the site-wide default, `undefined` for neither.
40
+ */
41
+ function titleTemplateFor(resource, options) {
42
+ return options.collectionTitleTemplates?.[resource.collection.name] ?? options.titleTemplate;
43
+ }
44
+ /** `%title%` and `%site%`, the only two tokens the template understands. */
45
+ function applyTitleTemplate(raw, site, template) {
46
+ if (template === undefined)
47
+ return raw;
48
+ return template.replaceAll('%title%', raw).replaceAll('%site%', site.name);
49
+ }
26
50
  function firstImage(resource, resolvers) {
27
51
  const resolve = resolvers?.media;
28
52
  if (resolve === undefined)
29
53
  return undefined;
54
+ for (const name of SEO_IMAGE_FIELDS) {
55
+ if (resource.collection.fields[name] === undefined)
56
+ continue;
57
+ const value = resource.entry.values[name];
58
+ const id = Array.isArray(value) ? value[0] : value;
59
+ if (typeof id !== 'string' || id.length === 0)
60
+ continue;
61
+ const image = resolve(id);
62
+ if (image !== null)
63
+ return image;
64
+ }
30
65
  for (const [name, field] of Object.entries(resource.collection.fields)) {
31
66
  if (field.kind !== 'media')
32
67
  continue;
@@ -40,6 +75,30 @@ function firstImage(resource, resolvers) {
40
75
  }
41
76
  return undefined;
42
77
  }
78
+ /**
79
+ * A manually set canonical URL (fiche 13, Task 1's "advanced, collapsed"
80
+ * field), or `null` for "let `canonicalUrl` derive it from routing".
81
+ *
82
+ * Scoped deliberately narrow: it changes the `<link rel="canonical">` this
83
+ * page itself renders (and, with it, `og:url`), but never what `sitemapUrlsFor`
84
+ * lists or what `buildJsonLd` names as `@id` — the same trade-off Yoast makes,
85
+ * and the honest one here too, since resolving "which other resource does
86
+ * this alias" is a real cross-reference this convention does not attempt.
87
+ */
88
+ function canonicalOverrideOf(resource, site) {
89
+ const field = resource.collection.fields.seoCanonical;
90
+ if (field === undefined || field.kind !== 'text')
91
+ return null;
92
+ const value = resource.entry.values.seoCanonical;
93
+ if (typeof value !== 'string')
94
+ return null;
95
+ const trimmed = value.trim();
96
+ if (trimmed.length === 0)
97
+ return null;
98
+ if (/^https?:\/\//u.test(trimmed))
99
+ return trimmed;
100
+ return absoluteUrl(site, trimmed.startsWith('/') ? trimmed : `/${trimmed}`);
101
+ }
43
102
  /**
44
103
  * Open Graph's `og:type` vocabulary is not schema.org's, and it is tiny:
45
104
  * `article`, `profile`, `website`, `book`, plus the music and video families.
@@ -59,20 +118,36 @@ function openGraphType(schemaType) {
59
118
  }
60
119
  export function buildMetaTags(site, resource, options = {}) {
61
120
  const tags = [];
62
- const url = canonicalUrl(site, resource);
121
+ const url = canonicalOverrideOf(resource, site) ?? canonicalUrl(site, resource);
63
122
  const schemaType = schemaTypeFor(resource.collection, {
64
123
  ...(options.types === undefined ? {} : { types: options.types }),
65
124
  });
66
- const title = options.title ?? pickString(resource, TITLE_FIELDS) ?? site.name;
67
- const rawDescription = options.description ?? pickString(resource, DESCRIPTION_FIELDS) ?? site.description;
125
+ // `seoTitle`/`seoDescription`/`seoImage` (fiche 13, Task 0 § decision (a)):
126
+ // read first, and for the title — never put through the template, which
127
+ // exists to dress up a *derived* title, not to append to one an editor
128
+ // already wrote in full.
129
+ const seoTitleOverride = pickString(resource, SEO_TITLE_FIELDS);
130
+ const derivedTitle = pickString(resource, TITLE_FIELDS) ?? site.name;
131
+ const title = options.title ??
132
+ seoTitleOverride ??
133
+ applyTitleTemplate(derivedTitle, site, titleTemplateFor(resource, options));
134
+ const rawDescription = options.description ??
135
+ pickString(resource, SEO_DESCRIPTION_FIELDS) ??
136
+ pickString(resource, DESCRIPTION_FIELDS) ??
137
+ site.description;
68
138
  const description = rawDescription === undefined ? undefined : truncate(rawDescription, MAX_DESCRIPTION);
69
- const image = options.image ?? firstImage(resource, options.resolvers);
139
+ const image = options.image ?? firstImage(resource, options.resolvers) ?? options.fallbackImage;
70
140
  tags.push({ kind: 'title', text: title });
71
141
  // The robots tag comes first among the meta tags because it is the one that
72
142
  // matters when it is wrong. An unpublished entry rendered through a preview
73
143
  // token must carry `noindex`: preview URLs leak — they get pasted into chats,
74
- // into tickets, and eventually into a crawler's referrer log.
75
- const indexable = options.noindex !== true && isPublished(resource.entry, options) && url !== null;
144
+ // into tickets, and eventually into a crawler's referrer log. A `seoNoindex`
145
+ // override behaves exactly like the explicit `options.noindex` an internal
146
+ // caller (a tag archive, a search results page) already sets.
147
+ const indexable = options.noindex !== true &&
148
+ !isSeoNoindexed(resource) &&
149
+ isPublished(resource.entry, options) &&
150
+ url !== null;
76
151
  if (!indexable) {
77
152
  tags.push({ kind: 'meta', name: 'robots', content: 'noindex, nofollow' });
78
153
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
package/dist/robots.d.ts CHANGED
@@ -30,6 +30,26 @@ export interface RobotsOptions {
30
30
  * can find, instead of a `Disallow` buried in a config file.
31
31
  */
32
32
  readonly allowIndexing?: boolean;
33
+ /**
34
+ * An admin's own hand-written robots.txt lines (fiche 50 task 4), merged
35
+ * in verbatim after the derived group(s) and before the `Sitemap:`
36
+ * directive — the one place in this file `assertSingleLine` deliberately
37
+ * does not apply, since this value is expected to carry real newlines.
38
+ * Trusted syntax: this function does not parse it, only splits it into
39
+ * lines and drops leading/trailing blank ones. Absent or blank contributes
40
+ * nothing, so a site that has never set this renders exactly as before.
41
+ */
42
+ readonly customRules?: string;
33
43
  }
44
+ /**
45
+ * True when `text` contains a bare `Disallow: /` for every user agent — the
46
+ * one line that blocks a whole site from every crawler (fiche 50's own named
47
+ * pitfall). Exported so a caller — the admin's custom-rules editor, in
48
+ * particular — can ask for confirmation *before* writing a rule that would
49
+ * de-index the entire site, the same way `allowIndexing: false` is a
50
+ * deliberate, separate choice rather than something a stray line falls into
51
+ * by accident.
52
+ */
53
+ export declare function robotsRuleDisallowsEverything(text: string): boolean;
34
54
  export declare function renderRobotsTxt(options: RobotsOptions): string;
35
55
  //# sourceMappingURL=robots.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGzC;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;IACxC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CACjC;AAYD,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAoC9D"}
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAGzC;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;IACxC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;IAChC;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnE;AAYD,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA0C9D"}
package/dist/robots.js CHANGED
@@ -1,5 +1,17 @@
1
1
  import { CogentaError } from '@cogenta/core';
2
2
  import { absoluteUrl } from './url.js';
3
+ /**
4
+ * True when `text` contains a bare `Disallow: /` for every user agent — the
5
+ * one line that blocks a whole site from every crawler (fiche 50's own named
6
+ * pitfall). Exported so a caller — the admin's custom-rules editor, in
7
+ * particular — can ask for confirmation *before* writing a rule that would
8
+ * de-index the entire site, the same way `allowIndexing: false` is a
9
+ * deliberate, separate choice rather than something a stray line falls into
10
+ * by accident.
11
+ */
12
+ export function robotsRuleDisallowsEverything(text) {
13
+ return /^\s*Disallow:\s*\/\s*$/imu.test(text);
14
+ }
3
15
  function assertSingleLine(value, what) {
4
16
  if (!/[\n\r]/u.test(value))
5
17
  return value;
@@ -35,6 +47,13 @@ export function renderRobotsTxt(options) {
35
47
  lines.push('');
36
48
  }
37
49
  }
50
+ const customRules = (options.customRules ?? '').trim();
51
+ if (customRules !== '') {
52
+ if (lines.at(-1) !== '')
53
+ lines.push('');
54
+ for (const line of customRules.split(/\r\n|\r|\n/u))
55
+ lines.push(line);
56
+ }
38
57
  // Sitemap lines are host-level, not group-level, so they go last and outside
39
58
  // any group. Put inside one, they are ignored by half the crawlers.
40
59
  const sitemaps = options.sitemaps ?? ['/sitemap.xml'];
@@ -1 +1 @@
1
- {"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAqCtC,SAAS,gBAAgB,CAAC,KAAa,EAAE,IAAY;IACnD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACxC,MAAM,IAAI,YAAY,CAAC;QACrB,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,gBAAgB,IAAI,gCAAgC;QAC7D,IAAI,EAAE,yGAAyG;QAC/G,OAAO,EAAE,EAAE,IAAI,EAAE;KAClB,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAsB;IACpD,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,IAAI,OAAO,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IAC5C,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACnE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAA;YACxF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,eAAe,gBAAgB,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC,CAAA;YACpE,CAAC;YACD,wEAAwE;YACxE,yEAAyE;YACzE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,UAAU,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;YACxD,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;gBACxC,KAAK,CAAC,IAAI,CAAC,aAAa,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;YAC3D,CAAC;YACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;YAClF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChB,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,cAAc,CAAC,CAAA;IACrD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACvC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,YAAY,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,aAAa,CAAC,EAAE,CAAC,CAAA;QAC5F,CAAC;IACH,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,IAAI,CAAA;AAC1C,CAAC"}
1
+ {"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /** A fetch-shaped function — overridable in tests, defaults to the global `fetch`. */
2
+ export type SearchConsoleFetch = typeof fetch;
3
+ export interface SearchConsoleOAuthOptions {
4
+ readonly clientId: string;
5
+ readonly clientSecret: string;
6
+ /** Must exactly match one of the redirect URIs registered on the Google Cloud OAuth client. */
7
+ readonly redirectUri: string;
8
+ }
9
+ /**
10
+ * Where a site's admin is sent to grant access. `state` is opaque to this
11
+ * file — the caller mints and verifies it (CSRF protection belongs to
12
+ * whoever owns the session, not to a URL builder) — and `access_type=offline`
13
+ * plus `prompt=consent` are what make Google actually hand back a
14
+ * `refresh_token`; without both, a re-authorization silently omits it.
15
+ */
16
+ export declare function buildAuthorizationUrl(options: SearchConsoleOAuthOptions, state: string): string;
17
+ export interface SearchConsoleTokens {
18
+ readonly accessToken: string;
19
+ readonly refreshToken: string;
20
+ readonly expiresAt: string;
21
+ }
22
+ /**
23
+ * Exchanges a one-time authorization code for a token pair. Called exactly
24
+ * once per connection, right after Google redirects back with `code` —
25
+ * never retried automatically, since a code is single-use and a retry
26
+ * would only produce a second, equally useless failure.
27
+ */
28
+ export declare function exchangeAuthorizationCode(options: SearchConsoleOAuthOptions, code: string, fetchImpl?: SearchConsoleFetch): Promise<SearchConsoleTokens>;
29
+ /**
30
+ * Trades a stored refresh token for a fresh access token. Called before
31
+ * every metrics request rather than caching an access token's own expiry
32
+ * (ADR-0032: rapatriés à la demande, not a background poll) — the extra
33
+ * round trip is one request per admin click, not a recurring cost.
34
+ */
35
+ export declare function refreshAccessToken(options: SearchConsoleOAuthOptions, refreshToken: string, fetchImpl?: SearchConsoleFetch): Promise<{
36
+ readonly accessToken: string;
37
+ readonly expiresAt: string;
38
+ }>;
39
+ export interface SearchConsoleMetricsRow {
40
+ readonly page: string;
41
+ readonly clicks: number;
42
+ readonly impressions: number;
43
+ readonly ctr: number;
44
+ readonly position: number;
45
+ }
46
+ export interface SearchAnalyticsQueryOptions {
47
+ readonly accessToken: string;
48
+ /** The GSC property as registered — a URL-prefix property (`https://example.com/`) or a domain property (`sc-domain:example.com`). */
49
+ readonly siteUrl: string;
50
+ /** `YYYY-MM-DD`. */
51
+ readonly startDate: string;
52
+ readonly endDate: string;
53
+ /** Defaults to 25 — enough for a "top pages" table without an unbounded response. */
54
+ readonly rowLimit?: number;
55
+ }
56
+ /**
57
+ * Clicks/impressions/CTR/average position per page over one date range —
58
+ * the one read this whole connector exists for. A `POST` to Google's own
59
+ * `searchAnalytics.query`, which Google itself documents as a read
60
+ * operation despite the HTTP verb (there is no `GET` equivalent in this
61
+ * API): no site data is created or changed by calling it, matching
62
+ * ADR-0032's "jamais de soumission... pour limiter la surface de ce que
63
+ * le jeton autorise".
64
+ */
65
+ export declare function fetchSearchAnalytics(options: SearchAnalyticsQueryOptions, fetchImpl?: SearchConsoleFetch): Promise<readonly SearchConsoleMetricsRow[]>;
66
+ //# sourceMappingURL=search-console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-console.d.ts","sourceRoot":"","sources":["../src/search-console.ts"],"names":[],"mappings":"AA6BA,sFAAsF;AACtF,MAAM,MAAM,kBAAkB,GAAG,OAAO,KAAK,CAAA;AAE7C,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,yBAAyB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/F;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAmBD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,yBAAyB,EAClC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,kBAA0B,GACpC,OAAO,CAAC,mBAAmB,CAAC,CA0C9B;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,EAClC,YAAY,EAAE,MAAM,EACpB,SAAS,GAAE,kBAA0B,GACpC,OAAO,CAAC;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BvE;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sIAAsI;IACtI,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,oBAAoB;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAaD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,EACpC,SAAS,GAAE,kBAA0B,GACpC,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CAkC7C"}
@@ -0,0 +1,169 @@
1
+ import { CogentaError } from '@cogenta/core';
2
+ /**
3
+ * Google Search Console connector (fiche 70 task 4, ADR-0032).
4
+ *
5
+ * **`fetch`-only, no Google SDK (R9).** `googleapis` pulls in an auth
6
+ * library, gRPC-adjacent transport code and a dependency tree far larger
7
+ * than the three HTTP calls this file actually needs: build an
8
+ * authorization URL, exchange a code for tokens once, and POST one
9
+ * `searchAnalytics.query` request. All three are plain, documented REST
10
+ * endpoints.
11
+ *
12
+ * **Read-only, structurally.** This file exports no function that could
13
+ * ever submit a sitemap, verify a property or change anything on the
14
+ * Google side — `fetchSearchAnalytics` is the only call that reaches the
15
+ * Search Console API itself, and it is a `POST` to a `query` endpoint that
16
+ * Google's own API classifies as read (ADR-0032 point 4: IndexNow remains
17
+ * the only write path this codebase has toward a search engine).
18
+ *
19
+ * **No state.** Like the rest of `@cogenta/seo`, this module holds no
20
+ * secret and touches no database (rule R5) — `createSearchConsoleConnectionStore`
21
+ * (`@cogenta/schema`) is where a refreshed token is kept; this file only
22
+ * ever receives one as a plain argument and returns a plain result.
23
+ */
24
+ const AUTHORIZATION_ENDPOINT = 'https://accounts.google.com/o/oauth2/v2/auth';
25
+ const TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token';
26
+ const SEARCH_ANALYTICS_SCOPE = 'https://www.googleapis.com/auth/webmasters.readonly';
27
+ /**
28
+ * Where a site's admin is sent to grant access. `state` is opaque to this
29
+ * file — the caller mints and verifies it (CSRF protection belongs to
30
+ * whoever owns the session, not to a URL builder) — and `access_type=offline`
31
+ * plus `prompt=consent` are what make Google actually hand back a
32
+ * `refresh_token`; without both, a re-authorization silently omits it.
33
+ */
34
+ export function buildAuthorizationUrl(options, state) {
35
+ const url = new URL(AUTHORIZATION_ENDPOINT);
36
+ url.searchParams.set('client_id', options.clientId);
37
+ url.searchParams.set('redirect_uri', options.redirectUri);
38
+ url.searchParams.set('response_type', 'code');
39
+ url.searchParams.set('scope', SEARCH_ANALYTICS_SCOPE);
40
+ url.searchParams.set('access_type', 'offline');
41
+ url.searchParams.set('prompt', 'consent');
42
+ url.searchParams.set('state', state);
43
+ return url.toString();
44
+ }
45
+ function tokenExchangeFailed(reason, cause) {
46
+ return new CogentaError({
47
+ code: 'SEARCH_CONSOLE_TOKEN_EXCHANGE_FAILED',
48
+ message: `Google's OAuth token endpoint refused the request: ${reason}.`,
49
+ hint: 'Check the OAuth client id/secret and that the redirect URI is registered exactly, then try connecting again.',
50
+ cause,
51
+ });
52
+ }
53
+ /**
54
+ * Exchanges a one-time authorization code for a token pair. Called exactly
55
+ * once per connection, right after Google redirects back with `code` —
56
+ * never retried automatically, since a code is single-use and a retry
57
+ * would only produce a second, equally useless failure.
58
+ */
59
+ export async function exchangeAuthorizationCode(options, code, fetchImpl = fetch) {
60
+ const response = await fetchImpl(TOKEN_ENDPOINT, {
61
+ method: 'POST',
62
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
63
+ body: new URLSearchParams({
64
+ code,
65
+ client_id: options.clientId,
66
+ client_secret: options.clientSecret,
67
+ redirect_uri: options.redirectUri,
68
+ grant_type: 'authorization_code',
69
+ }),
70
+ });
71
+ const body = (await response.json().catch(() => ({})));
72
+ if (!response.ok) {
73
+ const reason = typeof body.error_description === 'string'
74
+ ? body.error_description
75
+ : typeof body.error === 'string'
76
+ ? body.error
77
+ : `HTTP ${response.status}`;
78
+ throw tokenExchangeFailed(reason);
79
+ }
80
+ if (typeof body.access_token !== 'string' || typeof body.refresh_token !== 'string') {
81
+ // Google omits `refresh_token` when a user has already granted this
82
+ // app access before and `prompt=consent` was somehow not honoured —
83
+ // named explicitly here rather than left to read as a generic parse
84
+ // failure, since the fix (revoke access at myaccount.google.com/permissions,
85
+ // then reconnect) is different from every other failure this function raises.
86
+ throw tokenExchangeFailed(typeof body.refresh_token !== 'string'
87
+ ? "no refresh token was returned — revoke this app's access in the Google account and reconnect"
88
+ : 'the response carried no access token');
89
+ }
90
+ const expiresInSeconds = typeof body.expires_in === 'number' ? body.expires_in : 3600;
91
+ return {
92
+ accessToken: body.access_token,
93
+ refreshToken: body.refresh_token,
94
+ expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString(),
95
+ };
96
+ }
97
+ /**
98
+ * Trades a stored refresh token for a fresh access token. Called before
99
+ * every metrics request rather than caching an access token's own expiry
100
+ * (ADR-0032: rapatriés à la demande, not a background poll) — the extra
101
+ * round trip is one request per admin click, not a recurring cost.
102
+ */
103
+ export async function refreshAccessToken(options, refreshToken, fetchImpl = fetch) {
104
+ const response = await fetchImpl(TOKEN_ENDPOINT, {
105
+ method: 'POST',
106
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
107
+ body: new URLSearchParams({
108
+ refresh_token: refreshToken,
109
+ client_id: options.clientId,
110
+ client_secret: options.clientSecret,
111
+ grant_type: 'refresh_token',
112
+ }),
113
+ });
114
+ const body = (await response.json().catch(() => ({})));
115
+ if (!response.ok || typeof body.access_token !== 'string') {
116
+ const reason = typeof body.error_description === 'string'
117
+ ? body.error_description
118
+ : typeof body.error === 'string'
119
+ ? body.error
120
+ : `HTTP ${response.status}`;
121
+ throw tokenExchangeFailed(reason);
122
+ }
123
+ const expiresInSeconds = typeof body.expires_in === 'number' ? body.expires_in : 3600;
124
+ return {
125
+ accessToken: body.access_token,
126
+ expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString(),
127
+ };
128
+ }
129
+ /**
130
+ * Clicks/impressions/CTR/average position per page over one date range —
131
+ * the one read this whole connector exists for. A `POST` to Google's own
132
+ * `searchAnalytics.query`, which Google itself documents as a read
133
+ * operation despite the HTTP verb (there is no `GET` equivalent in this
134
+ * API): no site data is created or changed by calling it, matching
135
+ * ADR-0032's "jamais de soumission... pour limiter la surface de ce que
136
+ * le jeton autorise".
137
+ */
138
+ export async function fetchSearchAnalytics(options, fetchImpl = fetch) {
139
+ const endpoint = `https://www.googleapis.com/webmasters/v3/sites/${encodeURIComponent(options.siteUrl)}/searchAnalytics/query`;
140
+ const response = await fetchImpl(endpoint, {
141
+ method: 'POST',
142
+ headers: {
143
+ authorization: `Bearer ${options.accessToken}`,
144
+ 'content-type': 'application/json',
145
+ },
146
+ body: JSON.stringify({
147
+ startDate: options.startDate,
148
+ endDate: options.endDate,
149
+ dimensions: ['page'],
150
+ rowLimit: options.rowLimit ?? 25,
151
+ }),
152
+ });
153
+ const body = (await response.json().catch(() => ({})));
154
+ if (!response.ok) {
155
+ throw new CogentaError({
156
+ code: 'SEARCH_CONSOLE_QUERY_FAILED',
157
+ message: `Google Search Console refused the query: ${typeof body.error?.message === 'string' ? body.error.message : `HTTP ${response.status}`}.`,
158
+ hint: 'Confirm the connected Google account is a verified owner of this property in Search Console, then retry.',
159
+ });
160
+ }
161
+ return (body.rows ?? []).map((row) => ({
162
+ page: typeof row.keys?.[0] === 'string' ? row.keys[0] : '',
163
+ clicks: typeof row.clicks === 'number' ? row.clicks : 0,
164
+ impressions: typeof row.impressions === 'number' ? row.impressions : 0,
165
+ ctr: typeof row.ctr === 'number' ? row.ctr : 0,
166
+ position: typeof row.position === 'number' ? row.position : 0,
167
+ }));
168
+ }
169
+ //# sourceMappingURL=search-console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-console.js","sourceRoot":"","sources":["../src/search-console.ts"],"names":[],"mappings":"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"}
package/dist/sitemap.d.ts CHANGED
@@ -33,6 +33,19 @@ export interface SitemapFile {
33
33
  readonly isIndex: boolean;
34
34
  readonly urlCount: number;
35
35
  }
36
+ /**
37
+ * A site's own choice for one collection's contribution to the sitemap
38
+ * (fiche 21 task 3's "Sitemap" tab). `included: false` drops every entry of
39
+ * that collection outright — the same shape `isIndexable` already decides
40
+ * per-entry, just declared once per collection instead of per `seoNoindex`
41
+ * field. `changefreq`/`priority` are hints only (the protocol says crawlers
42
+ * may ignore either), applied to every URL the collection contributes.
43
+ */
44
+ export interface SitemapCollectionOverride {
45
+ readonly included?: boolean;
46
+ readonly changefreq?: ChangeFrequency;
47
+ readonly priority?: number;
48
+ }
36
49
  export interface SitemapOptions extends IndexableOptions {
37
50
  readonly maxUrls?: number;
38
51
  readonly maxBytes?: number;
@@ -44,6 +57,8 @@ export interface SitemapOptions extends IndexableOptions {
44
57
  readonly chunkPath?: (index: number) => string;
45
58
  /** `lastmod` of the index itself. Defaults to the newest child `lastmod`. */
46
59
  readonly lastmod?: string;
60
+ /** Per-collection inclusion, `changefreq` and `priority`, keyed by collection name. Absent means every collection is included with neither hint set. */
61
+ readonly collectionOverrides?: Readonly<Record<string, SitemapCollectionOverride>>;
47
62
  }
48
63
  /**
49
64
  * The files to write for a set of URLs.
@@ -1 +1 @@
1
- {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../src/sitemap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,gBAAgB,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAItD;;;;;;;;;GASG;AAEH,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,QAAS,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,WAAa,CAAA;AAK3C,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAA;AAEX,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAA;IACrC,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACnD;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,4FAA4F;IAC5F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,uEAAuE;IACvE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9C,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAmFD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,OAAO,GAAE,cAAmB,GAC3B,SAAS,WAAW,EAAE,CAyExB;AAWD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,OAAO,GAAE,cAAmB,GAC3B,SAAS,UAAU,EAAE,CAiBvB"}
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../src/sitemap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,EAAE,KAAK,gBAAgB,EAAsB,MAAM,gBAAgB,CAAA;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAItD;;;;;;;;;GASG;AAEH,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,QAAS,CAAA;AAEtC,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,WAAa,CAAA;AAK3C,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAA;AAEX,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAA;IACrC,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACnD;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,4FAA4F;IAC5F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,uEAAuE;IACvE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,oCAAoC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9C,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,wJAAwJ;IACxJ,QAAQ,CAAC,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAA;CACnF;AAmFD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,OAAO,GAAE,cAAmB,GAC3B,SAAS,WAAW,EAAE,CAyExB;AAWD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,SAAS,WAAW,EAAE,EACjC,OAAO,GAAE,cAAmB,GAC3B,SAAS,UAAU,EAAE,CAuBvB"}
package/dist/sitemap.js CHANGED
@@ -180,8 +180,12 @@ function newestLastmod(urls) {
180
180
  export function sitemapUrlsFor(site, resources, options = {}) {
181
181
  const published = indexableResources(site, resources, options);
182
182
  const hreflang = buildHreflangMap(site, resources, options);
183
+ const overrides = options.collectionOverrides;
183
184
  const urls = [];
184
185
  for (const resource of published) {
186
+ const override = overrides?.[resource.collection.name];
187
+ if (override?.included === false)
188
+ continue;
185
189
  const loc = canonicalUrl(site, resource);
186
190
  if (loc === null)
187
191
  continue;
@@ -189,6 +193,8 @@ export function sitemapUrlsFor(site, resources, options = {}) {
189
193
  urls.push({
190
194
  loc,
191
195
  lastmod: resource.entry.updatedAt,
196
+ ...(override?.changefreq === undefined ? {} : { changefreq: override.changefreq }),
197
+ ...(override?.priority === undefined ? {} : { priority: override.priority }),
192
198
  ...(alternates === undefined ? {} : { alternates }),
193
199
  });
194
200
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../src/sitemap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../src/sitemap.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogenta/seo",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Sitemaps, feeds, JSON-LD, hreflang and llms.txt derived from the content schema.",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
@@ -27,8 +27,8 @@
27
27
  "directory": "packages/seo"
28
28
  },
29
29
  "dependencies": {
30
- "@cogenta/core": "0.3.0",
31
- "@cogenta/schema": "0.2.0"
30
+ "@cogenta/core": "0.6.0",
31
+ "@cogenta/schema": "0.4.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "typescript": "^7.0.2",