@actuate-media/cms-core 0.65.0 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/dist/__tests__/api/ai-quality.test.js +73 -0
  3. package/dist/__tests__/api/ai-quality.test.js.map +1 -1
  4. package/dist/__tests__/api/llms-txt.test.js +59 -0
  5. package/dist/__tests__/api/llms-txt.test.js.map +1 -1
  6. package/dist/__tests__/api/public-seo.test.js +402 -4
  7. package/dist/__tests__/api/public-seo.test.js.map +1 -1
  8. package/dist/__tests__/api/route-contracts.test.js +7 -0
  9. package/dist/__tests__/api/route-contracts.test.js.map +1 -1
  10. package/dist/__tests__/content/slug.test.d.ts +2 -0
  11. package/dist/__tests__/content/slug.test.d.ts.map +1 -0
  12. package/dist/__tests__/content/slug.test.js +68 -0
  13. package/dist/__tests__/content/slug.test.js.map +1 -0
  14. package/dist/__tests__/middleware.test.js +47 -0
  15. package/dist/__tests__/middleware.test.js.map +1 -1
  16. package/dist/__tests__/redirects/auto-301.test.d.ts +2 -0
  17. package/dist/__tests__/redirects/auto-301.test.d.ts.map +1 -0
  18. package/dist/__tests__/redirects/auto-301.test.js +172 -0
  19. package/dist/__tests__/redirects/auto-301.test.js.map +1 -0
  20. package/dist/__tests__/seo/ai-bots.test.d.ts +2 -0
  21. package/dist/__tests__/seo/ai-bots.test.d.ts.map +1 -0
  22. package/dist/__tests__/seo/ai-bots.test.js +53 -0
  23. package/dist/__tests__/seo/ai-bots.test.js.map +1 -0
  24. package/dist/__tests__/seo/alt-text.test.d.ts +2 -0
  25. package/dist/__tests__/seo/alt-text.test.d.ts.map +1 -0
  26. package/dist/__tests__/seo/alt-text.test.js +47 -0
  27. package/dist/__tests__/seo/alt-text.test.js.map +1 -0
  28. package/dist/__tests__/seo/feeds.test.d.ts +2 -0
  29. package/dist/__tests__/seo/feeds.test.d.ts.map +1 -0
  30. package/dist/__tests__/seo/feeds.test.js +61 -0
  31. package/dist/__tests__/seo/feeds.test.js.map +1 -0
  32. package/dist/__tests__/seo/freshness.test.d.ts +2 -0
  33. package/dist/__tests__/seo/freshness.test.d.ts.map +1 -0
  34. package/dist/__tests__/seo/freshness.test.js +89 -0
  35. package/dist/__tests__/seo/freshness.test.js.map +1 -0
  36. package/dist/__tests__/seo/meta-tags-alternates.test.d.ts +2 -0
  37. package/dist/__tests__/seo/meta-tags-alternates.test.d.ts.map +1 -0
  38. package/dist/__tests__/seo/meta-tags-alternates.test.js +52 -0
  39. package/dist/__tests__/seo/meta-tags-alternates.test.js.map +1 -0
  40. package/dist/__tests__/seo/page-meta.test.js +230 -14
  41. package/dist/__tests__/seo/page-meta.test.js.map +1 -1
  42. package/dist/__tests__/seo/sitemap-notify.test.js +77 -1
  43. package/dist/__tests__/seo/sitemap-notify.test.js.map +1 -1
  44. package/dist/__tests__/validation/publish.test.d.ts +2 -0
  45. package/dist/__tests__/validation/publish.test.d.ts.map +1 -0
  46. package/dist/__tests__/validation/publish.test.js +164 -0
  47. package/dist/__tests__/validation/publish.test.js.map +1 -0
  48. package/dist/actions.d.ts.map +1 -1
  49. package/dist/actions.js +172 -8
  50. package/dist/actions.js.map +1 -1
  51. package/dist/api/route-helpers.d.ts +8 -0
  52. package/dist/api/route-helpers.d.ts.map +1 -1
  53. package/dist/api/route-helpers.js +20 -0
  54. package/dist/api/route-helpers.js.map +1 -1
  55. package/dist/api/routes/ai-seo.d.ts.map +1 -1
  56. package/dist/api/routes/ai-seo.js +32 -1
  57. package/dist/api/routes/ai-seo.js.map +1 -1
  58. package/dist/api/routes/auth.d.ts.map +1 -1
  59. package/dist/api/routes/auth.js +2 -1
  60. package/dist/api/routes/auth.js.map +1 -1
  61. package/dist/api/routes/documents.d.ts.map +1 -1
  62. package/dist/api/routes/documents.js +3 -3
  63. package/dist/api/routes/documents.js.map +1 -1
  64. package/dist/api/routes/seo-public.d.ts.map +1 -1
  65. package/dist/api/routes/seo-public.js +371 -62
  66. package/dist/api/routes/seo-public.js.map +1 -1
  67. package/dist/api/routes/seo.d.ts.map +1 -1
  68. package/dist/api/routes/seo.js +21 -10
  69. package/dist/api/routes/seo.js.map +1 -1
  70. package/dist/api/routes/url-resolution.d.ts.map +1 -1
  71. package/dist/api/routes/url-resolution.js +40 -1
  72. package/dist/api/routes/url-resolution.js.map +1 -1
  73. package/dist/api/routes/users.d.ts.map +1 -1
  74. package/dist/api/routes/users.js +6 -3
  75. package/dist/api/routes/users.js.map +1 -1
  76. package/dist/client.d.ts +1 -0
  77. package/dist/client.d.ts.map +1 -1
  78. package/dist/client.js +3 -0
  79. package/dist/client.js.map +1 -1
  80. package/dist/config/types.d.ts +35 -1
  81. package/dist/config/types.d.ts.map +1 -1
  82. package/dist/content/index.d.ts +1 -0
  83. package/dist/content/index.d.ts.map +1 -1
  84. package/dist/content/index.js +1 -0
  85. package/dist/content/index.js.map +1 -1
  86. package/dist/content/slug.d.ts +40 -0
  87. package/dist/content/slug.d.ts.map +1 -0
  88. package/dist/content/slug.js +78 -0
  89. package/dist/content/slug.js.map +1 -0
  90. package/dist/content/structured-data.d.ts +6 -0
  91. package/dist/content/structured-data.d.ts.map +1 -1
  92. package/dist/content/structured-data.js +6 -0
  93. package/dist/content/structured-data.js.map +1 -1
  94. package/dist/content-health/scanner.d.ts +4 -3
  95. package/dist/content-health/scanner.d.ts.map +1 -1
  96. package/dist/content-health/scanner.js +6 -12
  97. package/dist/content-health/scanner.js.map +1 -1
  98. package/dist/middleware.d.ts +1 -0
  99. package/dist/middleware.d.ts.map +1 -1
  100. package/dist/middleware.js +11 -2
  101. package/dist/middleware.js.map +1 -1
  102. package/dist/redirects/auto.d.ts +45 -0
  103. package/dist/redirects/auto.d.ts.map +1 -0
  104. package/dist/redirects/auto.js +55 -0
  105. package/dist/redirects/auto.js.map +1 -0
  106. package/dist/redirects/index.d.ts +2 -0
  107. package/dist/redirects/index.d.ts.map +1 -1
  108. package/dist/redirects/index.js +1 -0
  109. package/dist/redirects/index.js.map +1 -1
  110. package/dist/seo/ai-bots.d.ts +42 -0
  111. package/dist/seo/ai-bots.d.ts.map +1 -0
  112. package/dist/seo/ai-bots.js +104 -0
  113. package/dist/seo/ai-bots.js.map +1 -0
  114. package/dist/seo/alt-text.d.ts +39 -0
  115. package/dist/seo/alt-text.d.ts.map +1 -0
  116. package/dist/seo/alt-text.js +67 -0
  117. package/dist/seo/alt-text.js.map +1 -0
  118. package/dist/seo/analysis.d.ts.map +1 -1
  119. package/dist/seo/analysis.js +7 -11
  120. package/dist/seo/analysis.js.map +1 -1
  121. package/dist/seo/audit-engine.d.ts +1 -0
  122. package/dist/seo/audit-engine.d.ts.map +1 -1
  123. package/dist/seo/audit-engine.js +4 -4
  124. package/dist/seo/audit-engine.js.map +1 -1
  125. package/dist/seo/audit-runner.d.ts.map +1 -1
  126. package/dist/seo/audit-runner.js +1 -0
  127. package/dist/seo/audit-runner.js.map +1 -1
  128. package/dist/seo/feeds.d.ts +36 -0
  129. package/dist/seo/feeds.d.ts.map +1 -0
  130. package/dist/seo/feeds.js +71 -0
  131. package/dist/seo/feeds.js.map +1 -0
  132. package/dist/seo/index.d.ts +9 -3
  133. package/dist/seo/index.d.ts.map +1 -1
  134. package/dist/seo/index.js +5 -2
  135. package/dist/seo/index.js.map +1 -1
  136. package/dist/seo/llms-txt.d.ts.map +1 -1
  137. package/dist/seo/llms-txt.js +13 -2
  138. package/dist/seo/llms-txt.js.map +1 -1
  139. package/dist/seo/meta-tags.d.ts +14 -0
  140. package/dist/seo/meta-tags.d.ts.map +1 -1
  141. package/dist/seo/meta-tags.js +21 -2
  142. package/dist/seo/meta-tags.js.map +1 -1
  143. package/dist/seo/page-meta.d.ts +47 -0
  144. package/dist/seo/page-meta.d.ts.map +1 -1
  145. package/dist/seo/page-meta.js +280 -70
  146. package/dist/seo/page-meta.js.map +1 -1
  147. package/dist/seo/sitemap-notify.d.ts +30 -0
  148. package/dist/seo/sitemap-notify.d.ts.map +1 -1
  149. package/dist/seo/sitemap-notify.js +87 -0
  150. package/dist/seo/sitemap-notify.js.map +1 -1
  151. package/dist/validation/publish.d.ts +53 -0
  152. package/dist/validation/publish.d.ts.map +1 -0
  153. package/dist/validation/publish.js +75 -0
  154. package/dist/validation/publish.js.map +1 -0
  155. package/package.json +1 -1
