@cntrl-site/sdk 1.26.4 → 1.27.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/lib/Client/Client.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class Client {
|
|
|
11
11
|
private static getPageMeta;
|
|
12
12
|
getPageData(pageSlug: string, buildMode?: 'default' | 'self-hosted'): Promise<CntrlPageData>;
|
|
13
13
|
getProjectPagesPaths(): Promise<string[]>;
|
|
14
|
+
getProject(buildMode?: 'default' | 'self-hosted'): Promise<Project>;
|
|
14
15
|
getLayouts(): Promise<Layout[]>;
|
|
15
16
|
fetchCustomComponents(buildMode?: 'default' | 'self-hosted'): Promise<CustomComponentMeta[]>;
|
|
16
17
|
fetchCustomComponentBundle(componentId: string, buildMode?: 'default' | 'self-hosted'): Promise<string>;
|
package/lib/Client/Client.js
CHANGED
|
@@ -70,6 +70,11 @@ class Client {
|
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
+
getProject() {
|
|
74
|
+
return __awaiter(this, arguments, void 0, function* (buildMode = 'default') {
|
|
75
|
+
return this.fetchProject(buildMode);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
73
78
|
getLayouts() {
|
|
74
79
|
return __awaiter(this, void 0, void 0, function* () {
|
|
75
80
|
try {
|
package/lib/cli.js
CHANGED
|
@@ -46,6 +46,130 @@ commander_1.program
|
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
}));
|
|
49
|
+
commander_1.program
|
|
50
|
+
.command('generate-sitemap')
|
|
51
|
+
.description('Generate sitemap.xml and robots.txt for the published site')
|
|
52
|
+
.option('-o, --output <outputDir>', 'Output directory', 'public')
|
|
53
|
+
.option('-e, --env <envFilename>', 'Name of the .env file', '.env.local')
|
|
54
|
+
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
try {
|
|
56
|
+
(0, dotenv_1.config)({ path: options.env });
|
|
57
|
+
const apiUrl = process.env.CNTRL_API_URL;
|
|
58
|
+
if (!apiUrl) {
|
|
59
|
+
console.warn('[sitemap] CNTRL_API_URL is not set — skipping sitemap/robots generation.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const client = new Client_1.Client(apiUrl);
|
|
63
|
+
const project = yield client.getProject();
|
|
64
|
+
const siteUrl = resolveSiteUrl(project.primaryDomain, process.env.SITE_URL);
|
|
65
|
+
if (!siteUrl) {
|
|
66
|
+
console.warn('[sitemap] Could not resolve a canonical site URL — skipping sitemap/robots generation.\n' +
|
|
67
|
+
' The project has no primary domain in the API response and SITE_URL is not set.\n' +
|
|
68
|
+
' Either publish the site (so a primary domain exists) or set SITE_URL.');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const indexable = project.pages.filter(isIndexablePage);
|
|
72
|
+
const lastmod = new Date().toISOString();
|
|
73
|
+
const outputDir = path_1.default.resolve(process.cwd(), options.output);
|
|
74
|
+
if (!fs_1.default.existsSync(outputDir)) {
|
|
75
|
+
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
const sitemapPath = path_1.default.resolve(outputDir, 'sitemap.xml');
|
|
78
|
+
const robotsPath = path_1.default.resolve(outputDir, 'robots.txt');
|
|
79
|
+
fs_1.default.writeFileSync(sitemapPath, renderSitemap(indexable, siteUrl, lastmod));
|
|
80
|
+
fs_1.default.writeFileSync(robotsPath, renderRobots(siteUrl));
|
|
81
|
+
console.log(`Generated sitemap.xml at ${sitemapPath} (${indexable.length} of ${project.pages.length} pages)`);
|
|
82
|
+
console.log(`Generated robots.txt at ${robotsPath}`);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.warn(`[sitemap] Failed to generate sitemap/robots: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
|
|
86
|
+
console.warn('[sitemap] Continuing without updated sitemap.');
|
|
87
|
+
}
|
|
88
|
+
}));
|
|
89
|
+
function resolveSiteUrl(primaryDomain, override) {
|
|
90
|
+
const host = override || primaryDomain;
|
|
91
|
+
if (!host)
|
|
92
|
+
return null;
|
|
93
|
+
return parseAsUrl(host);
|
|
94
|
+
}
|
|
95
|
+
function isIndexablePage(page) {
|
|
96
|
+
if (typeof page.slug !== 'string')
|
|
97
|
+
return false;
|
|
98
|
+
if (page.isPublished === false)
|
|
99
|
+
return false;
|
|
100
|
+
if (page.isAuthProtected === true)
|
|
101
|
+
return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function renderSitemap(pages, siteUrl, lastmod) {
|
|
105
|
+
const entries = pages.map(page => {
|
|
106
|
+
const loc = escapeXml(buildPageUrl(siteUrl, page.slug));
|
|
107
|
+
const priority = page.slug === '' ? '1.00' : '0.80';
|
|
108
|
+
return [
|
|
109
|
+
' <url>',
|
|
110
|
+
` <loc>${loc}</loc>`,
|
|
111
|
+
` <lastmod>${lastmod}</lastmod>`,
|
|
112
|
+
` <priority>${priority}</priority>`,
|
|
113
|
+
' </url>'
|
|
114
|
+
].join('\n');
|
|
115
|
+
});
|
|
116
|
+
return [
|
|
117
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
118
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
|
119
|
+
...entries,
|
|
120
|
+
'</urlset>',
|
|
121
|
+
''
|
|
122
|
+
].join('\n');
|
|
123
|
+
}
|
|
124
|
+
function renderRobots(siteUrl) {
|
|
125
|
+
const sitemapUrl = new URL('/sitemap.xml', siteUrl.origin).toString();
|
|
126
|
+
return [
|
|
127
|
+
'User-agent: *',
|
|
128
|
+
'Allow: /',
|
|
129
|
+
'',
|
|
130
|
+
`Sitemap: ${sitemapUrl}`,
|
|
131
|
+
''
|
|
132
|
+
].join('\n');
|
|
133
|
+
}
|
|
134
|
+
function buildPageUrl(siteUrl, slug) {
|
|
135
|
+
const base = new URL(siteUrl.href);
|
|
136
|
+
if (!base.pathname.endsWith('/'))
|
|
137
|
+
base.pathname += '/';
|
|
138
|
+
const relative = stripSlashes(slug);
|
|
139
|
+
const target = relative ? new URL(`${relative}/`, base) : base;
|
|
140
|
+
target.search = '';
|
|
141
|
+
target.hash = '';
|
|
142
|
+
return target.toString();
|
|
143
|
+
}
|
|
144
|
+
function parseAsUrl(input) {
|
|
145
|
+
var _a;
|
|
146
|
+
return (_a = tryParseUrl(input)) !== null && _a !== void 0 ? _a : tryParseUrl(`https://${input}`);
|
|
147
|
+
}
|
|
148
|
+
function tryParseUrl(input) {
|
|
149
|
+
try {
|
|
150
|
+
return new URL(input);
|
|
151
|
+
}
|
|
152
|
+
catch (_a) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function stripSlashes(value) {
|
|
157
|
+
let start = 0;
|
|
158
|
+
let end = value.length;
|
|
159
|
+
while (start < end && value[start] === '/')
|
|
160
|
+
start += 1;
|
|
161
|
+
while (end > start && value[end - 1] === '/')
|
|
162
|
+
end -= 1;
|
|
163
|
+
return value.slice(start, end);
|
|
164
|
+
}
|
|
165
|
+
function escapeXml(value) {
|
|
166
|
+
return value
|
|
167
|
+
.replace(/&/g, '&')
|
|
168
|
+
.replace(/</g, '<')
|
|
169
|
+
.replace(/>/g, '>')
|
|
170
|
+
.replace(/"/g, '"')
|
|
171
|
+
.replace(/'/g, ''');
|
|
172
|
+
}
|
|
49
173
|
function convertLayouts(layouts, maxLayoutWidth = Number.MAX_SAFE_INTEGER) {
|
|
50
174
|
const sorted = layouts.slice().sort((la, lb) => la.startsWith - lb.startsWith);
|
|
51
175
|
const mapped = sorted.map((layout, i, ls) => {
|
|
@@ -74,6 +74,8 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
74
74
|
keywords?: string | undefined;
|
|
75
75
|
}>>;
|
|
76
76
|
id: z.ZodString;
|
|
77
|
+
isPublished: z.ZodOptional<z.ZodBoolean>;
|
|
78
|
+
isAuthProtected: z.ZodOptional<z.ZodBoolean>;
|
|
77
79
|
}, "strip", z.ZodTypeAny, {
|
|
78
80
|
id: string;
|
|
79
81
|
title: string;
|
|
@@ -86,6 +88,8 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
86
88
|
opengraphThumbnail?: string | undefined;
|
|
87
89
|
keywords?: string | undefined;
|
|
88
90
|
} | undefined;
|
|
91
|
+
isPublished?: boolean | undefined;
|
|
92
|
+
isAuthProtected?: boolean | undefined;
|
|
89
93
|
}, {
|
|
90
94
|
id: string;
|
|
91
95
|
title: string;
|
|
@@ -98,6 +102,8 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
98
102
|
opengraphThumbnail?: string | undefined;
|
|
99
103
|
keywords?: string | undefined;
|
|
100
104
|
} | undefined;
|
|
105
|
+
isPublished?: boolean | undefined;
|
|
106
|
+
isAuthProtected?: boolean | undefined;
|
|
101
107
|
}>, "many">;
|
|
102
108
|
fonts: z.ZodObject<{
|
|
103
109
|
google: z.ZodString;
|
|
@@ -158,6 +164,7 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
158
164
|
google: string;
|
|
159
165
|
adobe: string;
|
|
160
166
|
}>;
|
|
167
|
+
primaryDomain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
161
168
|
}, "strip", z.ZodTypeAny, {
|
|
162
169
|
html: {
|
|
163
170
|
head: string;
|
|
@@ -190,6 +197,8 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
190
197
|
opengraphThumbnail?: string | undefined;
|
|
191
198
|
keywords?: string | undefined;
|
|
192
199
|
} | undefined;
|
|
200
|
+
isPublished?: boolean | undefined;
|
|
201
|
+
isAuthProtected?: boolean | undefined;
|
|
193
202
|
}[];
|
|
194
203
|
fonts: {
|
|
195
204
|
custom: {
|
|
@@ -204,6 +213,7 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
204
213
|
google: string;
|
|
205
214
|
adobe: string;
|
|
206
215
|
};
|
|
216
|
+
primaryDomain?: string | null | undefined;
|
|
207
217
|
}, {
|
|
208
218
|
html: {
|
|
209
219
|
head: string;
|
|
@@ -236,6 +246,8 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
236
246
|
opengraphThumbnail?: string | undefined;
|
|
237
247
|
keywords?: string | undefined;
|
|
238
248
|
} | undefined;
|
|
249
|
+
isPublished?: boolean | undefined;
|
|
250
|
+
isAuthProtected?: boolean | undefined;
|
|
239
251
|
}[];
|
|
240
252
|
fonts: {
|
|
241
253
|
custom: {
|
|
@@ -250,4 +262,5 @@ export declare const ProjectSchema: z.ZodObject<{
|
|
|
250
262
|
google: string;
|
|
251
263
|
adobe: string;
|
|
252
264
|
};
|
|
265
|
+
primaryDomain?: string | null | undefined;
|
|
253
266
|
}>;
|
|
@@ -30,7 +30,9 @@ exports.ProjectSchema = zod_1.z.object({
|
|
|
30
30
|
keywords: zod_1.z.string().optional(),
|
|
31
31
|
enabled: zod_1.z.boolean()
|
|
32
32
|
}).optional(),
|
|
33
|
-
id: zod_1.z.string().min(1)
|
|
33
|
+
id: zod_1.z.string().min(1),
|
|
34
|
+
isPublished: zod_1.z.boolean().optional(),
|
|
35
|
+
isAuthProtected: zod_1.z.boolean().optional()
|
|
34
36
|
})),
|
|
35
37
|
fonts: zod_1.z.object({
|
|
36
38
|
google: zod_1.z.string(),
|
|
@@ -44,5 +46,6 @@ exports.ProjectSchema = zod_1.z.object({
|
|
|
44
46
|
url: zod_1.z.string()
|
|
45
47
|
}))
|
|
46
48
|
}))
|
|
47
|
-
})
|
|
49
|
+
}),
|
|
50
|
+
primaryDomain: zod_1.z.string().nullable().optional()
|
|
48
51
|
});
|