@actuate-media/plugin-seo 0.0.13 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @actuate-media/plugin-seo
2
2
 
3
+ ## 0.0.15
4
+
5
+ ### Patch Changes
6
+
7
+ - cc18833: SEO audit remediation — 47 verified fixes across the SEO system.
8
+
9
+ Highlights: redirect middleware no longer excludes legacy `.html/.php/.aspx`
10
+ URLs (migrations); robots.txt now `Allow`s the default OG image (`/api/cms/og.png`)
11
+ so social shares render; RSS always emits the mandatory channel `<description>`;
12
+ structured-data auto-detection no longer emits invalid `Review/Event/JobPosting`
13
+ (required fields enforced or the node is suppressed) and no longer mis-types
14
+ collections by substring (`newsletters`→NewsArticle etc.); the sitemap endpoint
15
+ no longer selects full document JSON for up to 45k rows; IndexNow submits on
16
+ every publish instead of being swallowed by the sitemap debounce; the exported
17
+ `renderJsonLdScript()` now escapes `<`; the editor no longer shows two
18
+ conflicting scores and the Content-tab analysis now understands section-built
19
+ pages; plus pagination `rel`/canonical, `og:locale` normalization + alternates,
20
+ canonical absolutization, VideoObject/Product/WebSite-SearchAction builders,
21
+ redirect loop/case handling, plugin-seo sitemap caps + real `lastmod`, and
22
+ plugin link-health routed through `safeFetch`. Adds several new exports on
23
+ `@actuate-media/cms-core` (e.g. `buildVideoObjectSchema`, `buildProductSchema`).
24
+
25
+ ## 0.0.14
26
+
27
+ ### Patch Changes
28
+
29
+ - 041a228: Add the MIT `license` field to every published package (previously missing) and correct `repository.url` to `github.com/actuate-media/actuatecms` (13 packages carried the wrong org).
30
+ - de419f2: Give plugin hooks a frozen, typed event contract. cms-core now exports
31
+ `PluginHook`, `PluginHookEvent`, and `PluginHookPayload` (document + upload
32
+ variants) as the single source of truth, and dispatches a complete, consistent
33
+ set of events: `afterCreate` / `afterUpdate` / `afterDelete` — each also in a
34
+ collection-namespaced form (`afterUpdate:navigations`, `afterCreate:orders`) —
35
+ plus `afterUpload` (fired post-upload from the media route). Every handler now
36
+ receives one typed payload; document field values live on `payload.data`.
37
+
38
+ Previously core fired only bare `afterCreate`/`afterUpdate` with the raw row, so
39
+ several shipped plugins' hooks were dead: `plugin-media`'s `afterUpload` never
40
+ fired, `plugin-navigation` read fields that didn't exist, and the namespaced
41
+ events `plugin-forms`/`plugin-commerce` declared were never dispatched. Each
42
+ plugin has been aligned to the shared type and dispatched events (and
43
+ `plugin-redirects`' request-time `onRedirectMatch` hook — which the lifecycle
44
+ bus never dispatched — was removed). Undispatched event names are now a
45
+ compile-time error.
46
+
3
47
  ## 0.0.13
4
48
 
5
49
  ### Patch Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit-fixes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-fixes.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit-fixes.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,162 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import { generateSitemapIndex, generateCollectionSitemap, SITEMAP_MAX_URLS, } from '../sitemap/index.js';