@@ -0,0 +1,89 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { resolveContentDates } from '../../seo/page-meta.js';
3
+ import { generateLlmsTxt } from '../../seo/llms-txt.js';
4
+ import { buildJsonFeed, buildRssFeed } from '../../seo/feeds.js';
5
+ describe('resolveContentDates', () => {
6
+ it('prefers DB publishedAt/updatedAt', () => {
7
+ const pub = new Date('2024-01-01T00:00:00.000Z');
8
+ const upd = new Date('2024-06-01T00:00:00.000Z');
9
+ expect(resolveContentDates({ doc: { publishedAt: pub, updatedAt: upd } })).toEqual({
10
+ datePublished: pub.toISOString(),
11
+ dateModified: upd.toISOString(),
12
+ });
13
+ });
14
+ it('falls back to editorial date fields for publication', () => {
15
+ const r = resolveContentDates({
16
+ doc: { updatedAt: new Date('2024-06-01T00:00:00.000Z') },
17
+ data: { publishedDate: '2024-01-15' },
18
+ });
19
+ expect(r.datePublished).toBe(new Date('2024-01-15').toISOString());
20
+ });
21
+ it('never lets dateModified predate publication', () => {
22
+ const r = resolveContentDates({
23
+ doc: { publishedAt: new Date('2024-01-01T00:00:00.000Z') },
24
+ data: {},
25
+ });
26
+ expect(r.dateModified).toBe(r.datePublished);
27
+ });
28
+ it('returns empty object when no dates are available', () => {
29
+ expect(resolveContentDates({ doc: {} })).toEqual({});
30
+ });
31
+ });
32
+ describe('llms.txt freshness', () => {
33
+ it('appends an Updated: date to each entry', () => {
34
+ const out = generateLlmsTxt({ siteName: 'Acme', siteUrl: 'https://acme.test' }, [
35
+ {
36
+ title: 'Hello',
37
+ url: 'https://acme.test/hello',
38
+ description: 'A post',
39
+ updatedAt: '2024-06-01T12:00:00.000Z',
40
+ collection: 'posts',
41
+ },
42
+ ]);
43
+ expect(out).toContain('- [Hello](https://acme.test/hello): A post — Updated: 2024-06-01');
44
+ });
45
+ it('omits the date marker when updatedAt is absent', () => {
46
+ const out = generateLlmsTxt({ siteName: 'Acme', siteUrl: 'https://acme.test' }, [
47
+ { title: 'Hello', url: 'https://acme.test/hello', collection: 'posts' },
48
+ ]);
49
+ expect(out).toContain('- [Hello](https://acme.test/hello)');
50
+ expect(out).not.toContain('Updated:');
51
+ });
52
+ });
53
+ describe('feed date_modified', () => {
54
+ const channel = {
55
+ title: 'Acme',
56
+ homeUrl: 'https://acme.test',
57
+ feedUrl: 'https://acme.test/feed.json',
58
+ };
59
+ it('emits date_modified in JSON Feed when present', () => {
60
+ const json = JSON.parse(buildJsonFeed(channel, [
61
+ {
62
+ url: 'https://acme.test/a',
63
+ title: 'A',
64
+ date: '2024-01-01T00:00:00.000Z',
65
+ dateModified: '2024-06-01T00:00:00.000Z',
66
+ },
67
+ ]));
68
+ expect(json.items[0].date_published).toBe('2024-01-01T00:00:00.000Z');
69
+ expect(json.items[0].date_modified).toBe('2024-06-01T00:00:00.000Z');
70
+ });
71
+ it('omits date_modified when not provided', () => {
72
+ const json = JSON.parse(buildJsonFeed(channel, [
73
+ { url: 'https://acme.test/a', title: 'A', date: '2024-01-01T00:00:00.000Z' },
74
+ ]));
75
+ expect(json.items[0].date_modified).toBeUndefined();
76
+ });
77
+ it('RSS still emits pubDate from the publication date', () => {
78
+ const rss = buildRssFeed(channel, [
79
+ {
80
+ url: 'https://acme.test/a',
81
+ title: 'A',
82
+ date: '2024-01-01T00:00:00.000Z',
83
+ dateModified: '2024-06-01T00:00:00.000Z',
84
+ },
85
+ ]);
86
+ expect(rss).toContain('<pubDate>');
87
+ });
88
+ });
89
+ //# sourceMappingURL=freshness.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/freshness.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=meta-tags-alternates.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-tags-alternates.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/seo/meta-tags-alternates.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { generateNextMetadata, renderMetaTagsHtml } from '../../seo/meta-tags.js';
3
+ const BASE = {
4
+ title: 'Hello',
5
+ description: 'A page',
6
+ url: 'https://example.com/hello',
7
+ siteName: 'Acme',
8
+ canonical: 'https://example.com/hello',
9
+ };
10
+ describe('meta-tags: metadataBase + hreflang alternates', () => {
11
+ it('sets metadataBase as a URL in the Next metadata object', () => {
12
+ const meta = generateNextMetadata({ ...BASE, metadataBase: 'https://example.com' });
13
+ expect(meta.metadataBase).toBeInstanceOf(URL);
14
+ expect(meta.metadataBase.href).toBe('https://example.com/');
15
+ });
16
+ it('ignores an unparseable metadataBase without throwing', () => {
17
+ const meta = generateNextMetadata({ ...BASE, metadataBase: 'not a url' });
18
+ expect(meta.metadataBase).toBeUndefined();
19
+ });
20
+ it('maps hreflang alternates to alternates.languages alongside canonical', () => {
21
+ const meta = generateNextMetadata({
22
+ ...BASE,
23
+ alternates: [
24
+ { hreflang: 'en', href: 'https://example.com/hello' },
25
+ { hreflang: 'fr', href: 'https://example.com/fr/bonjour' },
26
+ { hreflang: 'x-default', href: 'https://example.com/hello' },
27
+ ],
28
+ });
29
+ expect(meta.alternates?.canonical).toBe('https://example.com/hello');
30
+ expect(meta.alternates?.languages).toEqual({
31
+ en: 'https://example.com/hello',
32
+ fr: 'https://example.com/fr/bonjour',
33
+ 'x-default': 'https://example.com/hello',
34
+ });
35
+ });
36
+ it('renders <link rel="alternate" hreflang> tags in HTML output', () => {
37
+ const html = renderMetaTagsHtml({
38
+ ...BASE,
39
+ alternates: [
40
+ { hreflang: 'en', href: 'https://example.com/hello' },
41
+ { hreflang: 'fr', href: 'https://example.com/fr/bonjour' },
42
+ ],
43
+ });
44
+ expect(html).toContain('<link rel="alternate" hreflang="en" href="https://example.com/hello" />');
45
+ expect(html).toContain('<link rel="alternate" hreflang="fr" href="https://example.com/fr/bonjour" />');
46
+ });
47
+ it('emits no alternates block when none are supplied and no canonical', () => {
48
+ const meta = generateNextMetadata({ ...BASE, canonical: undefined });
49
+ expect(meta.alternates).toBeUndefined();
50
+ });
51
+ });
52
+ //# sourceMappingURL=meta-tags-alternates.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-tags-alternates.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/meta-tags-alternates.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAqB,MAAM,wBAAwB,CAAA;AAEpG,MAAM,IAAI,GAAiB;IACzB,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,QAAQ;IACrB,GAAG,EAAE,2BAA2B;IAChC,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,2BAA2B;CACvC,CAAA;AAED,QAAQ,CAAC,+CAA+C,EAAE,GAAG,EAAE;IAC7D,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,oBAAoB,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,qBAAqB,EAAE,CAGjF,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAA;QAC7C,MAAM,CAAE,IAAI,CAAC,YAAoB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,IAAI,GAAG,oBAAoB,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,CAGvE,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,IAAI,GAAG,oBAAoB,CAAC;YAChC,GAAG,IAAI;YACP,UAAU,EAAE;gBACV,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,2BAA2B,EAAE;gBACrD,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,gCAAgC,EAAE;gBAC1D,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,2BAA2B,EAAE;aAC7D;SACF,CAAgF,CAAA;QAEjF,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QACpE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC;YACzC,EAAE,EAAE,2BAA2B;YAC/B,EAAE,EAAE,gCAAgC;YACpC,WAAW,EAAE,2BAA2B;SACzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,IAAI,GAAG,kBAAkB,CAAC;YAC9B,GAAG,IAAI;YACP,UAAU,EAAE;gBACV,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,2BAA2B,EAAE;gBACrD,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,gCAAgC,EAAE;aAC3D;SACF,CAAC,CAAA;QACF,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CACpB,yEAAyE,CAC1E,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CACpB,8EAA8E,CAC/E,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,IAAI,GAAG,oBAAoB,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAA4B,CAAA;QAC/F,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,aAAa,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,5 +1,17 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { composePageMeta, detectSchemaType } from '../../seo/page-meta.js';
3
+ /** Pull the @graph array out of a composed JSON-LD result. */
4
+ function graphOf(jsonLd) {
5
+ const g = jsonLd?.['@graph'];
6
+ return Array.isArray(g) ? g : [];
7
+ }
8
+ /** Find the first graph node whose @type matches (string or array form). */
9
+ function nodeOfType(jsonLd, type) {
10
+ return graphOf(jsonLd).find((n) => {
11
+ const t = n['@type'];
12
+ return t === type || (Array.isArray(t) && t.includes(type));
13
+ });
14
+ }
3
15
  function makeCollection(overrides = {}) {
4
16
  return {
5
17
  slug: 'pages',
@@ -57,6 +69,33 @@ describe('composePageMeta', () => {
57
69
  });
58
70
  expect(result.url).toBe('https://example.com');
59
71
  });
