@reldens/cms 0.52.0 → 0.53.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/.claude/architecture-guide.md +450 -0
- package/.claude/security-guide.md +102 -0
- package/.claude/seo-guide.md +167 -0
- package/.claude/templating-system-guide.md +29 -0
- package/CLAUDE.md +93 -550
- package/bin/reldens-cms-generate-entities.js +0 -1
- package/install/index.html +4 -0
- package/lib/admin-manager/router-contents.js +1 -0
- package/lib/frontend/content-renderer.js +1 -0
- package/lib/frontend/template-cache.js +1 -1
- package/lib/frontend/template-resolver.js +7 -2
- package/lib/frontend.js +38 -6
- package/lib/manager.js +11 -1
- package/lib/mysql-installer.js +2 -1
- package/lib/sitemap-loader.js +101 -0
- package/lib/template-engine/collections-transformer.js +43 -6
- package/lib/template-engine.js +1 -5
- package/migrations/default-blocks.sql +1 -1
- package/migrations/default-entity-access.sql +1 -1
- package/migrations/default-forms.sql +0 -1
- package/migrations/default-homepage.sql +7 -7
- package/migrations/default-sitemaps-and-robots.sql +44 -0
- package/migrations/default-user.sql +1 -1
- package/migrations/users-authentication.sql +1 -1
- package/package.json +3 -4
- package/templates/layouts/raw.html +1 -0
- package/templates/raw.html +1 -0
- package/templates/robots.txt +3 -0
- package/templates/sitemap.xml +9 -0
- package/.claude/sitemap-generator-guide.md +0 -511
- package/bin/reldens-cms-generate-sitemap.js +0 -149
- package/lib/sitemap-generator.js +0 -181
package/lib/sitemap-generator.js
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Reldens - CMS - SitemapGenerator
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { Logger, sc } = require('@reldens/utils');
|
|
8
|
-
const { FileHandler } = require('@reldens/server-utils');
|
|
9
|
-
|
|
10
|
-
class SitemapGenerator
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
constructor(props)
|
|
14
|
-
{
|
|
15
|
-
this.dataServer = sc.get(props, 'dataServer', false);
|
|
16
|
-
this.projectRoot = sc.get(props, 'projectRoot', './');
|
|
17
|
-
this.defaultDomain = sc.get(props, 'defaultDomain', '');
|
|
18
|
-
this.domainMapping = sc.get(props, 'domainMapping', {});
|
|
19
|
-
this.domainPublicUrlMapping = sc.get(props, 'domainPublicUrlMapping', {});
|
|
20
|
-
this.sitemapDir = FileHandler.joinPaths(this.projectRoot, 'public', 'sitemap');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async generate(specificDomain = null)
|
|
24
|
-
{
|
|
25
|
-
if(!this.dataServer){
|
|
26
|
-
Logger.critical('DataServer is required for sitemap generation.');
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
let routes = await this.loadEnabledRoutes();
|
|
30
|
-
if(!routes){
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
if(0 === routes.length){
|
|
34
|
-
Logger.warning('No enabled routes found for sitemap generation.');
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
let filteredRoutes = routes;
|
|
38
|
-
if(specificDomain){
|
|
39
|
-
filteredRoutes = routes.filter((route) => {
|
|
40
|
-
let routeDomain = route.domain || this.defaultDomain;
|
|
41
|
-
return routeDomain === specificDomain;
|
|
42
|
-
});
|
|
43
|
-
if(0 === filteredRoutes.length){
|
|
44
|
-
Logger.warning('No routes found for domain: '+specificDomain);
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
let domainRoutes = this.groupRoutesByDomain(filteredRoutes);
|
|
49
|
-
if(!await this.saveSitemaps(domainRoutes)){
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
if(!specificDomain){
|
|
53
|
-
if(!await this.saveSitemapIndex(domainRoutes)){
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
Logger.info('Sitemap generation completed successfully.');
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async loadEnabledRoutes()
|
|
62
|
-
{
|
|
63
|
-
let routesEntity = this.dataServer.getEntity('routes');
|
|
64
|
-
if(!routesEntity){
|
|
65
|
-
Logger.critical('Routes entity not found in dataServer.');
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
let routes = await routesEntity.load({enabled: 1});
|
|
70
|
-
Logger.debug('Loaded '+routes.length+' enabled routes.');
|
|
71
|
-
return routes;
|
|
72
|
-
} catch(error) {
|
|
73
|
-
Logger.critical('Failed to load routes: '+error.message);
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
groupRoutesByDomain(routes)
|
|
79
|
-
{
|
|
80
|
-
let domainRoutes = {};
|
|
81
|
-
for(let route of routes){
|
|
82
|
-
let domain = route.domain || this.defaultDomain || 'default';
|
|
83
|
-
if(!sc.hasOwn(domainRoutes, domain)){
|
|
84
|
-
domainRoutes[domain] = [];
|
|
85
|
-
}
|
|
86
|
-
domainRoutes[domain].push(route);
|
|
87
|
-
}
|
|
88
|
-
return domainRoutes;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
buildSitemapXml(routes, domain)
|
|
92
|
-
{
|
|
93
|
-
let urlEntries = [];
|
|
94
|
-
for(let route of routes){
|
|
95
|
-
let urlEntry = ' <url>\n';
|
|
96
|
-
urlEntry += ' <loc>'+sc.sanitize(this.buildUrl(domain, route.path))+'</loc>\n';
|
|
97
|
-
if(route.updated_at){
|
|
98
|
-
urlEntry += ' <lastmod>'+sc.formatDate(new Date(route.updated_at), 'Y-m-d')+'</lastmod>\n';
|
|
99
|
-
}
|
|
100
|
-
urlEntry += ' </url>';
|
|
101
|
-
urlEntries.push(urlEntry);
|
|
102
|
-
}
|
|
103
|
-
return this.getSitemapTemplate().replace('{{URLS}}', urlEntries.join('\n'));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
buildSitemapIndexXml(domainRoutes)
|
|
107
|
-
{
|
|
108
|
-
let sitemapEntries = [];
|
|
109
|
-
for(let domain in domainRoutes){
|
|
110
|
-
let sitemapEntry = ' <sitemap>\n';
|
|
111
|
-
sitemapEntry += ' <loc>'+sc.sanitize(this.buildUrl(domain, '/sitemap/'+domain+'/sitemap.xml'))+'</loc>\n';
|
|
112
|
-
sitemapEntry += ' </sitemap>';
|
|
113
|
-
sitemapEntries.push(sitemapEntry);
|
|
114
|
-
}
|
|
115
|
-
return this.getSitemapIndexTemplate().replace('{{SITEMAPS}}', sitemapEntries.join('\n'));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
getSitemapTemplate()
|
|
119
|
-
{
|
|
120
|
-
return '<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
121
|
-
+'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
|
122
|
-
+'{{URLS}}\n'
|
|
123
|
-
+'</urlset>\n';
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
getSitemapIndexTemplate()
|
|
127
|
-
{
|
|
128
|
-
return '<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
129
|
-
+'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
|
130
|
-
+'{{SITEMAPS}}\n'
|
|
131
|
-
+'</sitemapindex>\n';
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async saveSitemaps(domainRoutes)
|
|
135
|
-
{
|
|
136
|
-
for(let domain in domainRoutes){
|
|
137
|
-
let domainDir = FileHandler.joinPaths(this.sitemapDir, domain);
|
|
138
|
-
if(!FileHandler.createFolder(domainDir)){
|
|
139
|
-
Logger.critical('Failed to create sitemap directory: '+domainDir);
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
let sitemapPath = FileHandler.joinPaths(domainDir, 'sitemap.xml');
|
|
143
|
-
if(!FileHandler.writeFile(sitemapPath, this.buildSitemapXml(domainRoutes[domain], domain))){
|
|
144
|
-
Logger.critical('Failed to write sitemap: '+sitemapPath);
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
Logger.info('Sitemap saved: '+sitemapPath);
|
|
148
|
-
}
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async saveSitemapIndex(domainRoutes)
|
|
153
|
-
{
|
|
154
|
-
if(!FileHandler.createFolder(this.sitemapDir)){
|
|
155
|
-
Logger.critical('Failed to create sitemap directory: '+this.sitemapDir);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
let indexPath = FileHandler.joinPaths(this.projectRoot, 'public', 'sitemap.xml');
|
|
159
|
-
if(!FileHandler.writeFile(indexPath, this.buildSitemapIndexXml(domainRoutes))){
|
|
160
|
-
Logger.critical('Failed to write sitemap index: '+indexPath);
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
Logger.info('Sitemap index saved: '+indexPath);
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
buildUrl(domain, path)
|
|
168
|
-
{
|
|
169
|
-
let publicUrl = sc.get(this.domainPublicUrlMapping, domain, 'http://'+domain);
|
|
170
|
-
if(publicUrl.endsWith('/')){
|
|
171
|
-
publicUrl = publicUrl.slice(0, -1);
|
|
172
|
-
}
|
|
173
|
-
if(!path.startsWith('/')){
|
|
174
|
-
path = '/'+path;
|
|
175
|
-
}
|
|
176
|
-
return publicUrl+path;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
module.exports.SitemapGenerator = SitemapGenerator;
|