3
+ import { generateRobotsTxt } from '../robots/index.js';
4
+ import { validateSchemaGraph } from '../schema/validator.js';
5
+ import { composeAndValidateSchema } from '../schema/composer.js';
6
+ import { detectRedirectChains, detectBrokenLinks, MAX_LINKS } from '../link-health/index.js';
7
+ import { AI_TRAINING_BOTS, AI_RETRIEVAL_BOTS } from '@actuate-media/cms-core';
8
+ // ---------------------------------------------------------------------------
9
+ // Finding 1 — sitemap 50k/50MB cap + stable index lastmod + Yoast child URLs
10
+ // ---------------------------------------------------------------------------
11
+ describe('sitemap generators (finding 1)', () => {
12
+ it('does not stamp a churning Date.now() lastmod on the index', () => {
13
+ const out = generateSitemapIndex(['posts'], 'https://example.com');
14
+ expect(out).not.toContain('<lastmod>');
15
+ // Yoast-style child URL, aligned with the core route.
16
+ expect(out).toContain('<loc>https://example.com/posts-sitemap.xml</loc>');
17
+ });
18
+ it('derives index lastmod from the collection newest-entry timestamp', () => {
19
+ const out = generateSitemapIndex([{ slug: 'posts', type: 'post', lastmod: '2026-01-02T03:04:05.000Z' }], 'https://example.com');
20
+ expect(out).toContain('<lastmod>2026-01-02T03:04:05.000Z</lastmod>');
21
+ // `post` Yoast base name for the canonical posts collection.
22
+ expect(out).toContain('<loc>https://example.com/post-sitemap.xml</loc>');
23
+ });
24
+ it('is deterministic across calls (same input -> same output)', () => {
25
+ const cfg = [{ slug: 'pages', type: 'page', lastmod: '2026-01-01T00:00:00.000Z' }];
26
+ expect(generateSitemapIndex(cfg, 'https://x.com')).toBe(generateSitemapIndex(cfg, 'https://x.com'));
27
+ });
28
+ it('renders a normal collection sitemap under the cap', () => {
29
+ const entries = [{ loc: 'a', lastmod: '2026-01-01' }, { loc: 'b' }];
30
+ const xml = generateCollectionSitemap(entries, 'https://example.com');
31
+ expect(xml).toContain('<loc>https://example.com/a</loc>');
32
+ expect(xml).toContain('<loc>https://example.com/b</loc>');
33
+ });
34
+ it('throws past the 50,000-URL limit instead of emitting an oversized file', () => {
35
+ const entries = Array.from({ length: SITEMAP_MAX_URLS + 1 }, (_, i) => ({
36
+ loc: `p${i}`,
37
+ }));
38
+ expect(() => generateCollectionSitemap(entries, 'https://example.com')).toThrow(RangeError);
39
+ });
40
+ it('accepts exactly the 50,000-URL limit', () => {
41
+ const entries = Array.from({ length: SITEMAP_MAX_URLS }, (_, i) => ({
42
+ loc: `p${i}`,
43
+ }));
44
+ expect(() => generateCollectionSitemap(entries, 'https://example.com')).not.toThrow();
45
+ });
46
+ });
47
+ // ---------------------------------------------------------------------------
48
+ // Finding 2 — validateSchema wired into the compose path (via @graph adapter)
49
+ // ---------------------------------------------------------------------------
50
+ describe('schema validation wiring (finding 2)', () => {
51
+ it('validateSchemaGraph flags a node in a @graph missing required fields', () => {
52
+ const graph = {
53
+ '@context': 'https://schema.org',
54
+ '@graph': [
55
+ { '@type': 'Article', headline: 'Hi', author: 'Jane', datePublished: '2026-01-01' },
56
+ { '@type': 'Review', reviewRating: { ratingValue: 5 } }, // missing itemReviewed, author
57
+ ],
58
+ };
59
+ const result = validateSchemaGraph(graph);
60
+ expect(result.valid).toBe(false);
61
+ const fields = result.errors.map((e) => e.field);
62
+ expect(fields).toContain('@graph[1].itemReviewed');
63
+ expect(fields).toContain('@graph[1].author');
64
+ // The valid Article node (node 0) has no error-severity findings.
65
+ const node0Errors = result.errors.filter((e) => e.field.startsWith('@graph[0].') && e.severity === 'error');
66
+ expect(node0Errors).toEqual([]);
67
+ });
68
+ it('validateSchemaGraph does not flag nodes for a wrapper-provided @context', () => {
69
+ const graph = {
70
+ '@context': 'https://schema.org',
71
+ '@graph': [{ '@type': 'Organization', name: 'Acme' }],
72
+ };
73
+ const result = validateSchemaGraph(graph);
74
+ expect(result.errors.some((e) => e.field.endsWith('@context'))).toBe(false);
75
+ expect(result.valid).toBe(true);
76
+ });
77
+ it('composeAndValidateSchema exercises the validator on the emitted node', () => {
78
+ const { schema, validation } = composeAndValidateSchema('Event', { name: 'Launch' });
79
+ expect(schema['@type']).toBe('Event');
80
+ // Missing startDate -> flagged, not silently shipped.
81
+ expect(validation.valid).toBe(false);
82
+ expect(validation.errors.some((e) => e.field === 'startDate')).toBe(true);
83
+ });
84
+ });
85
+ // ---------------------------------------------------------------------------
86
+ // Finding 3 — robots delegates to the canonical cms-core AI bot taxonomy
87
+ // ---------------------------------------------------------------------------
88
+ describe('generateRobotsTxt AI bots (finding 3)', () => {
89
+ it('blocks the full canonical training + retrieval taxonomy', () => {
90
+ const txt = generateRobotsTxt({ blockAIBots: true });
91
+ for (const bot of [...AI_TRAINING_BOTS, ...AI_RETRIEVAL_BOTS]) {
92
+ expect(txt).toContain(`User-agent: ${bot}`);
93
+ }
94
+ // 2026 bots that the stale hardcoded list of 8 was missing.
95
+ for (const bot of ['PerplexityBot', 'Amazonbot', 'Applebot-Extended', 'OAI-SearchBot']) {
96
+ expect(txt).toContain(`User-agent: ${bot}`);
97
+ }
98
+ });
99
+ it('does not emit AI bot rules when blockAIBots is off', () => {
100
+ const txt = generateRobotsTxt({ blockAIBots: false });
101
+ expect(txt).not.toContain('GPTBot');
102
+ });
103
+ it('dedupes an additional bot that repeats a canonical token', () => {
104
+ const txt = generateRobotsTxt({ blockAIBots: true, additionalAIBots: ['GPTBot'] });
105
+ expect(txt.match(/User-agent: GPTBot/g)?.length).toBe(1);
106
+ });
107
+ });
108
+ // ---------------------------------------------------------------------------
109
+ // Finding 4 — redirect loops distinguished from terminating chains
110
+ // ---------------------------------------------------------------------------
111
+ describe('detectRedirectChains (finding 4)', () => {
112
+ it('labels a cycle as a loop, not a chain', () => {
113
+ const result = detectRedirectChains([
114
+ { from: 'A', to: 'B' },
115
+ { from: 'B', to: 'A' },
116
+ ]);
117
+ expect(result).toHaveLength(1);
118
+ expect(result[0].kind).toBe('loop');
119
+ expect(result[0].chain).toEqual(['A', 'B', 'A']);
120
+ });
121
+ it('labels a terminating multi-hop redirect as a chain', () => {
122
+ const result = detectRedirectChains([
123
+ { from: 'A', to: 'B' },
124
+ { from: 'B', to: 'C' },
125
+ ]);
126
+ expect(result).toHaveLength(1);
127
+ expect(result[0].kind).toBe('chain');
128
+ expect(result[0].finalUrl).toBe('C');
129
+ expect(result[0].length).toBe(2);
130
+ });
131
+ it('does not emit a chain for a single hop', () => {
132
+ expect(detectRedirectChains([{ from: 'A', to: 'B' }])).toEqual([]);
133
+ });
134
+ });
135
+ // ---------------------------------------------------------------------------
136
+ // Finding 5 — broken-link checker uses safeFetch, caps links, keeps timeout
137
+ // ---------------------------------------------------------------------------
138
+ describe('detectBrokenLinks (finding 5)', () => {
139
+ afterEach(() => {
140
+ vi.restoreAllMocks();
141
+ });
142
+ it('blocks SSRF targets (loopback) via safeFetch instead of raw fetch', async () => {
143
+ const fetchSpy = vi.spyOn(globalThis, 'fetch');
144
+ const html = '<a href="http://127.0.0.1/admin">x</a>';
145
+ const results = await detectBrokenLinks(html, 'https://example.com');
146
+ expect(results).toHaveLength(1);
147
+ expect(results[0].status).toBe('blocked');
148
+ // safeFetch's SSRF preflight rejects before any network fetch is issued.
149
+ expect(fetchSpy).not.toHaveBeenCalled();
150
+ });
151
+ it('caps the number of links scanned at MAX_LINKS', async () => {
152
+ const fetchSpy = vi.spyOn(globalThis, 'fetch');
153
+ // Distinct loopback paths: rejected by safeFetch's synchronous IP-literal
154
+ // check (no DNS, no network), so this exercises the cap without hanging.
155
+ const html = Array.from({ length: MAX_LINKS + 50 }, (_, i) => `<a href="http://127.0.0.1/p${i}">x</a>`).join('');
156
+ const results = await detectBrokenLinks(html, 'https://example.com');
157
+ expect(results).toHaveLength(MAX_LINKS);
158
+ expect(results.every((r) => r.status === 'blocked')).toBe(true);
159
+ expect(fetchSpy).not.toHaveBeenCalled();
160
+ });
161
+ });
162
+ //# sourceMappingURL=audit-fixes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-fixes.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-fixes.test.ts"],"names":[],"mappings":"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"}
package/dist/hooks.d.ts CHANGED
@@ -4,9 +4,12 @@
4
4
  * Schema defaults and structured-data stamping are handled in cms-core