72
+ it('honors the plugin-seo canonicalUrl field name', () => {
73
+ const result = composePageMeta({
74
+ doc: {
75
+ id: '1',
76
+ collection: 'posts',
77
+ slug: 'hello',
78
+ data: { title: 'Hello', canonicalUrl: 'https://example.com/canonical-target' },
79
+ },
80
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
81
+ config: makeConfig(),
82
+ });
83
+ expect(result.canonical).toBe('https://example.com/canonical-target');
84
+ });
85
+ it('honors lowercase noindex and plugin-seo robotsNoindex field names', () => {
86
+ const lower = composePageMeta({
87
+ doc: { id: '1', collection: 'posts', slug: 'a', data: { title: 'A', noindex: true } },
88
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
89
+ config: makeConfig(),
90
+ });
91
+ expect(lower.meta['robots']).toContain('noindex');
92
+ const plugin = composePageMeta({
93
+ doc: { id: '2', collection: 'posts', slug: 'b', data: { title: 'B', robotsNoindex: true } },
94
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
95
+ config: makeConfig(),
96
+ });
97
+ expect(plugin.meta['robots']).toContain('noindex');
98
+ });
60
99
  it('prefers explicit pageSettings.metaTitle over data.title', () => {
61
100
  const result = composePageMeta({
62
101
  doc: {
@@ -71,7 +110,7 @@ describe('composePageMeta', () => {
71
110
  });
72
111
  expect(result.title).toBe('SEO Title');
73
112
  });
74
- it('composes BlogPosting JSON-LD for posts with author + publisher', () => {
113
+ it('composes a connected @graph with a BlogPosting node, author + publisher', () => {
75
114
  const result = composePageMeta({
76
115
  doc: {
77
116
  id: '1',
@@ -85,31 +124,133 @@ describe('composePageMeta', () => {
85
124
  organization: { name: 'Example Inc', logo: 'https://example.com/logo.png' },
86
125
  }),
87
126
  });
88
- expect(result.jsonLd).toMatchObject({
89
- '@context': 'https://schema.org',
127
+ expect(result.jsonLd?.['@context']).toBe('https://schema.org');
128
+ const article = nodeOfType(result.jsonLd, 'BlogPosting');
129
+ expect(article).toMatchObject({
90
130
  '@type': 'BlogPosting',
91
- name: 'First Post',
92
- description: 'Hello',
93
- url: 'https://example.com/blog/first-post',
131
+ headline: 'First Post',
94
132
  datePublished: '2026-01-01T00:00:00.000Z',
95
- author: { '@type': 'Person', name: 'Jane Doe' },
96
- publisher: {
97
- '@type': 'Organization',
98
- name: 'Example Inc',
99
- logo: { '@type': 'ImageObject', url: 'https://example.com/logo.png' },
133
+ // dateModified falls back to publication when no later edit exists.
134
+ dateModified: '2026-01-01T00:00:00.000Z',
135
+ publisher: { '@id': 'https://example.com/#organization' },
136
+ });
137
+ // The connected graph stacks WebSite + Organization site nodes.
138
+ expect(nodeOfType(result.jsonLd, 'WebSite')).toBeDefined();
139
+ const org = nodeOfType(result.jsonLd, 'Organization');
140
+ expect(org).toMatchObject({ name: 'Example Inc' });
141
+ // A Person node is present and the article references it.
142
+ const person = nodeOfType(result.jsonLd, 'Person');
143
+ expect(person).toMatchObject({ name: 'Jane Doe' });
144
+ expect(article?.author).toEqual({ '@id': person?.['@id'] });
145
+ });
146
+ it('emits article:published_time / article:modified_time OG tags for articles', () => {
147
+ const result = composePageMeta({
148
+ doc: {
149
+ id: '1',
150
+ collection: 'posts',
151
+ slug: 'p',
152
+ data: { title: 'P' },
153
+ publishedAt: '2026-01-01T00:00:00.000Z',
154
+ updatedAt: '2026-02-01T00:00:00.000Z',
100
155
  },
156
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
157
+ config: makeConfig(),
158
+ });
159
+ expect(result.metaHtml).toContain('article:published_time');
160
+ expect(result.metaHtml).toContain('2026-01-01T00:00:00.000Z');
161
+ expect(result.metaHtml).toContain('article:modified_time');
162
+ expect(result.metaHtml).toContain('2026-02-01T00:00:00.000Z');
163
+ });
164
+ it('uses an editorial publishedDate when the DB publishedAt is absent', () => {
165
+ const result = composePageMeta({
166
+ doc: {
167
+ id: '1',
168
+ collection: 'posts',
169
+ slug: 'p',
170
+ data: { title: 'P', schemaType: 'BlogPosting', publishedDate: '2025-03-10' },
171
+ },
172
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
173
+ config: makeConfig(),
101
174
  });
175
+ const article = nodeOfType(result.jsonLd, 'BlogPosting');
176
+ expect(article?.datePublished).toBe(new Date('2025-03-10').toISOString());
102
177
  });
103
- it('respects per-collection defaultSchemaType', () => {
178
+ it('respects per-collection defaultSchemaType as a graph entity node', () => {
104
179
  const result = composePageMeta({
105
- doc: { id: '1', collection: 'locations', slug: 'nyc', data: { title: 'NYC' } },
180
+ doc: {
181
+ id: '1',
182
+ collection: 'locations',
183
+ slug: 'nyc',
184
+ data: { title: 'NYC', phone: '555-0100' },
185
+ },
106
186
  collection: makeCollection({
107
187
  slug: 'locations',
108
188
  seo: { defaultSchemaType: 'LocalBusiness' },
109
189
  }),
110
190
  config: makeConfig(),
111
191
  });
112
- expect(result.jsonLd?.['@type']).toBe('LocalBusiness');
192
+ const biz = nodeOfType(result.jsonLd, 'LocalBusiness');
193
+ expect(biz).toMatchObject({ '@type': 'LocalBusiness', name: 'NYC', telephone: '555-0100' });
194
+ // The WebPage node cross-links to the business entity.
195
+ const webPage = nodeOfType(result.jsonLd, 'WebPage');
196
+ expect(webPage?.mainEntity).toEqual({ '@id': biz?.['@id'] });
197
+ });
198
+ it('derives a BreadcrumbList from the URL path (Home → … → page)', () => {
199
+ const result = composePageMeta({
200
+ doc: { id: '1', collection: 'posts', slug: 'hello', data: { title: 'Hello' } },
201
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
202
+ config: makeConfig(),
203
+ });
204
+ const crumbs = nodeOfType(result.jsonLd, 'BreadcrumbList');
205
+ expect(crumbs).toBeDefined();
206
+ const items = crumbs?.itemListElement;
207
+ expect(items.map((i) => i.name)).toEqual(['Home', 'Blog', 'Hello']);
208
+ expect(items[0].item).toBe('https://example.com');
209
+ expect(items[2].item).toBe('https://example.com/blog/hello');
210
+ });
211
+ it('does not emit a breadcrumb for the homepage', () => {
212
+ const result = composePageMeta({
213
+ doc: { id: '1', collection: 'pages', slug: 'home', data: { title: 'Home' } },
214
+ collection: makeCollection({ slug: 'pages', urlPrefix: '', type: 'page' }),
215
+ config: makeConfig(),
216
+ });
217
+ expect(nodeOfType(result.jsonLd, 'BreadcrumbList')).toBeUndefined();
218
+ });
219
+ it('emits Organization sameAs from config', () => {
220
+ const result = composePageMeta({
221
+ doc: { id: '1', collection: 'pages', slug: 'about', data: { title: 'About' } },
222
+ collection: makeCollection(),
223
+ config: makeConfig({
224
+ organization: {
225
+ name: 'Example Inc',
226
+ sameAs: ['https://twitter.com/example', 'https://linkedin.com/company/example'],
227
+ },
228
+ }),
229
+ });
230
+ const org = nodeOfType(result.jsonLd, 'Organization');
231
+ expect(org?.sameAs).toEqual([
232
+ 'https://twitter.com/example',
233
+ 'https://linkedin.com/company/example',
234
+ ]);
235
+ });
236
+ it('promotes FAQ pairs to FAQPage mainEntity on the WebPage node', () => {
237
+ const result = composePageMeta({
238
+ doc: {
239
+ id: '1',
240
+ collection: 'pages',
241
+ slug: 'faq',
242
+ data: {
243
+ title: 'FAQ',
244
+ faqItems: [{ question: 'Is it free?', answer: 'Yes.' }],
245
+ },
246
+ },
247
+ collection: makeCollection({ slug: 'faq' }),
248
+ config: makeConfig(),
249
+ });
250
+ const webPage = nodeOfType(result.jsonLd, 'FAQPage');
251
+ expect(webPage).toBeDefined();
252
+ const mainEntity = webPage?.mainEntity;
253
+ expect(mainEntity[0]).toMatchObject({ '@type': 'Question', name: 'Is it free?' });
113
254
  });
114
255
  it('honors doc-level structuredData verbatim when set', () => {
115
256
  const result = composePageMeta({
@@ -197,6 +338,81 @@ describe('composePageMeta', () => {
197
338
  });
198
339
  expect(result.meta['og:image']).toBe('https://example.com/api/cms/og.png?title=' + encodeURIComponent('About Us'));
199
340
  });
341
+ it('falls back to the page hero/featured image (object or string) for og:image', () => {
342
+ const fromObject = composePageMeta({
343
+ doc: {
344
+ id: '1',
345
+ collection: 'pages',
346
+ slug: 'about',
347
+ data: { title: 'About', featuredImage: { url: 'https://cdn.test/hero.jpg' } },
348
+ },
349
+ collection: makeCollection(),
350
+ config: makeConfig(),
351
+ });
352
+ expect(fromObject.meta['og:image']).toBe('https://cdn.test/hero.jpg');
353
+ const fromString = composePageMeta({
354
+ doc: {
355
+ id: '2',
356
+ collection: 'pages',
357
+ slug: 'team',
358
+ data: { title: 'Team', heroImage: 'https://cdn.test/team.png' },
359
+ },
360
+ collection: makeCollection(),
361
+ config: makeConfig(),
362
+ });
363
+ expect(fromString.meta['og:image']).toBe('https://cdn.test/team.png');
364
+ });
365
+ it('emits the GEO key takeaway as Schema.org abstract and a description fallback', () => {
366
+ const result = composePageMeta({
367
+ doc: {
368
+ id: '1',
369
+ collection: 'posts',
370
+ slug: 'guide',
371
+ data: { title: 'Guide', keyTakeaway: 'Set up the CMS in under five minutes.' },
372
+ publishedAt: '2026-01-01T00:00:00.000Z',
373
+ },
374
+ collection: makeCollection({ slug: 'posts', urlPrefix: 'blog', type: 'post' }),
375
+ config: makeConfig(),
376
+ });
377
+ // abstract appears on the article node in the @graph.
378
+ const article = nodeOfType(result.jsonLd, 'BlogPosting');
379
+ expect(article?.abstract).toBe('Set up the CMS in under five minutes.');
380
+ // With no meta description/excerpt, the takeaway becomes the description.
381
+ expect(result.description).toBe('Set up the CMS in under five minutes.');
382
+ expect(result.meta['og:description']).toBe('Set up the CMS in under five minutes.');
383
+ });
384
+ it('does not let the key takeaway override an explicit meta description', () => {
385
+ const result = composePageMeta({
386
+ doc: {
387
+ id: '1',
388
+ collection: 'pages',
389
+ slug: 'x',
390
+ data: {
391
+ title: 'X',
392
+ metaDescription: 'Explicit description.',
393
+ keyTakeaway: 'Takeaway summary.',
394
+ },
395
+ },
396
+ collection: makeCollection(),
397
+ config: makeConfig(),
398
+ });
399
+ expect(result.description).toBe('Explicit description.');
400
+ });
401
+ it('passes hreflang alternates through to the head and Next metadata', () => {
402
+ const result = composePageMeta({
403
+ doc: { id: '1', collection: 'pages', slug: 'about', data: { title: 'About' } },
404
+ collection: makeCollection(),
405
+ config: makeConfig(),
406
+ alternates: [
407
+ { hreflang: 'en', href: 'https://example.com/about' },
408
+ { hreflang: 'fr', href: 'https://example.com/fr/a-propos' },
409
+ ],
410
+ });
411
+ expect(result.metaHtml).toContain('<link rel="alternate" hreflang="fr" href="https://example.com/fr/a-propos" />');
412
+ const metadata = result.metadata;
413
+ expect(metadata.alternates?.languages?.fr).toBe('https://example.com/fr/a-propos');
414
+ expect(metadata.metadataBase).toBeInstanceOf(URL);
415
+ });
200
416
  it('escapes < in JSON-LD HTML so it cannot break out of <script>', () => {
201
417
  const result = composePageMeta({
202
418
  doc: { id: '1', collection: 'pages', slug: 'x', data: { title: '</script><img src=x>' } },
@@ -1 +1 @@
1
- {"version":3,"file":"page-meta.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/page-meta.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"page-meta.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/page-meta.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
- import { buildSearchEnginePings, buildSitemapUrl, notifySitemapOnPublish, } from '../../seo/sitemap-notify.js';
2
+ import { buildIndexNowSubmission, buildSearchEnginePings, buildSitemapUrl, INDEXNOW_ENDPOINT, notifySitemapOnPublish, } from '../../seo/sitemap-notify.js';
3
3
  import { DEFAULT_SEO_MODULE_SETTINGS } from '../../seo/config-store.js';
4
4
  const baseSettings = {
5
5
  sitemapEnabled: DEFAULT_SEO_MODULE_SETTINGS.sitemapEnabled,
@@ -30,6 +30,41 @@ describe('buildSearchEnginePings', () => {
30
30
  }
31
31
  });
32
32
  });
33
+ describe('buildIndexNowSubmission', () => {
34
+ const keyLocation = 'https://example.com/api/cms/indexnow-key.txt';
35
+ it('builds a submission for same-host URLs', () => {
36
+ const sub = buildIndexNowSubmission({
37
+ key: 'abc123',
38
+ keyLocation,
39
+ changedUrls: ['https://example.com/about', 'https://example.com/about'],
40
+ });
41
+ expect(sub).toEqual({
42
+ host: 'example.com',
43
+ key: 'abc123',
44
+ keyLocation,
45
+ urlList: ['https://example.com/about'],
46
+ });
47
+ });
48
+ it('returns null without a key or key location', () => {
49
+ expect(buildIndexNowSubmission({ key: null, keyLocation, changedUrls: ['https://example.com/a'] })).toBeNull();
50
+ expect(buildIndexNowSubmission({
51
+ key: 'k',
52
+ keyLocation: '',
53
+ changedUrls: ['https://example.com/a'],
54
+ })).toBeNull();
55
+ });
56
+ it('drops cross-host and non-absolute URLs (SSRF / spec guard)', () => {
57
+ const sub = buildIndexNowSubmission({
58
+ key: 'k',
59
+ keyLocation,
60
+ changedUrls: ['https://evil.com/x', '/relative', 'https://example.com/ok'],
61
+ });
62
+ expect(sub?.urlList).toEqual(['https://example.com/ok']);
63
+ });
64
+ it('returns null when nothing valid remains', () => {
65
+ expect(buildIndexNowSubmission({ key: 'k', keyLocation, changedUrls: ['https://evil.com/x'] })).toBeNull();
66
+ });
67
+ });
33
68
  describe('notifySitemapOnPublish', () => {
34
69
  it('does nothing when the sitemap is disabled', async () => {
35
70
  const fetchImpl = okFetch();
@@ -126,6 +161,47 @@ describe('notifySitemapOnPublish', () => {
126
161
  expect(res.pinged.sort()).toEqual(['bing', 'google']);
127
162
  expect(fetchImpl).toHaveBeenCalledTimes(2);
128
163
  });
164
+ it('submits changed URLs to IndexNow when a key is configured', async () => {
165
+ const calls = [];
166
+ const fetchImpl = vi.fn(async (url, init) => {
167
+ calls.push({ url, init });
168
+ return new Response('', { status: 200 });
169
+ });
170
+ const res = await notifySitemapOnPublish({
171
+ settings: baseSettings,
172
+ siteUrl: 'https://example.com',
173
+ environment: 'production',
174
+ fetchImpl,
175
+ changedUrls: ['https://example.com/about'],
176
+ indexNowKey: 'abc123',
177
+ indexNowKeyLocation: 'https://example.com/api/cms/indexnow-key.txt',
178
+ });
179
+ expect(res.pinged).toContain('indexnow');
180
+ const indexNowCall = calls.find((c) => c.url === INDEXNOW_ENDPOINT);
181
+ expect(indexNowCall).toBeDefined();
182
+ expect(indexNowCall?.init?.method).toBe('POST');
183
+ const body = JSON.parse(String(indexNowCall?.init?.body));
184
+ expect(body).toMatchObject({
185
+ host: 'example.com',
186
+ key: 'abc123',
187
+ urlList: ['https://example.com/about'],
188
+ });
189
+ });
190
+ it('skips IndexNow when no key is configured (legacy pings still fire)', async () => {
191
+ const fetchImpl = okFetch();
192
+ const res = await notifySitemapOnPublish({
193
+ settings: baseSettings,
194
+ siteUrl: 'https://example.com',
195
+ environment: 'production',
196
+ fetchImpl,
197
+ changedUrls: ['https://example.com/about'],
198
+ });
199
+ expect(res.pinged).not.toContain('indexnow');
200
+ expect(res.skipped).toContainEqual({
201
+ target: 'indexnow',
202
+ reason: 'not-configured-or-no-urls',
203
+ });
204
+ });
129
205
  it('refuses to ping when the site URL is missing', async () => {
130
206
  const fetchImpl = okFetch();
131
207
  const res = await notifySitemapOnPublish({