@actuate-media/cms-core 0.41.0 → 0.42.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.
- package/dist/__tests__/seo/settings-defaults.test.d.ts +2 -0
- package/dist/__tests__/seo/settings-defaults.test.d.ts.map +1 -0
- package/dist/__tests__/seo/settings-defaults.test.js +189 -0
- package/dist/__tests__/seo/settings-defaults.test.js.map +1 -0
- package/dist/__tests__/seo/sitemap-notify.test.d.ts +2 -0
- package/dist/__tests__/seo/sitemap-notify.test.d.ts.map +1 -0
- package/dist/__tests__/seo/sitemap-notify.test.js +191 -0
- package/dist/__tests__/seo/sitemap-notify.test.js.map +1 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +80 -3
- package/dist/actions.js.map +1 -1
- package/dist/api/handlers.d.ts.map +1 -1
- package/dist/api/handlers.js +62 -10
- package/dist/api/handlers.js.map +1 -1
- package/dist/config/types.d.ts +49 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/page-builder/schema.d.ts +2 -2
- package/dist/seo/config-store.d.ts +2 -0
- package/dist/seo/config-store.d.ts.map +1 -1
- package/dist/seo/config-store.js +2 -0
- package/dist/seo/config-store.js.map +1 -1
- package/dist/seo/index.d.ts +6 -4
- package/dist/seo/index.d.ts.map +1 -1
- package/dist/seo/index.js +3 -2
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/meta-tags.d.ts +36 -0
- package/dist/seo/meta-tags.d.ts.map +1 -1
- package/dist/seo/meta-tags.js +78 -0
- package/dist/seo/meta-tags.js.map +1 -1
- package/dist/seo/page-meta.d.ts.map +1 -1
- package/dist/seo/page-meta.js +47 -8
- package/dist/seo/page-meta.js.map +1 -1
- package/dist/seo/sitemap-notify.d.ts +85 -0
- package/dist/seo/sitemap-notify.d.ts.map +1 -0
- package/dist/seo/sitemap-notify.js +159 -0
- package/dist/seo/sitemap-notify.js.map +1 -0
- package/dist/seo/title-templates.d.ts +26 -0
- package/dist/seo/title-templates.d.ts.map +1 -1
- package/dist/seo/title-templates.js +83 -0
- package/dist/seo/title-templates.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-defaults.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/seo/settings-defaults.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { validateTitleTemplate, applySiteTitleTemplate, DEFAULT_SITE_TITLE_TEMPLATE, } from '../../seo/title-templates.js';
|
|
3
|
+
import { buildVerificationMetaEntries, renderVerificationMetaHtml, buildNextVerification, } from '../../seo/meta-tags.js';
|
|
4
|
+
import { mergeSiteSeoConfig } from '../../seo/config-store.js';
|
|
5
|
+
import { composePageMeta } from '../../seo/page-meta.js';
|
|
6
|
+
describe('validateTitleTemplate', () => {
|
|
7
|
+
it('accepts a template with known tokens', () => {
|
|
8
|
+
const r = validateTitleTemplate('%page% — %site%');
|
|
9
|
+
expect(r.valid).toBe(true);
|
|
10
|
+
expect(r.unknownTokens).toEqual([]);
|
|
11
|
+
});
|
|
12
|
+
it('treats an empty template as valid (falls back to default)', () => {
|
|
13
|
+
expect(validateTitleTemplate('').valid).toBe(true);
|
|
14
|
+
expect(validateTitleTemplate(' ').valid).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
it('rejects unsupported tokens', () => {
|
|
17
|
+
const r = validateTitleTemplate('%page% %bogus%');
|
|
18
|
+
expect(r.valid).toBe(false);
|
|
19
|
+
expect(r.unknownTokens).toContain('bogus');
|
|
20
|
+
expect(r.errors[0]).toMatch(/%bogus%/);
|
|
21
|
+
});
|
|
22
|
+
it('accepts literal-only text with no tokens', () => {
|
|
23
|
+
expect(validateTitleTemplate('My Site').valid).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it('rejects a template that is only an unknown token', () => {
|
|
26
|
+
expect(validateTitleTemplate('%nope%').valid).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('applySiteTitleTemplate', () => {
|
|
30
|
+
it('renders the standard page/site template', () => {
|
|
31
|
+
expect(applySiteTitleTemplate('%page% — %site%', { page: 'About', site: 'Acme' })).toBe('About — Acme');
|
|
32
|
+
});
|
|
33
|
+
it('falls back to the default template when blank', () => {
|
|
34
|
+
expect(applySiteTitleTemplate('', { page: 'About', site: 'Acme' })).toBe('About — Acme');
|
|
35
|
+
expect(DEFAULT_SITE_TITLE_TEMPLATE).toBe('%page% — %site%');
|
|
36
|
+
});
|
|
37
|
+
it('collapses dangling separators left by empty tokens', () => {
|
|
38
|
+
expect(applySiteTitleTemplate('%page% — %site%', { page: 'About' })).toBe('About');
|
|
39
|
+
expect(applySiteTitleTemplate('%page% — %site%', { site: 'Acme' })).toBe('Acme');
|
|
40
|
+
});
|
|
41
|
+
it('supports the %type%, %author% and %separator% tokens', () => {
|
|
42
|
+
expect(applySiteTitleTemplate('%page% %separator% %type% %separator% %site%', {
|
|
43
|
+
page: 'Hello',
|
|
44
|
+
type: 'Post',
|
|
45
|
+
site: 'Acme',
|
|
46
|
+
separator: '·',
|
|
47
|
+
})).toBe('Hello · Post · Acme');
|
|
48
|
+
});
|
|
49
|
+
it('falls back to the page title when nothing renders', () => {
|
|
50
|
+
expect(applySiteTitleTemplate('%site%', { page: 'Only Page' })).toBe('Only Page');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('mergeSiteSeoConfig', () => {
|
|
54
|
+
it('overrides scalar defaults and deep-merges verification', () => {
|
|
55
|
+
const base = {
|
|
56
|
+
siteName: 'Base',
|
|
57
|
+
titleTemplate: '%page%',
|
|
58
|
+
verification: { googleSearchConsole: 'g-base', bingWebmasterTools: 'b-base' },
|
|
59
|
+
};
|
|
60
|
+
const merged = mergeSiteSeoConfig(base, {
|
|
61
|
+
titleTemplate: '%page% — %site%',
|
|
62
|
+
verification: { bingWebmasterTools: 'b-new' },
|
|
63
|
+
});
|
|
64
|
+
expect(merged.siteName).toBe('Base');
|
|
65
|
+
expect(merged.titleTemplate).toBe('%page% — %site%');
|
|
66
|
+
// google preserved from base, bing overridden
|
|
67
|
+
expect(merged.verification?.googleSearchConsole).toBe('g-base');
|
|
68
|
+
expect(merged.verification?.bingWebmasterTools).toBe('b-new');
|
|
69
|
+
});
|
|
70
|
+
it('drops empty-string overrides so they fall back to the base', () => {
|
|
71
|
+
const merged = mergeSiteSeoConfig({ defaultMetaDescription: 'Base desc' }, { defaultMetaDescription: '' });
|
|
72
|
+
expect(merged.defaultMetaDescription).toBe('Base desc');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('verification meta tags', () => {
|
|
76
|
+
const tokens = {
|
|
77
|
+
googleSearchConsole: 'goog-token',
|
|
78
|
+
bingWebmasterTools: 'bing-token',
|
|
79
|
+
yandex: 'yndx-token',
|
|
80
|
+
pinterest: 'pin-token',
|
|
81
|
+
facebookDomain: 'fb-token',
|
|
82
|
+
};
|
|
83
|
+
it('builds the standard provider meta entries', () => {
|
|
84
|
+
const entries = buildVerificationMetaEntries(tokens);
|
|
85
|
+
const byName = Object.fromEntries(entries.map((e) => [e.name, e.content]));
|
|
86
|
+
expect(byName['google-site-verification']).toBe('goog-token');
|
|
87
|
+
expect(byName['msvalidate.01']).toBe('bing-token');
|
|
88
|
+
expect(byName['yandex-verification']).toBe('yndx-token');
|
|
89
|
+
expect(byName['p:domain_verify']).toBe('pin-token');
|
|
90
|
+
expect(byName['facebook-domain-verification']).toBe('fb-token');
|
|
91
|
+
});
|
|
92
|
+
it('skips empty/whitespace tokens', () => {
|
|
93
|
+
expect(buildVerificationMetaEntries({ googleSearchConsole: ' ' })).toEqual([]);
|
|
94
|
+
expect(buildVerificationMetaEntries(null)).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
it('renders only safe escaped meta tags (no script injection)', () => {
|
|
97
|
+
const html = renderVerificationMetaHtml({
|
|
98
|
+
googleSearchConsole: '"><script>alert(1)</script>',
|
|
99
|
+
});
|
|
100
|
+
expect(html).not.toContain('<script>');
|
|
101
|
+
expect(html).toContain('<script>');
|
|
102
|
+
expect(html.startsWith('<meta name="google-site-verification"')).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
it('renders custom tags but requires content + name/property', () => {
|
|
105
|
+
const entries = buildVerificationMetaEntries({
|
|
106
|
+
customMetaTags: [
|
|
107
|
+
{ id: '1', name: 'custom-verify', content: 'abc' },
|
|
108
|
+
{ id: '2', property: 'og:custom', content: 'xyz' },
|
|
109
|
+
{ id: '3', content: 'no-name' }, // dropped
|
|
110
|
+
{ id: '4', name: 'empty' }, // dropped (no content)
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
expect(entries).toHaveLength(2);
|
|
114
|
+
expect(entries[0]).toEqual({ name: 'custom-verify', content: 'abc' });
|
|
115
|
+
expect(entries[1]).toEqual({ property: 'og:custom', content: 'xyz' });
|
|
116
|
+
});
|
|
117
|
+
it('maps google/yandex to first-class Next keys and the rest under other', () => {
|
|
118
|
+
const v = buildNextVerification(tokens);
|
|
119
|
+
expect(v?.google).toBe('goog-token');
|
|
120
|
+
expect(v?.yandex).toBe('yndx-token');
|
|
121
|
+
expect(v?.other?.['msvalidate.01']).toBe('bing-token');
|
|
122
|
+
expect(v?.other?.['p:domain_verify']).toBe('pin-token');
|
|
123
|
+
expect(buildNextVerification(null)).toBeUndefined();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe('composePageMeta — site defaults', () => {
|
|
127
|
+
const baseConfig = {
|
|
128
|
+
seo: {
|
|
129
|
+
siteName: 'Acme',
|
|
130
|
+
siteUrl: 'https://acme.test',
|
|
131
|
+
titleTemplate: '%page% — %site%',
|
|
132
|
+
defaultMetaDescription: 'The Acme default description.',
|
|
133
|
+
verification: { googleSearchConsole: 'goog-token' },
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
it('applies the title template when no explicit SEO title is set', () => {
|
|
137
|
+
const meta = composePageMeta({
|
|
138
|
+
doc: { id: '1', collection: 'pages', slug: 'about', data: { title: 'About Us' } },
|
|
139
|
+
collection: {
|
|
140
|
+
slug: 'pages',
|
|
141
|
+
labels: { singular: 'Page', plural: 'Pages' },
|
|
142
|
+
fields: [],
|
|
143
|
+
},
|
|
144
|
+
config: baseConfig,
|
|
145
|
+
});
|
|
146
|
+
expect(meta.title).toBe('About Us — Acme');
|
|
147
|
+
});
|
|
148
|
+
it('uses the explicit metaTitle over the template', () => {
|
|
149
|
+
const meta = composePageMeta({
|
|
150
|
+
doc: {
|
|
151
|
+
id: '1',
|
|
152
|
+
collection: 'pages',
|
|
153
|
+
slug: 'about',
|
|
154
|
+
data: { title: 'About Us', metaTitle: 'Custom Title' },
|
|
155
|
+
},
|
|
156
|
+
config: baseConfig,
|
|
157
|
+
});
|
|
158
|
+
expect(meta.title).toBe('Custom Title');
|
|
159
|
+
});
|
|
160
|
+
it('falls back to the default meta description', () => {
|
|
161
|
+
const meta = composePageMeta({
|
|
162
|
+
doc: { id: '1', collection: 'pages', slug: 'about', data: { title: 'About Us' } },
|
|
163
|
+
config: baseConfig,
|
|
164
|
+
});
|
|
165
|
+
expect(meta.description).toBe('The Acme default description.');
|
|
166
|
+
});
|
|
167
|
+
it('prefers a per-document description over the default', () => {
|
|
168
|
+
const meta = composePageMeta({
|
|
169
|
+
doc: {
|
|
170
|
+
id: '1',
|
|
171
|
+
collection: 'pages',
|
|
172
|
+
slug: 'about',
|
|
173
|
+
data: { title: 'About Us', metaDescription: 'Page-specific.' },
|
|
174
|
+
},
|
|
175
|
+
config: baseConfig,
|
|
176
|
+
});
|
|
177
|
+
expect(meta.description).toBe('Page-specific.');
|
|
178
|
+
});
|
|
179
|
+
it('injects verification meta into the rendered output and Next metadata', () => {
|
|
180
|
+
const meta = composePageMeta({
|
|
181
|
+
doc: { id: '1', collection: 'pages', slug: 'about', data: { title: 'About Us' } },
|
|
182
|
+
config: baseConfig,
|
|
183
|
+
});
|
|
184
|
+
expect(meta.meta['google-site-verification']).toBe('goog-token');
|
|
185
|
+
expect(meta.metaHtml).toContain('name="google-site-verification"');
|
|
186
|
+
expect(meta.metadata.verification?.google).toBe('goog-token');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=settings-defaults.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-defaults.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/settings-defaults.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap-notify.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/seo/sitemap-notify.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { buildSearchEnginePings, buildSitemapUrl, notifySitemapOnPublish, } from '../../seo/sitemap-notify.js';
|
|
3
|
+
import { DEFAULT_SEO_MODULE_SETTINGS } from '../../seo/config-store.js';
|
|
4
|
+
const baseSettings = {
|
|
5
|
+
sitemapEnabled: DEFAULT_SEO_MODULE_SETTINGS.sitemapEnabled,
|
|
6
|
+
autoRegenerateSitemapOnPublish: DEFAULT_SEO_MODULE_SETTINGS.autoRegenerateSitemapOnPublish,
|
|
7
|
+
pingSearchEnginesOnPublish: DEFAULT_SEO_MODULE_SETTINGS.pingSearchEnginesOnPublish,
|
|
8
|
+
};
|
|
9
|
+
function okFetch() {
|
|
10
|
+
return vi.fn(async () => new Response('', { status: 200 }));
|
|
11
|
+
}
|
|
12
|
+
describe('buildSitemapUrl', () => {
|
|
13
|
+
it('derives /sitemap.xml from the site origin', () => {
|
|
14
|
+
expect(buildSitemapUrl('https://example.com')).toBe('https://example.com/sitemap.xml');
|
|
15
|
+
expect(buildSitemapUrl('https://example.com/blog/')).toBe('https://example.com/sitemap.xml');
|
|
16
|
+
});
|
|
17
|
+
it('returns null for empty or non-http(s) URLs', () => {
|
|
18
|
+
expect(buildSitemapUrl('')).toBeNull();
|
|
19
|
+
expect(buildSitemapUrl(null)).toBeNull();
|
|
20
|
+
expect(buildSitemapUrl('not a url')).toBeNull();
|
|
21
|
+
expect(buildSitemapUrl('ftp://example.com')).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('buildSearchEnginePings', () => {
|
|
25
|
+
it('encodes the sitemap URL into google + bing targets', () => {
|
|
26
|
+
const pings = buildSearchEnginePings('https://example.com/sitemap.xml');
|
|
27
|
+
expect(pings.map((p) => p.name)).toEqual(['google', 'bing']);
|
|
28
|
+
for (const p of pings) {
|
|
29
|
+
expect(p.url).toContain(encodeURIComponent('https://example.com/sitemap.xml'));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('notifySitemapOnPublish', () => {
|
|
34
|
+
it('does nothing when the sitemap is disabled', async () => {
|
|
35
|
+
const fetchImpl = okFetch();
|
|
36
|
+
const res = await notifySitemapOnPublish({
|
|
37
|
+
settings: { ...baseSettings, sitemapEnabled: false },
|
|
38
|
+
siteUrl: 'https://example.com',
|
|
39
|
+
fetchImpl,
|
|
40
|
+
allowNonProduction: true,
|
|
41
|
+
});
|
|
42
|
+
expect(res.invalidateCache).toBe(false);
|
|
43
|
+
expect(res.regenerated).toBe(false);
|
|
44
|
+
expect(res.pinged).toEqual([]);
|
|
45
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
46
|
+
expect(res.skipped).toContainEqual({ target: 'sitemap', reason: 'sitemap-disabled' });
|
|
47
|
+
});
|
|
48
|
+
it('does not invalidate or write when auto-regenerate is off', async () => {
|
|
49
|
+
const fetchImpl = okFetch();
|
|
50
|
+
const res = await notifySitemapOnPublish({
|
|
51
|
+
settings: { ...baseSettings, autoRegenerateSitemapOnPublish: false },
|
|
52
|
+
siteUrl: 'https://example.com',
|
|
53
|
+
fetchImpl,
|
|
54
|
+
allowNonProduction: true,
|
|
55
|
+
});
|
|
56
|
+
expect(res.invalidateCache).toBe(false);
|
|
57
|
+
expect(res.regenerated).toBe(false);
|
|
58
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
59
|
+
expect(res.skipped).toContainEqual({ target: 'sitemap', reason: 'auto-regenerate-disabled' });
|
|
60
|
+
});
|
|
61
|
+
it('regenerates but does not ping when auto-regenerate on, ping off', async () => {
|
|
62
|
+
const fetchImpl = okFetch();
|
|
63
|
+
const res = await notifySitemapOnPublish({
|
|
64
|
+
settings: { ...baseSettings, pingSearchEnginesOnPublish: false },
|
|
65
|
+
siteUrl: 'https://example.com',
|
|
66
|
+
fetchImpl,
|
|
67
|
+
allowNonProduction: true,
|
|
68
|
+
});
|
|
69
|
+
expect(res.invalidateCache).toBe(true);
|
|
70
|
+
expect(res.regenerated).toBe(true);
|
|
71
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
72
|
+
expect(res.skipped).toContainEqual({ target: 'ping', reason: 'ping-disabled' });
|
|
73
|
+
});
|
|
74
|
+
it('debounces the write + ping but still invalidates cache within the window', async () => {
|
|
75
|
+
const fetchImpl = okFetch();
|
|
76
|
+
const res = await notifySitemapOnPublish({
|
|
77
|
+
settings: baseSettings,
|
|
78
|
+
siteUrl: 'https://example.com',
|
|
79
|
+
environment: 'production',
|
|
80
|
+
lastGeneratedAt: new Date(Date.now() - 5_000).toISOString(),
|
|
81
|
+
debounceMs: 60_000,
|
|
82
|
+
fetchImpl,
|
|
83
|
+
});
|
|
84
|
+
// Cache still drops (cheap, correctness), but no write + no ping.
|
|
85
|
+
expect(res.invalidateCache).toBe(true);
|
|
86
|
+
expect(res.regenerated).toBe(false);
|
|
87
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
88
|
+
expect(res.skipped).toContainEqual({ target: 'sitemap', reason: 'debounced' });
|
|
89
|
+
});
|
|
90
|
+
it('regenerates once the debounce window has elapsed', async () => {
|
|
91
|
+
const fetchImpl = okFetch();
|
|
92
|
+
const res = await notifySitemapOnPublish({
|
|
93
|
+
settings: baseSettings,
|
|
94
|
+
siteUrl: 'https://example.com',
|
|
95
|
+
environment: 'production',
|
|
96
|
+
lastGeneratedAt: new Date(Date.now() - 120_000).toISOString(),
|
|
97
|
+
debounceMs: 60_000,
|
|
98
|
+
fetchImpl,
|
|
99
|
+
});
|
|
100
|
+
expect(res.invalidateCache).toBe(true);
|
|
101
|
+
expect(res.regenerated).toBe(true);
|
|
102
|
+
expect(res.pinged.sort()).toEqual(['bing', 'google']);
|
|
103
|
+
});
|
|
104
|
+
it('skips pinging outside production unless explicitly allowed', async () => {
|
|
105
|
+
const fetchImpl = okFetch();
|
|
106
|
+
const res = await notifySitemapOnPublish({
|
|
107
|
+
settings: baseSettings,
|
|
108
|
+
siteUrl: 'https://example.com',
|
|
109
|
+
environment: 'preview',
|
|
110
|
+
fetchImpl,
|
|
111
|
+
});
|
|
112
|
+
expect(res.regenerated).toBe(true);
|
|
113
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
114
|
+
expect(res.skipped).toContainEqual({ target: 'ping', reason: 'non-production:preview' });
|
|
115
|
+
});
|
|
116
|
+
it('pings google + bing in production with a valid https site URL', async () => {
|
|
117
|
+
const fetchImpl = okFetch();
|
|
118
|
+
const res = await notifySitemapOnPublish({
|
|
119
|
+
settings: baseSettings,
|
|
120
|
+
siteUrl: 'https://example.com',
|
|
121
|
+
environment: 'production',
|
|
122
|
+
fetchImpl,
|
|
123
|
+
});
|
|
124
|
+
expect(res.regenerated).toBe(true);
|
|
125
|
+
expect(res.sitemapUrl).toBe('https://example.com/sitemap.xml');
|
|
126
|
+
expect(res.pinged.sort()).toEqual(['bing', 'google']);
|
|
127
|
+
expect(fetchImpl).toHaveBeenCalledTimes(2);
|
|
128
|
+
});
|
|
129
|
+
it('refuses to ping when the site URL is missing', async () => {
|
|
130
|
+
const fetchImpl = okFetch();
|
|
131
|
+
const res = await notifySitemapOnPublish({
|
|
132
|
+
settings: baseSettings,
|
|
133
|
+
siteUrl: null,
|
|
134
|
+
environment: 'production',
|
|
135
|
+
fetchImpl,
|
|
136
|
+
});
|
|
137
|
+
expect(res.regenerated).toBe(true);
|
|
138
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
139
|
+
expect(res.skipped).toContainEqual({ target: 'ping', reason: 'missing-or-invalid-site-url' });
|
|
140
|
+
});
|
|
141
|
+
it('refuses to ping when the production site URL is http (not https)', async () => {
|
|
142
|
+
const fetchImpl = okFetch();
|
|
143
|
+
const res = await notifySitemapOnPublish({
|
|
144
|
+
settings: baseSettings,
|
|
145
|
+
siteUrl: 'http://example.com',
|
|
146
|
+
environment: 'production',
|
|
147
|
+
fetchImpl,
|
|
148
|
+
});
|
|
149
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
150
|
+
expect(res.skipped).toContainEqual({ target: 'ping', reason: 'non-https-site-url' });
|
|
151
|
+
});
|
|
152
|
+
it('refuses to ping when the site URL resolves to a private/internal host', async () => {
|
|
153
|
+
const fetchImpl = okFetch();
|
|
154
|
+
const res = await notifySitemapOnPublish({
|
|
155
|
+
settings: baseSettings,
|
|
156
|
+
siteUrl: 'http://127.0.0.1',
|
|
157
|
+
environment: 'production',
|
|
158
|
+
fetchImpl,
|
|
159
|
+
allowNonProduction: true,
|
|
160
|
+
});
|
|
161
|
+
expect(fetchImpl).not.toHaveBeenCalled();
|
|
162
|
+
expect(res.skipped.some((s) => s.target === 'ping' && s.reason.startsWith('unsafe-site-url'))).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
it('records non-2xx ping responses as skipped, not pinged', async () => {
|
|
165
|
+
const fetchImpl = vi.fn(async (url) => url.includes('google')
|
|
166
|
+
? new Response('', { status: 404 })
|
|
167
|
+
: new Response('', { status: 200 }));
|
|
168
|
+
const res = await notifySitemapOnPublish({
|
|
169
|
+
settings: baseSettings,
|
|
170
|
+
siteUrl: 'https://example.com',
|
|
171
|
+
environment: 'production',
|
|
172
|
+
fetchImpl,
|
|
173
|
+
});
|
|
174
|
+
expect(res.pinged).toEqual(['bing']);
|
|
175
|
+
expect(res.skipped).toContainEqual({ target: 'google', reason: 'http-404' });
|
|
176
|
+
});
|
|
177
|
+
it('never throws when fetch rejects', async () => {
|
|
178
|
+
const fetchImpl = vi.fn(async () => {
|
|
179
|
+
throw new Error('network down');
|
|
180
|
+
});
|
|
181
|
+
const res = await notifySitemapOnPublish({
|
|
182
|
+
settings: baseSettings,
|
|
183
|
+
siteUrl: 'https://example.com',
|
|
184
|
+
environment: 'production',
|
|
185
|
+
fetchImpl,
|
|
186
|
+
});
|
|
187
|
+
expect(res.pinged).toEqual([]);
|
|
188
|
+
expect(res.skipped.some((s) => s.reason.startsWith('fetch-error'))).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=sitemap-notify.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap-notify.test.js","sourceRoot":"","sources":["../../../src/__tests__/seo/sitemap-notify.test.ts"],"names":[],"mappings":"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"}
|
package/dist/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAMA,OAAO,EAAqB,KAAK,cAAc,EAAwB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
|
package/dist/actions.js
CHANGED
|
@@ -5,6 +5,8 @@ import { stripInternalDataKeys } from './security/internal-keys.js';
|
|
|
5
5
|
import { getActuateConfig } from './config/runtime.js';
|
|
6
6
|
import { validateRelations } from './fields/relations.js';
|
|
7
7
|
import { invalidationTagsForDocumentWrite, invalidationTagsForGlobalWrite } from './cache/http.js';
|
|
8
|
+
import { notifySitemapOnPublish } from './seo/sitemap-notify.js';
|
|
9
|
+
import { getSeoOverrides, putSeoOverrides, resolveSeoModuleSettings, } from './seo/config-store.js';
|
|
8
10
|
function prisma(ctx) {
|
|
9
11
|
return ctx.db;
|
|
10
12
|
}
|
|
@@ -88,9 +90,60 @@ async function flushEffects(effects, ctx) {
|
|
|
88
90
|
else if (effect.kind === 'plugin-hook') {
|
|
89
91
|
await firePluginHooks(effect.event, effect.doc, ctx);
|
|
90
92
|
}
|
|
91
|
-
else {
|
|
93
|
+
else if (effect.kind === 'cache-invalidate') {
|
|
92
94
|
await fireCacheInvalidate(effect.tags);
|
|
93
95
|
}
|
|
96
|
+
else {
|
|
97
|
+
await fireSitemapNotify(ctx);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Sitemap cache tag — invalidated on any public-content change. */
|
|
102
|
+
const SITEMAP_CACHE_TAG = 'sitemap';
|
|
103
|
+
/**
|
|
104
|
+
* Best-effort sitemap regeneration + (production-gated) search-engine ping
|
|
105
|
+
* fired after public content changes. Reads the shared SEO module settings so
|
|
106
|
+
* the toggles in Settings > SEO / SEO Technical govern behaviour. Never throws
|
|
107
|
+
* — the content write has already committed.
|
|
108
|
+
*/
|
|
109
|
+
async function fireSitemapNotify(ctx) {
|
|
110
|
+
try {
|
|
111
|
+
const overrides = await getSeoOverrides(ctx.db);
|
|
112
|
+
const settings = resolveSeoModuleSettings(overrides);
|
|
113
|
+
if (!settings.sitemapEnabled || !settings.autoRegenerateSitemapOnPublish)
|
|
114
|
+
return;
|
|
115
|
+
const cfg = getActuateConfig();
|
|
116
|
+
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ??
|
|
117
|
+
cfg?.seo?.siteUrl ??
|
|
118
|
+
null;
|
|
119
|
+
const result = await notifySitemapOnPublish({
|
|
120
|
+
settings,
|
|
121
|
+
siteUrl,
|
|
122
|
+
lastGeneratedAt: settings.sitemapLastGeneratedAt,
|
|
123
|
+
});
|
|
124
|
+
// Cheap + un-debounced: refresh the sitemap cache on every change so the
|
|
125
|
+
// next request rebuilds with the latest public content.
|
|
126
|
+
if (result.invalidateCache) {
|
|
127
|
+
await fireCacheInvalidate([SITEMAP_CACHE_TAG]);
|
|
128
|
+
}
|
|
129
|
+
// Expensive + debounced: only persist the regeneration timestamp once per
|
|
130
|
+
// window so bursts of publishes don't hammer the single `__seo_config__`
|
|
131
|
+
// row. The Settings/Technical UI reads this for "last generated".
|
|
132
|
+
if (result.regenerated) {
|
|
133
|
+
const next = {
|
|
134
|
+
...(overrides ?? {}),
|
|
135
|
+
module: {
|
|
136
|
+
...(overrides?.module ?? {}),
|
|
137
|
+
sitemapLastGeneratedAt: new Date().toISOString(),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
await putSeoOverrides(ctx.db, next, ctx.userId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
145
|
+
console.error('[actuate] sitemap notify failed — sitemap may be stale until next write:', err instanceof Error ? err.message : err);
|
|
146
|
+
}
|
|
94
147
|
}
|
|
95
148
|
}
|
|
96
149
|
function getCollectionFields(collection) {
|
|
@@ -343,6 +396,20 @@ export async function updateDocument(collection, id, data, ctx) {
|
|
|
343
396
|
kind: 'cache-invalidate',
|
|
344
397
|
tags: invalidationTagsForDocumentWrite(collection, id),
|
|
345
398
|
});
|
|
399
|
+
// Sitemap upkeep: a change is sitemap-relevant when the document enters,
|
|
400
|
+
// stays in, or leaves the PUBLISHED state. Pure DRAFT→DRAFT edits never
|
|
401
|
+
// touch the public sitemap, so don't enqueue (avoids needless pings).
|
|
402
|
+
const wasPublished = existing.status === 'PUBLISHED';
|
|
403
|
+
const isPublished = (status ?? existing.status) === 'PUBLISHED';
|
|
404
|
+
if (isPublishingNow) {
|
|
405
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'publish' });
|
|
406
|
+
}
|
|
407
|
+
else if (wasPublished && !isPublished) {
|
|
408
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'unpublish' });
|
|
409
|
+
}
|
|
410
|
+
else if (wasPublished && isPublished) {
|
|
411
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'update' });
|
|
412
|
+
}
|
|
346
413
|
return result;
|
|
347
414
|
});
|
|
348
415
|
await flushEffects(pendingEffects, ctx);
|
|
@@ -397,6 +464,11 @@ export async function updateDocumentSeoFields(collection, id, seoFields, ctx) {
|
|
|
397
464
|
kind: 'cache-invalidate',
|
|
398
465
|
tags: invalidationTagsForDocumentWrite(collection, id),
|
|
399
466
|
});
|
|
467
|
+
// SEO field edits (e.g. toggling `noindex`, changing canonical) change
|
|
468
|
+
// sitemap inclusion for already-public docs, so refresh the sitemap.
|
|
469
|
+
if (existing.status === 'PUBLISHED') {
|
|
470
|
+
pendingEffects.push({ kind: 'sitemap-notify', reason: 'update' });
|
|
471
|
+
}
|
|
400
472
|
return result;
|
|
401
473
|
});
|
|
402
474
|
await flushEffects(pendingEffects, ctx);
|
|
@@ -426,7 +498,7 @@ export async function deleteDocument(collection, id, ctx) {
|
|
|
426
498
|
data: { deletedAt: new Date() },
|
|
427
499
|
});
|
|
428
500
|
});
|
|
429
|
-
|
|
501
|
+
const deleteEffects = [
|
|
430
502
|
{
|
|
431
503
|
kind: 'webhook',
|
|
432
504
|
event: 'document.deleted',
|
|
@@ -436,7 +508,12 @@ export async function deleteDocument(collection, id, ctx) {
|
|
|
436
508
|
kind: 'cache-invalidate',
|
|
437
509
|
tags: invalidationTagsForDocumentWrite(collection, id),
|
|
438
510
|
},
|
|
439
|
-
]
|
|
511
|
+
];
|
|
512
|
+
// Removing public content changes the sitemap; drafts were never in it.
|
|
513
|
+
if (existing.status === 'PUBLISHED') {
|
|
514
|
+
deleteEffects.push({ kind: 'sitemap-notify', reason: 'delete' });
|
|
515
|
+
}
|
|
516
|
+
await flushEffects(deleteEffects, ctx);
|
|
440
517
|
}
|
|
441
518
|
function stripInternalKeys(data) {
|
|
442
519
|
return stripInternalDataKeys(data);
|