5
5
  * (`prepareContentStructuredData` on document create/update). Hooks here are
6
6
  * limited to cache invalidation side effects.
7
+ *
8
+ * These hooks use the shared `PluginHook` contract from cms-core: each handler
9
+ * receives a single typed payload. For document-lifecycle events the top-level
10
+ * `collection` identifies the collection; field values live under
11
+ * `payload.data`.
7
12
  */
8
- export declare const seoHooks: Array<{
9
- event: string;
10
- handler: (...args: unknown[]) => Promise<void> | void;
11
- }>;
13
+ import type { PluginHook } from '@actuate-media/cms-core';
14
+ export declare const seoHooks: PluginHook[];
12
15
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACtD,CAgBA,CAAA"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,yBAAyB,CAAA;AAEpF,eAAO,MAAM,QAAQ,EAAE,UAAU,EAoBhC,CAAA"}
package/dist/hooks.js CHANGED
@@ -1,18 +1,15 @@
1
- /**
2
- * Plugin lifecycle hooks.
3
- *
4
- * Schema defaults and structured-data stamping are handled in cms-core
5
- * (`prepareContentStructuredData` on document create/update). Hooks here are
6
- * limited to cache invalidation side effects.
7
- */
8
1
  export const seoHooks = [
9
2
  {
3
+ // `afterUpdate` is a dispatched document-lifecycle event. When a document
4
+ // changes we drop its cached sitemap fragment so the next request rebuilds.
10
5
  event: 'afterUpdate',
11
- handler: async (...args) => {
12
- const [data] = args;
13
- if (!data)
6
+ handler: async (payload) => {
7
+ if (!payload)
14
8
  return;
15
- const cacheKey = `sitemap:${data._collection ?? 'global'}`;
9
+ const doc = payload;
10
+ // The collection lives at the top level of the payload (NOT in
11
+ // `payload.data`, and NOT under a `_collection` field).
12
+ const cacheKey = `sitemap:${doc.collection ?? 'global'}`;
16
13
  if (typeof globalThis !== 'undefined') {
17
14
  const cache = globalThis.__sitemapCache;
18
15
  cache?.delete(cacheKey);
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,QAAQ,GAGhB;IACH;QACE,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;YACpC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAiC,CAAA;YAChD,IAAI,CAAC,IAAI;gBAAE,OAAM;YAEjB,MAAM,QAAQ,GAAG,WAAY,IAAI,CAAC,WAAsB,IAAI,QAAQ,EAAE,CAAA;YACtE,IAAI,OAAO,UAAU,KAAK,WAAW,EAAE,CAAC;gBACtC,MAAM,KAAK,GAAI,UAAsC,CAAC,cAEzC,CAAA;gBACb,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;KACF;CACF,CAAA"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,QAAQ,GAAiB;IACpC;QACE,0EAA0E;QAC1E,4EAA4E;QAC5E,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACzB,IAAI,CAAC,OAAO;gBAAE,OAAM;YACpB,MAAM,GAAG,GAAG,OAAoC,CAAA;YAEhD,+DAA+D;YAC/D,wDAAwD;YACxD,MAAM,QAAQ,GAAG,WAAW,GAAG,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAA;YACxD,IAAI,OAAO,UAAU,KAAK,WAAW,EAAE,CAAC;gBACtC,MAAM,KAAK,GAAI,UAAsC,CAAC,cAEzC,CAAA;gBACb,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;KACF;CACF,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { FieldDefinition, CollectionDefinition } from '@actuate-media/cms-core';
1
+ import type { FieldDefinition, CollectionDefinition, PluginHook } from '@actuate-media/cms-core';
2
2
  export interface ActuatePlugin {
3
3
  name: string;
4
4
  fields?: Record<string, FieldDefinition>;
@@ -8,10 +8,7 @@ export interface ActuatePlugin {
8
8
  icon: string;
9
9
  path: string;
10
10
  }>;
11
- hooks?: Array<{
12
- event: string;
13
- handler: (...args: unknown[]) => Promise<void> | void;
14
- }>;
11
+ hooks?: PluginHook[];
15
12
  }
16
13
  export interface SEOPluginConfig {
17
14
  sitemap?: {
@@ -53,16 +50,17 @@ export { seoFields } from './fields.js';
53
50
  export { seoCollections } from './collections.js';
54
51
  export { seoHooks } from './hooks.js';
55
52
  export { detectSchemaType } from './schema/auto-detect.js';
56
- export { composeSchema } from './schema/composer.js';
57
- export { validateSchema } from './schema/validator.js';
53
+ export { composeSchema, composeAndValidateSchema } from './schema/composer.js';
54
+ export { validateSchema, validateSchemaGraph } from './schema/validator.js';
58
55
  export type { ValidationResult } from './schema/validator.js';
59
- export { generateSitemapIndex, generateCollectionSitemap, generateImageSitemap, generateVideoSitemap, generateNewsSitemap, generateHreflangSitemap, buildDocumentUrl, } from './sitemap/index.js';
56
+ export { generateSitemapIndex, generateCollectionSitemap, generateImageSitemap, generateVideoSitemap, generateNewsSitemap, generateHreflangSitemap, buildDocumentUrl, SITEMAP_MAX_URLS, SITEMAP_MAX_BYTES, } from './sitemap/index.js';
60
57
  export type { SitemapEntry, ImageSitemapEntry, VideoSitemapEntry, NewsSitemapEntry, HreflangEntry, CollectionSitemapConfig, } from './sitemap/index.js';
61
58
  export { generateRobotsTxt } from './robots/index.js';
62
59
  export type { RobotsConfig } from './robots/index.js';
63
60
  export { generateOGImage } from './og-image/index.js';
64
61
  export type { OGImageOptions } from './og-image/index.js';
65
- export { detectBrokenLinks, detectOrphanPages, detectRedirectChains } from './link-health/index.js';
62
+ export { detectBrokenLinks, detectOrphanPages, detectRedirectChains, MAX_LINKS, } from './link-health/index.js';
63
+ export type { LinkHealthResult, RedirectChain } from './link-health/index.js';
66
64
  export { detectDuplicates, suggestCanonical } from './canonical/index.js';
67
65
  export type { DuplicateGroup } from './canonical/index.js';
68
66
  export { SEOPanel } from './admin/SEOPanel.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -22,12 +22,12 @@ export { seoFields } from './fields.js';
22
22
  export { seoCollections } from './collections.js';
23
23
  export { seoHooks } from './hooks.js';
24
24
  export { detectSchemaType } from './schema/auto-detect.js';
25
- export { composeSchema } from './schema/composer.js';
26
- export { validateSchema } from './schema/validator.js';
27
- export { generateSitemapIndex, generateCollectionSitemap, generateImageSitemap, generateVideoSitemap, generateNewsSitemap, generateHreflangSitemap, buildDocumentUrl, } from './sitemap/index.js';
25
+ export { composeSchema, composeAndValidateSchema } from './schema/composer.js';
26
+ export { validateSchema, validateSchemaGraph } from './schema/validator.js';
27
+ export { generateSitemapIndex, generateCollectionSitemap, generateImageSitemap, generateVideoSitemap, generateNewsSitemap, generateHreflangSitemap, buildDocumentUrl, SITEMAP_MAX_URLS, SITEMAP_MAX_BYTES, } from './sitemap/index.js';
28
28
  export { generateRobotsTxt } from './robots/index.js';
29
29
  export { generateOGImage } from './og-image/index.js';
30
- export { detectBrokenLinks, detectOrphanPages, detectRedirectChains } from './link-health/index.js';
30
+ export { detectBrokenLinks, detectOrphanPages, detectRedirectChains, MAX_LINKS, } from './link-health/index.js';
31
31
  export { detectDuplicates, suggestCanonical } from './canonical/index.js';
32
32
  export { SEOPanel } from './admin/SEOPanel.js';
33
33
  export { GooglePreview } from './admin/GooglePreview.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AA4CrC,sDAAsD;AACtD,MAAM,UAAU,SAAS,CAAC,SAA0B,EAAE;IACpD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,GAAG,SAAS,EAAE;QACxB,WAAW,EAAE,EAAE,GAAG,cAAc,EAAE;QAClC,aAAa,EAAE;YACb,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;YACvD,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE;YACvD,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE;SACjE;QACD,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7B,GAAG,IAAI;YACP,aAAa,EAAE,MAAM;SACtB,CAAC,CAA2B;KAC9B,CAAA;AACH,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAS3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AACnG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAyCrC,sDAAsD;AACtD,MAAM,UAAU,SAAS,CAAC,SAA0B,EAAE;IACpD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,EAAE,GAAG,SAAS,EAAE;QACxB,WAAW,EAAE,EAAE,GAAG,cAAc,EAAE;QAClC,aAAa,EAAE;YACb,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE;YACvD,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE;YACvD,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE;SACjE;QACD,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7B,GAAG,IAAI;YACP,aAAa,EAAE,MAAM;SACtB,CAAC,CAA2B;KAC9B,CAAA;AACH,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE3E,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAS3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,GACV,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA"}
@@ -1,6 +1,6 @@
1
1
  export interface LinkHealthResult {
2
2
  url: string;
3
- status: 'ok' | 'broken' | 'redirect' | 'timeout' | 'error';
3
+ status: 'ok' | 'broken' | 'redirect' | 'timeout' | 'error' | 'blocked';
4
4
  statusCode?: number;
5
5
  redirectTarget?: string;
6
6
  responseTime?: number;
@@ -8,15 +8,35 @@ export interface LinkHealthResult {
8
8
  }
9
9
  export interface RedirectChain {
10
10
  initialUrl: string;
11
+ /** Whether this is a terminating multi-hop chain or a cyclic redirect loop. */
12
+ kind: 'chain' | 'loop';
11
13
  chain: string[];
12
14
  finalUrl: string;
13
15
  length: number;
14
16
  }
15
- /** Scans HTML content for links and checks their health. */
17
+ /** Hard cap on the number of unique links checked per scan (DoS / fan-out guard). */
18
+ export declare const MAX_LINKS = 200;
19
+ /**
20
+ * Scans HTML content for links and checks their health.
21
+ *
22
+ * Outbound requests go through cms-core's `safeFetch` (DNS-resolving SSRF
23
+ * preflight + `redirect: 'manual'`) so a link to an internal/loopback/metadata
24
+ * address can't be used to probe the host. Scans are capped at {@link MAX_LINKS}
25
+ * unique URLs and run with bounded concurrency, each under a hard timeout.
26
+ */
16
27
  export declare function detectBrokenLinks(content: string, baseUrl: string): Promise<LinkHealthResult[]>;
17
28
  /** Finds pages that are not linked from any other page. */
18
29
  export declare function detectOrphanPages(allPages: string[], linkedPages: string[]): string[];
19
- /** Detects redirect chains longer than a single hop. */
30
+ /**
31
+ * Detects multi-hop redirect chains and cyclic redirect loops.
32
+ *
33
+ * A terminating sequence of 2+ redirects (3+ nodes) is a `chain`. A sequence
34
+ * that revisits an earlier node is a `loop` — reported separately because loops
35
+ * cause infinite-redirect crawl errors, whereas chains merely waste crawl
36
+ * budget. Mirrors cms-core's `detectChainsAndLoops`: each loop is reported once
37
+ * (all its members are marked handled) and sub-chains are collapsed into the
38
+ * longest chain from their entry point.
39
+ */
20
40
  export declare function detectRedirectChains(redirects: Array<{
21
41
  from: string;
22
42
  to: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/link-health/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAID,4DAA4D;AAC5D,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAmD7B;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAGrF;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,aAAa,EAAE,CA0BjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/link-health/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;IACtE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;IACtB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAID,qFAAqF;AACrF,eAAO,MAAM,SAAS,MAAM,CAAA;AA2B5B;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAuD7B;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAGrF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7C,aAAa,EAAE,CAiDjB"}
@@ -1,9 +1,37 @@
1
+ import { safeFetch, SsrfBlockedError } from '@actuate-media/cms-core';
1
2
  const LINK_REGEX = /href=["']([^"']+)["']/gi;
2
- /** Scans HTML content for links and checks their health. */
3
+ /** Hard cap on the number of unique links checked per scan (DoS / fan-out guard). */
4
+ export const MAX_LINKS = 200;
5
+ /** Number of link checks issued in parallel. */
6
+ const CONCURRENCY = 6;
7
+ /** Per-request timeout (ms). */
8
+ const REQUEST_TIMEOUT_MS = 10_000;
9
+ /** Runs `worker` over `items` with a bounded concurrency, preserving input order. */
10
+ async function mapWithConcurrency(items, concurrency, worker) {
11
+ const results = new Array(items.length);
12
+ let cursor = 0;
13
+ async function run() {
14
+ while (cursor < items.length) {
15
+ const index = cursor++;
16
+ results[index] = await worker(items[index], index);
17
+ }
18
+ }
19
+ const runners = Array.from({ length: Math.min(concurrency, items.length) }, () => run());
20
+ await Promise.all(runners);
21
+ return results;
22
+ }
23
+ /**
24
+ * Scans HTML content for links and checks their health.
25
+ *
26
+ * Outbound requests go through cms-core's `safeFetch` (DNS-resolving SSRF
27
+ * preflight + `redirect: 'manual'`) so a link to an internal/loopback/metadata
28
+ * address can't be used to probe the host. Scans are capped at {@link MAX_LINKS}
29
+ * unique URLs and run with bounded concurrency, each under a hard timeout.
30
+ */
3
31
  export async function detectBrokenLinks(content, baseUrl) {
4
32
  const base = baseUrl.replace(/\/$/, '');
5
- const results = [];
6
33
  const seen = new Set();
34
+ const targets = [];
7
35
  let match;
8
36
  while ((match = LINK_REGEX.exec(content)) !== null) {
9
37
  const href = match[1];
@@ -14,63 +42,99 @@ export async function detectBrokenLinks(content, baseUrl) {
14
42
  if (seen.has(url))
15
43
  continue;
16
44
  seen.add(url);
45
+ targets.push({ url, source: href });
46
+ if (targets.length >= MAX_LINKS)
47
+ break;
48
+ }
49
+ return mapWithConcurrency(targets, CONCURRENCY, async ({ url, source }) => {
50
+ const started = Date.now();
17
51
  try {
18
- const controller = new AbortController();
19
- const timeout = setTimeout(() => controller.abort(), 10_000);
20
- const response = await fetch(url, {
52
+ const response = await safeFetch(url, {
21
53
  method: 'HEAD',
22
- signal: controller.signal,
23
- redirect: 'manual',
54
+ timeoutMs: REQUEST_TIMEOUT_MS,
55
+ requireDnsCheck: true,
24
56
  });
25
- clearTimeout(timeout);
57
+ const responseTime = Date.now() - started;
26
58
  if (response.status >= 300 && response.status < 400) {
27
- results.push({
59
+ return {
28
60
  url,
29
61
  status: 'redirect',
30
62
  statusCode: response.status,
31
63
  redirectTarget: response.headers.get('location') ?? undefined,
32
- source: href,
33
- });
64
+ responseTime,
65
+ source,
66
+ };
34
67
  }
35
- else if (response.ok) {
36
- results.push({ url, status: 'ok', statusCode: response.status, source: href });
37
- }
38
- else {
39
- results.push({ url, status: 'broken', statusCode: response.status, source: href });
68
+ if (response.ok) {
69
+ return { url, status: 'ok', statusCode: response.status, responseTime, source };
40
70
  }
71
+ return { url, status: 'broken', statusCode: response.status, responseTime, source };
41
72
  }
42
73
  catch (error) {
43
- const isAbort = error instanceof DOMException && error.name === 'AbortError';
44
- results.push({
45
- url,
46
- status: isAbort ? 'timeout' : 'error',
47
- source: href,
48
- });
74
+ const responseTime = Date.now() - started;
75
+ if (error instanceof SsrfBlockedError) {
76
+ return { url, status: 'blocked', responseTime, source };
77
+ }
78
+ const isTimeout = error instanceof DOMException &&
79
+ (error.name === 'TimeoutError' || error.name === 'AbortError');
80
+ return { url, status: isTimeout ? 'timeout' : 'error', responseTime, source };
49
81
  }
50
- }
51
- return results;
82
+ });
52
83
  }
53
84
  /** Finds pages that are not linked from any other page. */
54
85
  export function detectOrphanPages(allPages, linkedPages) {
55
86
  const linkedSet = new Set(linkedPages.map((p) => p.replace(/\/$/, '').toLowerCase()));
56
87
  return allPages.filter((page) => !linkedSet.has(page.replace(/\/$/, '').toLowerCase()));
57
88
  }
58
- /** Detects redirect chains longer than a single hop. */
89
+ /**
90
+ * Detects multi-hop redirect chains and cyclic redirect loops.
91
+ *
92
+ * A terminating sequence of 2+ redirects (3+ nodes) is a `chain`. A sequence
93
+ * that revisits an earlier node is a `loop` — reported separately because loops
94
+ * cause infinite-redirect crawl errors, whereas chains merely waste crawl
95
+ * budget. Mirrors cms-core's `detectChainsAndLoops`: each loop is reported once
96
+ * (all its members are marked handled) and sub-chains are collapsed into the
97
+ * longest chain from their entry point.
98
+ */
59
99
  export function detectRedirectChains(redirects) {
60
100
  const redirectMap = new Map(redirects.map((r) => [r.from, r.to]));
61
101
  const chains = [];
102
+ const reported = new Set();
62
103
  for (const { from } of redirects) {
104
+ if (reported.has(from))
105
+ continue;
63
106
  const chain = [from];
107
+ const visited = new Set([from]);
64
108
  let current = from;
65
- const visited = new Set();
66
- while (redirectMap.has(current) && !visited.has(current)) {
67
- visited.add(current);
68
- current = redirectMap.get(current);
69
- chain.push(current);
109
+ let loop = false;
110
+ while (redirectMap.has(current)) {
111
+ const next = redirectMap.get(current);
112
+ chain.push(next);
113
+ if (visited.has(next)) {
114
+ loop = true;
115
+ break;
116
+ }
117
+ visited.add(next);
118
+ current = next;
119
+ }
120
+ if (loop) {
121
+ // Report each cycle once; mark every member handled.
122
+ chain.forEach((node) => reported.add(node));
123
+ chains.push({
124
+ initialUrl: from,
125
+ kind: 'loop',
126
+ chain,
127
+ finalUrl: chain[chain.length - 1] ?? '',
128
+ length: chain.length - 1,
129
+ });
70
130
  }
71
- if (chain.length > 2) {
131
+ else if (chain.length > 2) {
132
+ // Collapse sub-chains: mark every non-terminal node handled so we don't
133
+ // re-emit the tail of this chain from a later starting point.
134
+ chain.slice(0, -1).forEach((node) => reported.add(node));
72
135
  chains.push({
73
136
  initialUrl: from,
137
+ kind: 'chain',
74
138
  chain,
75
139
  finalUrl: chain[chain.length - 1] ?? '',
76
140
  length: chain.length - 1,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/link-health/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/link-health/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/robots/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAC,CAAA;IACF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B;AAaD,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAsC9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/robots/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAC,CAAA;IACF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC5B;AAUD,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAuC9D"}
@@ -1,13 +1,11 @@
1
- const DEFAULT_AI_BOTS = [
2
- 'GPTBot',
3
- 'ChatGPT-User',
4
- 'ClaudeBot',
5
- 'Claude-Web',
6
- 'anthropic-ai',
7
- 'Bytespider',
8
- 'CCBot',
9
- 'Google-Extended',
10
- ];
1
+ import { AI_TRAINING_BOTS, AI_RETRIEVAL_BOTS } from '@actuate-media/cms-core';
2
+ /**
3
+ * Canonical AI-crawler blocklist. Delegates to cms-core's curated taxonomy
4
+ * (AI_TRAINING_BOTS + AI_RETRIEVAL_BOTS) so the plugin and the core /robots.txt
5
+ * route share a single source of truth instead of drifting apart. The legacy
6
+ * `blockAIBots` boolean blocks both groups, matching core's behavior.
7
+ */
8
+ const DEFAULT_AI_BOTS = [...AI_TRAINING_BOTS, ...AI_RETRIEVAL_BOTS];
11
9
  /** Generates a robots.txt string from the given configuration. */
12
10
  export function generateRobotsTxt(config) {
13
11
  const lines = [];
@@ -30,7 +28,8 @@ export function generateRobotsTxt(config) {
30
28
  lines.push('');
31
29
  }
32
30
  if (config.blockAIBots) {
33
- const bots = [...DEFAULT_AI_BOTS, ...(config.additionalAIBots ?? [])];
31
+ // Dedupe in case an integrator repeats a canonical token in additionalAIBots.
32
+ const bots = [...new Set([...DEFAULT_AI_BOTS, ...(config.additionalAIBots ?? [])])];
34
33
  for (const bot of bots) {
35
34
  lines.push(`User-agent: ${bot}`);
36
35
  lines.push('Disallow: /');
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/robots/index.ts"],"names":[],"mappings":"AAYA,MAAM,eAAe,GAAG;IACtB,QAAQ;IACR,cAAc;IACd,WAAW;IACX,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,OAAO;IACP,iBAAiB;CAClB,CAAA;AAED,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAE/F,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAC3C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACjC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;QAC/C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,CAAA;QACrE,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,CAAA;YAChC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChB,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;QAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/robots/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAc7E;;;;;GAKG;AACH,MAAM,eAAe,GAAsB,CAAC,GAAG,gBAAgB,EAAE,GAAG,iBAAiB,CAAC,CAAA;AAEtF,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;IAE/F,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAC3C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACjC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;YACjC,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;QAC/C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,8EAA8E;QAC9E,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACnF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,CAAA;YAChC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACzB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChB,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;QAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
@@ -1,3 +1,15 @@
1
+ import { type ValidationResult } from './validator.js';
1
2
  /** Builds a nested JSON-LD structure with @context, @type, and related entities. */
2
3
  export declare function composeSchema(type: string, data: Record<string, unknown>, nested?: Record<string, unknown>): Record<string, unknown>;
4
+ /**
5
+ * Composes a JSON-LD node and validates it against Schema.org requirements in
6
+ * one step — the compose path that actually exercises the validator so nodes
7
+ * missing required fields (invalid Review/Event/JobPosting, etc.) are flagged
8
+ * instead of shipping silently. Returns the composed `schema` alongside its
9
+ * `validation` result; callers (e.g. the SEO audit UI) surface the warnings.
10
+ */
11
+ export declare function composeAndValidateSchema(type: string, data: Record<string, unknown>, nested?: Record<string, unknown>): {
12
+ schema: Record<string, unknown>;
13
+ validation: ValidationResult;
14
+ };
3
15
  //# sourceMappingURL=composer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/schema/composer.ts"],"names":[],"mappings":"AAsBA,oFAAoF;AACpF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2CzB"}
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/schema/composer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAwB3E,oFAAoF;AACpF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2CzB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAGnE"}
@@ -1,3 +1,4 @@
1
+ import { validateSchemaGraph } from './validator.js';
1
2
  const NESTED_ENTITY_MAP = {
2
3
  Article: [
3
4
  { field: 'author', type: 'Person' },
@@ -63,4 +64,15 @@ export function composeSchema(type, data, nested) {
63
64
  }
64
65
  return schema;
65
66
  }
67
+ /**
68
+ * Composes a JSON-LD node and validates it against Schema.org requirements in
69
+ * one step — the compose path that actually exercises the validator so nodes
70
+ * missing required fields (invalid Review/Event/JobPosting, etc.) are flagged
71
+ * instead of shipping silently. Returns the composed `schema` alongside its
72
+ * `validation` result; callers (e.g. the SEO audit UI) surface the warnings.
73
+ */
74
+ export function composeAndValidateSchema(type, data, nested) {
75
+ const schema = composeSchema(type, data, nested);
76
+ return { schema, validation: validateSchemaGraph(schema) };
77
+ }
66
78
  //# sourceMappingURL=composer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"composer.js","sourceRoot":"","sources":["../../src/schema/composer.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAA2D;IAChF,OAAO,EAAE;QACP,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QACnC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE;KAC7C;IACD,KAAK,EAAE;QACL,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE;QAC5C,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE;KACrC;IACD,UAAU,EAAE;QACV,EAAE,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE;QACrD,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE;KACxC;IACD,MAAM,EAAE;QACN,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QACnC,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE;KACzC;IACD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACnD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACtD,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;CAC7D,CAAA;AAED,oFAAoF;AACpF,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,IAA6B,EAC7B,MAAgC;IAEhC,MAAM,MAAM,GAA4B;QACtC,UAAU,EAAE,oBAAoB;QAChC,OAAO,EAAE,IAAI;KACd,CAAA;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACjC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC1D,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACrB,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IAChD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAwC,CAAA;QAC7E,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;gBAClB,OAAO,EAAE,GAAG,CAAC,IAAI;gBACjB,GAAG,UAAU;aACd,CAAA;QACH,CAAC;aAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;YACxF,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG;gBAClB,OAAO,EAAE,GAAG,CAAC,IAAI;gBACjB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;aACtB,CAAA;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC;gBAAE,SAAQ;YACrD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChE,MAAM,SAAS,GAAG,KAAgC,CAAA;gBAClD,MAAM,CAAC,GAAG,CAAC,GAAG;oBACZ,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO;oBACtC,GAAG,SAAS;iBACb,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"composer.js","sourceRoot":"","sources":["../../src/schema/composer.ts"],"names":[],"mappings":"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"}
@@ -8,4 +8,16 @@ export interface ValidationResult {
8
8
  }
9
9
  /** Validates a JSON-LD schema object against Schema.org requirements. */
10
10
  export declare function validateSchema(schema: Record<string, unknown>): ValidationResult;
11
+ /**
12
+ * Validates emitted JSON-LD that may be a single node, an array of nodes, or a
13
+ * `@graph` wrapper (`{ '@context', '@graph': [...] }`) — the shape the compose
14
+ * path produces. Each node is checked with {@link validateSchema} and its field
15
+ * paths are prefixed with the node's position so a caller can pinpoint which
16
+ * node in the graph is missing a required field.
17
+ *
18
+ * This is the safety net that connects the validator to the compose path: nodes
19
+ * missing required fields are surfaced as errors instead of silently shipping
20
+ * invalid structured data.
21
+ */
22
+ export declare function validateSchemaGraph(input: Record<string, unknown> | Array<Record<string, unknown>>): ValidationResult;
11
23
  //# sourceMappingURL=validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/schema/validator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;KAC9B,CAAC,CAAA;CACH;AA8BD,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,CAqFhF"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/schema/validator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;KAC9B,CAAC,CAAA;CACH;AA8BD,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,CAqFhF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9D,gBAAgB,CAgClB"}
@@ -104,4 +104,45 @@ export function validateSchema(schema) {
104
104
  const hasErrors = errors.some((e) => e.severity === 'error');
105
105
  return { valid: !hasErrors, errors };
106
106
  }
107
+ /**
108
+ * Validates emitted JSON-LD that may be a single node, an array of nodes, or a
109
+ * `@graph` wrapper (`{ '@context', '@graph': [...] }`) — the shape the compose
110
+ * path produces. Each node is checked with {@link validateSchema} and its field
111
+ * paths are prefixed with the node's position so a caller can pinpoint which
112
+ * node in the graph is missing a required field.
113
+ *
114
+ * This is the safety net that connects the validator to the compose path: nodes
115
+ * missing required fields are surfaced as errors instead of silently shipping
116
+ * invalid structured data.
117
+ */
118
+ export function validateSchemaGraph(input) {
119
+ let graph;
120
+ let context;
121
+ if (Array.isArray(input)) {
122
+ graph = input;
123
+ context = undefined;
124
+ }
125
+ else if (Array.isArray(input['@graph'])) {
126
+ graph = input['@graph'];
127
+ context = input['@context'];
128
+ }
129
+ else {
130
+ // Not a graph/array — validate the single node directly.
131
+ return validateSchema(input);
132
+ }
133
+ const errors = [];
134
+ graph.forEach((node, i) => {
135
+ // A `@graph` shares a single top-level `@context`; don't flag every node for
136
+ // a missing `@context` when the wrapper provides one.
137
+ const nodeForCheck = context !== undefined && node['@context'] === undefined
138
+ ? { ...node, '@context': context }
139
+ : node;
140
+ const result = validateSchema(nodeForCheck);
141
+ for (const err of result.errors) {
142
+ errors.push({ ...err, field: `@graph[${i}].${err.field}` });
143
+ }
144
+ });
145
+ const hasErrors = errors.some((e) => e.severity === 'error');
146
+ return { valid: !hasErrors, errors };
147
+ }
107
148
  //# sourceMappingURL=validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/schema/validator.ts"],"names":[],"mappings":"AASA,MAAM,eAAe,GAA6B;IAChD,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,eAAe,CAAC;IAChD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,MAAM,CAAC;IAChB,YAAY,EAAE,CAAC,MAAM,CAAC;IACtB,KAAK,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;IAC5B,OAAO,EAAE,CAAC,YAAY,CAAC;IACvB,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,UAAU,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,oBAAoB,CAAC;IACzD,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;IAClC,MAAM,EAAE,CAAC,cAAc,EAAE,QAAQ,EAAE,cAAc,CAAC;IAClD,OAAO,EAAE,CAAC,MAAM,CAAC;CAClB,CAAA;AAED,MAAM,kBAAkB,GAA6B;IACnD,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,CAAC;IAC9D,OAAO,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC;IAC/B,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,YAAY,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;IAC7B,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,CAAC;IACtD,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC;IACpC,UAAU,EAAE,CAAC,aAAa,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,CAAC;IAC3E,aAAa,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,KAAK,CAAC;IACnD,MAAM,EAAE,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,OAAO,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,CAAC;CACrD,CAAA;AAED,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAC,MAA+B;IAC5D,MAAM,MAAM,GAA+B,EAAE,CAAA;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAuB,CAAA;IAElD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,mDAAmD;YAC5D,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC;YACV,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,yDAAyD;YAClE,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAA;QACF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;IACjC,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IAC5C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAClF,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK;gBACL,OAAO,EAAE,mBAAmB,KAAK,yBAAyB,IAAI,EAAE;gBAChE,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IAClD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAClF,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK;gBACL,OAAO,EAAE,sBAAsB,KAAK,yBAAyB,IAAI,EAAE;gBACnE,QAAQ,EAAE,SAAS;aACpB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;QACnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,UAAU;gBACjB,OAAO,EAAE,sEAAsE;gBAC/E,QAAQ,EAAE,SAAS;aACpB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAmC,CAAA;QACxE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,CAAA;YACvB,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,UAAU,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK,EAAE,cAAc,CAAC,SAAS;oBAC/B,OAAO,EAAE,sCAAsC;oBAC/C,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAA;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK,EAAE,cAAc,CAAC,QAAQ;oBAC9B,OAAO,EAAE,8DAA8D;oBACvE,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAA;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,CAAC,gBAAgB,CAAwC,CAAA;YACzE,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CAAC;oBACV,KAAK,EAAE,cAAc,CAAC,uBAAuB;oBAC7C,OAAO,EAAE,wCAAwC;oBACjD,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAA;IAC5D,OAAO,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,CAAA;AACtC,CAAC"}
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/schema/validator.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,14 @@ export interface SitemapEntry {
4
4
  changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
5
5
  priority?: number;
6
6
  }
7
+ /**
8
+ * Google rejects a sitemap file with more than 50,000 URLs or larger than 50 MB
9
+ * uncompressed. `generateCollectionSitemap` enforces both — a consumer feeding
10
+ * it an entire collection must paginate upstream (mirrors the core route, which
11
+ * splits at SITEMAP_PAGE_SIZE) rather than emit an oversized file Google drops.
12
+ */
13
+ export declare const SITEMAP_MAX_URLS = 50000;
14
+ export declare const SITEMAP_MAX_BYTES: number;
7
15
  export interface ImageSitemapEntry {
8
16
  pageUrl: string;
9
17
  images: Array<{
@@ -52,6 +60,13 @@ export interface CollectionSitemapConfig {
52
60
  sitemapChangeFreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
53
61
  excludeFromSitemap?: boolean;
54
62
  archivePath?: string;
63
+ /**
64
+ * The newest child entry's last-modified timestamp (ISO 8601). Used as the
65
+ * `<lastmod>` for this collection in the sitemap index. Prefer an accurate
66
+ * value from the collection's most-recently-updated document — a lastmod that
67
+ * changes on every fetch trains crawlers to ignore the signal.
68
+ */
69
+ lastmod?: string;
55
70
  }
56
71
  /**
57
72
  * Build the public URL for a document given its collection config and slug.
@@ -59,7 +74,15 @@ export interface CollectionSitemapConfig {
59
74
  * - Posts (urlPrefix: "blog") -> `{baseUrl}/blog/{slug}`
60
75
  */
61
76
  export declare function buildDocumentUrl(baseUrl: string, urlPrefix: string | undefined, slug: string): string;
62
- /** Generates a sitemap index XML referencing per-collection sitemaps. */
77
+ /**
78
+ * Generates a sitemap index XML referencing per-collection sitemaps.
79
+ *
80
+ * Child URLs follow the same Yoast-style naming the core route serves
81
+ * (`{base}/{name}-sitemap.xml`). `<lastmod>` is derived from each collection's
82
+ * newest child entry (`CollectionSitemapConfig.lastmod`) and omitted when
83
+ * unknown — never stamped with `Date.now()`, which would churn on every fetch
84
+ * and train crawlers to ignore lastmod entirely.
85
+ */
63
86
  export declare function generateSitemapIndex(collections: (string | CollectionSitemapConfig)[], baseUrl: string): string;
64
87
  /**
65
88
  * Generates a sitemap XML for a collection's documents.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sitemap/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sitemap/index.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,12 @@
1
+ import { sitemapBaseName, collectionSitemapFilename } from '@actuate-media/cms-core';
2
+ /**
3
+ * Google rejects a sitemap file with more than 50,000 URLs or larger than 50 MB
4
+ * uncompressed. `generateCollectionSitemap` enforces both — a consumer feeding
5
+ * it an entire collection must paginate upstream (mirrors the core route, which
6
+ * splits at SITEMAP_PAGE_SIZE) rather than emit an oversized file Google drops.
7
+ */
8
+ export const SITEMAP_MAX_URLS = 50_000;
9
+ export const SITEMAP_MAX_BYTES = 50 * 1024 * 1024;
1
10
  function xmlEscape(str) {
2
11
  return str
3
12
  .replace(/&/g, '&amp;')
@@ -19,7 +28,15 @@ export function buildDocumentUrl(baseUrl, urlPrefix, slug) {
19
28
  }
20
29
  return `${base}/${slug}`;
21
30
  }
22
- /** Generates a sitemap index XML referencing per-collection sitemaps. */
31
+ /**
32
+ * Generates a sitemap index XML referencing per-collection sitemaps.
33
+ *
34
+ * Child URLs follow the same Yoast-style naming the core route serves
35
+ * (`{base}/{name}-sitemap.xml`). `<lastmod>` is derived from each collection's
36
+ * newest child entry (`CollectionSitemapConfig.lastmod`) and omitted when
37
+ * unknown — never stamped with `Date.now()`, which would churn on every fetch
38
+ * and train crawlers to ignore lastmod entirely.
39
+ */
23
40
  export function generateSitemapIndex(collections, baseUrl) {
24
41
  const base = baseUrl.replace(/\/$/, '');
25
42
  const sitemaps = collections
@@ -29,8 +46,14 @@ export function generateSitemapIndex(collections, baseUrl) {
29
46
  return !col.excludeFromSitemap;
30
47
  })
31
48
  .map((col) => {
32
- const slug = typeof col === 'string' ? col : col.slug;
33
- return ` <sitemap>\n <loc>${xmlEscape(base)}/sitemaps/${xmlEscape(slug)}.xml</loc>\n <lastmod>${new Date().toISOString()}</lastmod>\n </sitemap>`;
49
+ const cfg = typeof col === 'string' ? { slug: col } : col;
50
+ const baseName = sitemapBaseName({ slug: cfg.slug, type: cfg.type });
51
+ const loc = `${base}/${collectionSitemapFilename(baseName, 0)}`;
52
+ let xml = ` <sitemap>\n <loc>${xmlEscape(loc)}</loc>`;
53
+ if (cfg.lastmod)
54
+ xml += `\n <lastmod>${xmlEscape(cfg.lastmod)}</lastmod>`;
55
+ xml += '\n </sitemap>';
56
+ return xml;
34
57
  })
35
58
  .join('\n');
36
59
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -53,6 +76,10 @@ export function generateCollectionSitemap(entries, baseUrl, collectionConfig) {
53
76
  priority: 0.6,
54
77
  });
55
78
  }
79
+ if (allEntries.length > SITEMAP_MAX_URLS) {
80
+ throw new RangeError(`Sitemap would contain ${allEntries.length} URLs, exceeding the ${SITEMAP_MAX_URLS} limit. ` +
81
+ 'Paginate the collection into multiple sitemap files.');
82
+ }
56
83
  const urls = allEntries
57
84
  .map((entry) => {
58
85
  let loc;
@@ -82,10 +109,16 @@ export function generateCollectionSitemap(entries, baseUrl, collectionConfig) {
82
109
  return xml;
83
110
  })
84
111
  .join('\n');
85
- return `<?xml version="1.0" encoding="UTF-8"?>
112
+ const xml = `<?xml version="1.0" encoding="UTF-8"?>
86
113
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
87
114
  ${urls}
88
115
  </urlset>`;
116
+ const bytes = new TextEncoder().encode(xml).length;
117
+ if (bytes > SITEMAP_MAX_BYTES) {
118
+ throw new RangeError(`Sitemap is ${bytes} bytes, exceeding the ${SITEMAP_MAX_BYTES}-byte (50 MB) limit. ` +
119
+ 'Paginate the collection into multiple sitemap files.');
120
+ }
121
+ return xml;
89
122
  }
90
123
  /** Generates a Google Image sitemap extension. */
91
124
  export function generateImageSitemap(entries) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sitemap/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sitemap/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@actuate-media/plugin-seo",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
+ "license": "MIT",
4
5
  "repository": {
5
6
  "type": "git",
6
- "url": "https://github.com/actuatecms/actuatecms.git",
7
+ "url": "https://github.com/actuate-media/actuatecms.git",
7
8
  "directory": "packages/plugin-seo"
8
9
  },
9
10
  "publishConfig": {
@@ -27,7 +28,7 @@
27
28
  "@types/react": "^19.0.0",
28
29
  "typescript": "^5.7.0",
29
30
  "vitest": "^4.1.0",
30
- "@actuate-media/cms-core": "0.77.3"
31
+ "@actuate-media/cms-core": "0.92.0"
31
32
  },
32
33
  "peerDependencies": {
33
34
  "@actuate-media/cms-core": ">=0.1.0",