@roottale/cms-renderer-next 0.47.0 → 0.51.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/CHANGELOG.md +80 -0
- package/dist/blog-filter-BKCGM0qd.d.ts +29 -0
- package/dist/{chunk-6MFHA555.js → chunk-27RT6B3O.js} +1 -1
- package/dist/chunk-27RT6B3O.js.map +1 -0
- package/dist/chunk-2QU4JU46.js +3927 -0
- package/dist/chunk-2QU4JU46.js.map +1 -0
- package/dist/chunk-4RQ3SEDL.js +106 -0
- package/dist/chunk-4RQ3SEDL.js.map +1 -0
- package/dist/{chunk-OMXEU4LS.js → chunk-QYNEOFL7.js} +140 -136
- package/dist/chunk-QYNEOFL7.js.map +1 -0
- package/dist/{chunk-FUA5H6JE.js → chunk-U2IM6OCQ.js} +46 -2
- package/dist/chunk-U2IM6OCQ.js.map +1 -0
- package/dist/cms-public.css +137 -18
- package/dist/concerns-client.d.ts +1 -1
- package/dist/expertise-client.d.ts +1 -1
- package/dist/expertise-client.js +1 -1
- package/dist/hero-carousel-client.js +1 -1
- package/dist/routes.d.ts +377 -21
- package/dist/routes.js +273 -106
- package/dist/routes.js.map +1 -1
- package/dist/seo-asset-hosts.d.ts +36 -0
- package/dist/seo-asset-hosts.js +391 -0
- package/dist/seo-asset-hosts.js.map +1 -0
- package/dist/server.d.ts +34 -216
- package/dist/server.js +7 -7
- package/dist/{site-config-Dicv57oY.d.ts → site-config-DNpvlqA5.d.ts} +201 -201
- package/dist/spaces-client.d.ts +1 -1
- package/dist/team-expanding-stage-client.d.ts +1 -1
- package/dist/team-expanding-stage-client.js +1 -1
- package/dist/templates.d.ts +64 -25
- package/dist/templates.js +14 -7
- package/dist/templates.js.map +1 -1
- package/package.json +7 -2
- package/dist/chunk-6MFHA555.js.map +0 -1
- package/dist/chunk-FUA5H6JE.js.map +0 -1
- package/dist/chunk-FZK3EXYZ.js +0 -103
- package/dist/chunk-FZK3EXYZ.js.map +0 -1
- package/dist/chunk-OMXEU4LS.js.map +0 -1
- package/dist/chunk-ZHXYCABN.js +0 -3584
- package/dist/chunk-ZHXYCABN.js.map +0 -1
package/dist/routes.js
CHANGED
|
@@ -1,65 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
collectCollectionCategories
|
|
4
|
-
|
|
2
|
+
collectCategoriesWithCounts,
|
|
3
|
+
collectCollectionCategories,
|
|
4
|
+
resolveCollections,
|
|
5
|
+
resolveCollectionsResult,
|
|
6
|
+
resolvePostCollection,
|
|
7
|
+
resolvePostUrl,
|
|
8
|
+
safeFetchPosts,
|
|
9
|
+
trimSlash
|
|
10
|
+
} from "./chunk-U2IM6OCQ.js";
|
|
5
11
|
|
|
6
12
|
// src/routes.ts
|
|
7
13
|
import { CMS_CLIENT_VERSION } from "@roottale/cms-client/server";
|
|
8
14
|
|
|
9
|
-
// src/routes-shared.ts
|
|
10
|
-
import { fetchPosts } from "@roottale/cms-client/server";
|
|
11
|
-
import { resolvePostCollection, resolvePostUrl } from "@roottale/cms-core";
|
|
12
|
-
async function resolveCollectionsResult(input) {
|
|
13
|
-
if (typeof input === "function") {
|
|
14
|
-
try {
|
|
15
|
-
return { collections: await input(), failed: false };
|
|
16
|
-
} catch (err) {
|
|
17
|
-
console.error(
|
|
18
|
-
"[@roottale/cms-renderer-next/routes] collections resolver \uC2E4\uD328:",
|
|
19
|
-
err
|
|
20
|
-
);
|
|
21
|
-
return { collections: void 0, failed: true };
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return { collections: input, failed: false };
|
|
25
|
-
}
|
|
26
|
-
async function resolveCollections(input) {
|
|
27
|
-
return (await resolveCollectionsResult(input)).collections;
|
|
28
|
-
}
|
|
29
|
-
function trimSlash(u) {
|
|
30
|
-
return u.replace(/\/+$/, "");
|
|
31
|
-
}
|
|
32
|
-
async function safeFetchPosts(config, limit) {
|
|
33
|
-
try {
|
|
34
|
-
const page = await fetchPosts({
|
|
35
|
-
apiKey: config.apiKey,
|
|
36
|
-
baseUrl: config.apiBase,
|
|
37
|
-
type: "post",
|
|
38
|
-
limit
|
|
39
|
-
});
|
|
40
|
-
return page.items;
|
|
41
|
-
} catch (err) {
|
|
42
|
-
console.error("[@roottale/cms-renderer-next/routes] fetchPosts \uC2E4\uD328:", err);
|
|
43
|
-
return [];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
15
|
// src/routes-feed-sitemap.ts
|
|
48
16
|
import {
|
|
49
|
-
fetchAuthors,
|
|
50
|
-
fetchBlogSettings,
|
|
51
|
-
fetchPosts as fetchPosts2,
|
|
52
17
|
generateRssXml,
|
|
53
18
|
rssItemsFromPosts
|
|
54
19
|
} from "@roottale/cms-client/server";
|
|
55
20
|
import {
|
|
56
|
-
isInCollectionMode,
|
|
57
|
-
resolvePostCollection as
|
|
58
|
-
resolvePostUrl as
|
|
21
|
+
isInCollectionMode as isInCollectionMode2,
|
|
22
|
+
resolvePostCollection as resolvePostCollection3,
|
|
23
|
+
resolvePostUrl as resolvePostUrl3
|
|
59
24
|
} from "@roottale/cms-core";
|
|
60
25
|
|
|
61
26
|
// src/routes-metadata.ts
|
|
62
27
|
import { resolvePostPath } from "@roottale/cms-core";
|
|
28
|
+
function resolveRobotsMeta(flags) {
|
|
29
|
+
if (!flags.noindex && !flags.nofollow) return void 0;
|
|
30
|
+
return { index: !flags.noindex, follow: !flags.nofollow };
|
|
31
|
+
}
|
|
63
32
|
function buildPostMetadata(post, options = {}) {
|
|
64
33
|
const seo = post.seo ?? void 0;
|
|
65
34
|
const title = seo?.title || post.title;
|
|
@@ -83,6 +52,10 @@ function buildPostMetadata(post, options = {}) {
|
|
|
83
52
|
if (description) openGraph.description = description;
|
|
84
53
|
if (canonical) openGraph.url = canonical;
|
|
85
54
|
if (post.date) openGraph.publishedTime = post.date;
|
|
55
|
+
if (post.modified) openGraph.modifiedTime = post.modified;
|
|
56
|
+
if (post.section) openGraph.section = post.section;
|
|
57
|
+
if (post.tags && post.tags.length > 0) openGraph.tags = [...post.tags];
|
|
58
|
+
if (post.authors && post.authors.length > 0) openGraph.authors = [...post.authors];
|
|
86
59
|
if (ogImage) openGraph.images = [{ url: ogImage, alt: title }];
|
|
87
60
|
const meta = { title, openGraph };
|
|
88
61
|
if (description) meta.description = description;
|
|
@@ -97,10 +70,26 @@ function buildPostMetadata(post, options = {}) {
|
|
|
97
70
|
if (languages) meta.alternates.languages = languages;
|
|
98
71
|
}
|
|
99
72
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
73
|
+
if (options.siteUrl) {
|
|
74
|
+
const feedPath = options.feedPath ?? "/feed.xml";
|
|
75
|
+
const normalizedFeedPath = feedPath.startsWith("/") ? feedPath : `/${feedPath}`;
|
|
76
|
+
meta.alternates = {
|
|
77
|
+
...meta.alternates,
|
|
78
|
+
types: {
|
|
79
|
+
"application/rss+xml": `${trimSlash(options.siteUrl)}${normalizedFeedPath}`
|
|
80
|
+
}
|
|
81
|
+
};
|
|
102
82
|
}
|
|
83
|
+
const robots = resolveRobotsMeta({
|
|
84
|
+
...seo?.noindex !== void 0 && { noindex: seo.noindex },
|
|
85
|
+
...seo?.nofollow !== void 0 && { nofollow: seo.nofollow }
|
|
86
|
+
});
|
|
87
|
+
if (robots) meta.robots = robots;
|
|
103
88
|
if (post.id) meta.other = { "rt:content-id": post.id };
|
|
89
|
+
const twitter = { card: "summary_large_image", title };
|
|
90
|
+
if (description) twitter.description = description;
|
|
91
|
+
if (ogImage) twitter.images = [ogImage];
|
|
92
|
+
meta.twitter = twitter;
|
|
104
93
|
return meta;
|
|
105
94
|
}
|
|
106
95
|
function buildHreflangLanguages(translations, siteUrl, locales) {
|
|
@@ -120,40 +109,133 @@ function buildHreflangLanguages(translations, siteUrl, locales) {
|
|
|
120
109
|
return languages;
|
|
121
110
|
}
|
|
122
111
|
|
|
123
|
-
// src/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
112
|
+
// src/archive-index-policy.ts
|
|
113
|
+
var ARCHIVE_POST_COUNT_LIMIT = 200;
|
|
114
|
+
var NOT_FOUND = {
|
|
115
|
+
render: "notFound",
|
|
116
|
+
index: false,
|
|
117
|
+
inSitemap: false
|
|
118
|
+
};
|
|
119
|
+
var NOINDEX = {
|
|
120
|
+
render: "ok",
|
|
121
|
+
index: false,
|
|
122
|
+
inSitemap: false
|
|
123
|
+
};
|
|
124
|
+
var INDEXED = {
|
|
125
|
+
render: "ok",
|
|
126
|
+
index: true,
|
|
127
|
+
inSitemap: true
|
|
128
|
+
};
|
|
129
|
+
var POLICY_NOT_APPLIED = INDEXED;
|
|
130
|
+
function isNonNegativeInteger(value) {
|
|
131
|
+
return Number.isInteger(value) && value >= 0;
|
|
132
|
+
}
|
|
133
|
+
function resolveCategoryPromotion(promotedSlugs, slug) {
|
|
134
|
+
if (!promotedSlugs) return "unknown";
|
|
135
|
+
return promotedSlugs.includes(slug) ? "promoted" : "not-promoted";
|
|
136
|
+
}
|
|
137
|
+
function resolveAuthorPromotion(authorsEnabled) {
|
|
138
|
+
if (authorsEnabled === void 0) return "unknown";
|
|
139
|
+
return authorsEnabled ? "promoted" : "not-promoted";
|
|
140
|
+
}
|
|
141
|
+
function decideArchiveIndex(input) {
|
|
142
|
+
const page = input.page ?? 1;
|
|
143
|
+
if (!isNonNegativeInteger(input.postCount)) return NOINDEX;
|
|
144
|
+
if (!isNonNegativeInteger(page) || page < 1) return NOINDEX;
|
|
145
|
+
if (input.postCount === 0 && input.kind !== "search") return NOT_FOUND;
|
|
146
|
+
if (page >= 2) return NOINDEX;
|
|
147
|
+
if (input.kind !== "category" && input.kind !== "author") return NOINDEX;
|
|
148
|
+
switch (input.promotion) {
|
|
149
|
+
case "promoted":
|
|
150
|
+
return INDEXED;
|
|
151
|
+
case "unknown":
|
|
152
|
+
return POLICY_NOT_APPLIED;
|
|
153
|
+
default:
|
|
154
|
+
return NOINDEX;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function buildArchiveMetadata(input, options = {}) {
|
|
158
|
+
const decision = decideArchiveIndex(input);
|
|
159
|
+
const meta = { title: input.title };
|
|
160
|
+
if (input.description) meta.description = input.description;
|
|
161
|
+
if (options.siteUrl && options.path) {
|
|
162
|
+
const normalized = options.path.startsWith("/") ? options.path : `/${options.path}`;
|
|
163
|
+
meta.alternates = { canonical: `${trimSlash(options.siteUrl)}${normalized}` };
|
|
164
|
+
}
|
|
165
|
+
const robots = resolveRobotsMeta({
|
|
166
|
+
noindex: !decision.index,
|
|
167
|
+
...input.nofollow !== void 0 && { nofollow: input.nofollow }
|
|
168
|
+
});
|
|
169
|
+
if (robots) meta.robots = robots;
|
|
170
|
+
return meta;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/routes-sitemap-entries.ts
|
|
174
|
+
import {
|
|
175
|
+
fetchAuthors,
|
|
176
|
+
fetchBlogSettings,
|
|
177
|
+
fetchPosts as fetchPosts2
|
|
178
|
+
} from "@roottale/cms-client/server";
|
|
179
|
+
import { isInCollectionMode, resolvePostCollection as resolvePostCollection2, resolvePostUrl as resolvePostUrl2 } from "@roottale/cms-core";
|
|
180
|
+
|
|
181
|
+
// src/archive-categories.ts
|
|
182
|
+
import {
|
|
183
|
+
fetchCategoryCounts,
|
|
184
|
+
fetchPosts
|
|
185
|
+
} from "@roottale/cms-client/server";
|
|
186
|
+
async function fetchBlogArchivePosts(config, options = {}) {
|
|
187
|
+
const page = await fetchPosts({
|
|
188
|
+
apiKey: config.apiKey,
|
|
189
|
+
baseUrl: config.apiBase,
|
|
190
|
+
type: "post",
|
|
191
|
+
limit: ARCHIVE_POST_COUNT_LIMIT,
|
|
192
|
+
// 서버측 "미소속 글" 필터 — 페이지(`excludeCollections`)와 같은 정의.
|
|
193
|
+
excludeCollections: true,
|
|
194
|
+
...options.revalidate !== void 0 && { revalidate: options.revalidate }
|
|
195
|
+
});
|
|
196
|
+
return page.items;
|
|
197
|
+
}
|
|
198
|
+
async function fetchServerCategoryCounts(config, options) {
|
|
199
|
+
try {
|
|
200
|
+
const result = await fetchCategoryCounts({
|
|
201
|
+
apiKey: config.apiKey,
|
|
202
|
+
baseUrl: config.apiBase,
|
|
203
|
+
// 레거시 `/blog` 계열의 모집단 = 미소속 글. 페이지(`excludeCollections`)·
|
|
204
|
+
// 사이트맵과 **같은 서버 판정**을 쓰기 위해 서버 필터로 지정한다.
|
|
205
|
+
excludeCollections: true,
|
|
206
|
+
...options.revalidate !== void 0 && { revalidate: options.revalidate }
|
|
150
207
|
});
|
|
151
|
-
|
|
208
|
+
if (result.truncated) {
|
|
209
|
+
console.warn(
|
|
210
|
+
"[@roottale/cms-renderer-next/routes] \uBD84\uB958 \uC218\uAC00 \uC11C\uBC84 \uC0C1\uD55C\uC744 \uB118\uC5B4 \uC77C\uBD80\uAC00 \uC751\uB2F5\uC5D0\uC11C \uBE60\uC84C\uC2B5\uB2C8\uB2E4(\uC0C9\uC778\uC5D0\uC11C \uB204\uB77D\uB420 \uC218 \uC788\uC74C)."
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
return result.categories.filter((category) => category.publishedPostCount > 0).map((category) => ({
|
|
214
|
+
name: category.name,
|
|
215
|
+
slug: category.slug,
|
|
216
|
+
count: category.publishedPostCount
|
|
217
|
+
}));
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.warn(
|
|
220
|
+
"[@roottale/cms-renderer-next/routes] \uBD84\uB958\uBCC4 \uAE00 \uC218 \uC9D1\uACC4 API \uC2E4\uD328 \u2014 \uCD5C\uADFC \uAE00 \uBC30\uCE58 \uD30C\uC0DD\uC73C\uB85C \uD3F4\uBC31:",
|
|
221
|
+
err
|
|
222
|
+
);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function fetchBlogArchiveCategories(config, options = {}) {
|
|
227
|
+
const counts = await fetchServerCategoryCounts(config, options);
|
|
228
|
+
if (counts) return counts;
|
|
229
|
+
return collectCategoriesWithCounts(await fetchBlogArchivePosts(config, options));
|
|
152
230
|
}
|
|
231
|
+
|
|
232
|
+
// src/routes-sitemap-entries.ts
|
|
153
233
|
var SITEMAP_DEFAULTS = {
|
|
154
234
|
blogImages: true,
|
|
155
235
|
locales: [],
|
|
156
236
|
authors: false
|
|
237
|
+
// promotedCategorySlugs 는 의도적으로 기본값이 없다 — "모름"(undefined)과
|
|
238
|
+
// "승격 0건"([])을 구분해야 색인 정책을 fail-soft 로 적용할 수 있다.
|
|
157
239
|
};
|
|
158
240
|
async function safeFetchAuthors(config) {
|
|
159
241
|
try {
|
|
@@ -165,20 +247,29 @@ async function safeFetchAuthors(config) {
|
|
|
165
247
|
}
|
|
166
248
|
async function resolveSitemapSettings(config, opts) {
|
|
167
249
|
let remote = {};
|
|
250
|
+
let settingsFetchFailed = false;
|
|
168
251
|
if (!opts.skipRemoteSettings) {
|
|
169
252
|
try {
|
|
170
253
|
remote = (await fetchBlogSettings({
|
|
171
254
|
apiKey: config.apiKey,
|
|
172
255
|
baseUrl: config.apiBase
|
|
173
256
|
})).sitemap ?? {};
|
|
174
|
-
} catch {
|
|
257
|
+
} catch (err) {
|
|
258
|
+
settingsFetchFailed = true;
|
|
259
|
+
console.error(
|
|
260
|
+
"[@roottale/cms-renderer-next/routes] fetchBlogSettings \uC2E4\uD328(\uAE30\uBCF8\uAC12\uC73C\uB85C \uC9C4\uD589):",
|
|
261
|
+
err
|
|
262
|
+
);
|
|
175
263
|
}
|
|
176
264
|
}
|
|
177
|
-
|
|
265
|
+
const settings = {
|
|
178
266
|
blogImages: opts.blogImages ?? remote.blogImages ?? SITEMAP_DEFAULTS.blogImages,
|
|
179
267
|
locales: opts.locales ?? remote.locales ?? SITEMAP_DEFAULTS.locales,
|
|
180
268
|
authors: opts.authors ?? remote.authors ?? SITEMAP_DEFAULTS.authors
|
|
181
269
|
};
|
|
270
|
+
const promoted = opts.promotedCategorySlugs ?? remote.promotedCategorySlugs;
|
|
271
|
+
if (promoted) settings.promotedCategorySlugs = promoted;
|
|
272
|
+
return { settings, settingsFetchFailed };
|
|
182
273
|
}
|
|
183
274
|
async function localesWithPublishedContent(config, locales) {
|
|
184
275
|
if (locales.length === 0) return locales;
|
|
@@ -238,84 +329,152 @@ function postEntries(config, siteUrl, posts, collections, settings, defaultLocal
|
|
|
238
329
|
return [entry];
|
|
239
330
|
});
|
|
240
331
|
}
|
|
241
|
-
function
|
|
332
|
+
async function safeBlogArchiveCategories(config) {
|
|
333
|
+
try {
|
|
334
|
+
return await fetchBlogArchiveCategories(config);
|
|
335
|
+
} catch (err) {
|
|
336
|
+
console.error(
|
|
337
|
+
"[@roottale/cms-renderer-next/routes] \uC544\uCE74\uC774\uBE0C \uCE74\uD14C\uACE0\uB9AC \uC870\uD68C \uC2E4\uD328:",
|
|
338
|
+
err
|
|
339
|
+
);
|
|
340
|
+
return [];
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async function categoryEntries(config, siteUrl, collections, promotedSlugs) {
|
|
344
|
+
const inSitemap = (category) => decideArchiveIndex({
|
|
345
|
+
kind: "category",
|
|
346
|
+
promotion: resolveCategoryPromotion(promotedSlugs, category.slug),
|
|
347
|
+
postCount: category.count
|
|
348
|
+
}).inSitemap;
|
|
242
349
|
if (isInCollectionMode(collections)) {
|
|
350
|
+
const posts = await safeFetchPosts(config, ARCHIVE_POST_COUNT_LIMIT);
|
|
243
351
|
return collections.filter((c) => c.archives && c.basePath).flatMap((c) => {
|
|
244
352
|
const cats = collectCollectionCategories(posts, collections, c.key);
|
|
245
353
|
if (!cats.length) return [];
|
|
246
354
|
const base = `${siteUrl}${trimSlash(c.basePath)}`;
|
|
247
355
|
return [
|
|
248
356
|
{ url: `${base}/categories` },
|
|
249
|
-
...cats.map((category) => ({
|
|
357
|
+
...cats.filter(inSitemap).map((category) => ({
|
|
250
358
|
url: `${base}/categories/${category.slug}`
|
|
251
359
|
}))
|
|
252
360
|
];
|
|
253
361
|
});
|
|
254
362
|
}
|
|
255
|
-
const categories =
|
|
363
|
+
const categories = await safeBlogArchiveCategories(config);
|
|
256
364
|
if (!categories.length) return [];
|
|
257
365
|
const blogBase = config.blogBasePath ?? "/blog";
|
|
258
366
|
return [
|
|
259
367
|
{ url: `${siteUrl}${blogBase}/categories` },
|
|
260
|
-
...categories.map((category) => ({
|
|
368
|
+
...categories.filter(inSitemap).map((category) => ({
|
|
261
369
|
url: `${siteUrl}${blogBase}/categories/${category.slug}`
|
|
262
370
|
}))
|
|
263
371
|
];
|
|
264
372
|
}
|
|
373
|
+
async function authorEntries(config, siteUrl, settings, authorBasePath) {
|
|
374
|
+
if (!settings.authors) return [];
|
|
375
|
+
const authors = await safeFetchAuthors(config);
|
|
376
|
+
const base = trimSlash(authorBasePath ?? "/blog/author");
|
|
377
|
+
const promotion = resolveAuthorPromotion(settings.authors);
|
|
378
|
+
return authors.filter(
|
|
379
|
+
(a) => decideArchiveIndex({
|
|
380
|
+
kind: "author",
|
|
381
|
+
promotion,
|
|
382
|
+
postCount: a.postCount
|
|
383
|
+
}).inSitemap
|
|
384
|
+
).map((a) => ({
|
|
385
|
+
url: `${siteUrl}${base}/${encodeURIComponent(a.slug)}`,
|
|
386
|
+
lastModified: a.lastUpdatedAt ?? void 0
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/routes-feed-sitemap.ts
|
|
391
|
+
function createFeedRoute(config) {
|
|
392
|
+
return async function GET() {
|
|
393
|
+
const siteUrl = trimSlash(config.siteUrl);
|
|
394
|
+
const collections = await resolveCollections(config.collections);
|
|
395
|
+
const allPosts = await safeFetchPosts(config, 50);
|
|
396
|
+
const inCollectionMode = isInCollectionMode2(collections);
|
|
397
|
+
const blogBase = config.blogBasePath ?? "/blog";
|
|
398
|
+
const posts = inCollectionMode ? allPosts.filter((p) => {
|
|
399
|
+
const c = resolvePostCollection3(p, collections);
|
|
400
|
+
return c ? c.feed === true && c.detail !== false && c.basePath !== "" : false;
|
|
401
|
+
}) : allPosts;
|
|
402
|
+
const xml = generateRssXml({
|
|
403
|
+
title: config.title,
|
|
404
|
+
link: inCollectionMode ? siteUrl : `${siteUrl}${blogBase}`,
|
|
405
|
+
feedUrl: `${siteUrl}/feed.xml`,
|
|
406
|
+
description: config.description,
|
|
407
|
+
language: config.language,
|
|
408
|
+
items: rssItemsFromPosts(posts, {
|
|
409
|
+
postUrl: (p) => inCollectionMode ? resolvePostUrl3(siteUrl, p, collections) ?? `${siteUrl}${blogBase}/${p.slug}` : `${siteUrl}${blogBase}/${p.slug}`
|
|
410
|
+
})
|
|
411
|
+
});
|
|
412
|
+
return new Response(xml, {
|
|
413
|
+
headers: {
|
|
414
|
+
"content-type": "application/rss+xml; charset=utf-8",
|
|
415
|
+
"cache-control": "public, max-age=1800, s-maxage=1800"
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
};
|
|
419
|
+
}
|
|
265
420
|
function createSitemap(config, staticRoutes = []) {
|
|
266
421
|
return async function sitemap() {
|
|
267
422
|
const siteUrl = trimSlash(config.siteUrl);
|
|
268
423
|
const collections = await resolveCollections(config.collections);
|
|
269
|
-
const posts = await safeFetchPosts(config,
|
|
270
|
-
const settings = await resolveSitemapSettings(config, {
|
|
424
|
+
const posts = await safeFetchPosts(config, ARCHIVE_POST_COUNT_LIMIT);
|
|
425
|
+
const { settings } = await resolveSitemapSettings(config, {
|
|
271
426
|
skipRemoteSettings: true,
|
|
272
427
|
blogImages: false
|
|
273
428
|
});
|
|
274
429
|
return [
|
|
275
430
|
...staticEntries(staticRoutes),
|
|
276
431
|
...postEntries(config, siteUrl, posts, collections, settings),
|
|
277
|
-
|
|
432
|
+
// settings.promotedCategorySlugs 는 여기서 항상 undefined(위 skipRemoteSettings)
|
|
433
|
+
// → 색인 정책 미적용 = 레거시 동등. 정책이 필요하면 createSitemapIndex 로.
|
|
434
|
+
...await categoryEntries(config, siteUrl, collections, void 0)
|
|
278
435
|
];
|
|
279
436
|
};
|
|
280
437
|
}
|
|
281
438
|
function createSitemapIndex(config, staticRoutes = [], opts = {}) {
|
|
282
439
|
async function generateSitemaps() {
|
|
283
|
-
const settings = await resolveSitemapSettings(
|
|
440
|
+
const { settings, settingsFetchFailed } = await resolveSitemapSettings(
|
|
441
|
+
config,
|
|
442
|
+
opts
|
|
443
|
+
);
|
|
284
444
|
const ids = ["static", "blog", "categories"];
|
|
285
|
-
if (settings.authors) ids.push("authors");
|
|
445
|
+
if (settings.authors || settingsFetchFailed) ids.push("authors");
|
|
286
446
|
return ids.map((id) => ({ id }));
|
|
287
447
|
}
|
|
288
448
|
async function sitemap(props) {
|
|
289
449
|
const id = await props.id;
|
|
290
450
|
const siteUrl = trimSlash(config.siteUrl);
|
|
291
|
-
const settings = await resolveSitemapSettings(config, opts);
|
|
451
|
+
const { settings } = await resolveSitemapSettings(config, opts);
|
|
292
452
|
const activeLocales = await localesWithPublishedContent(config, settings.locales);
|
|
293
453
|
const defaultLocale = activeLocales[0];
|
|
294
454
|
if (id === "static") return staticEntries(staticRoutes);
|
|
295
455
|
if (id === "authors") {
|
|
296
|
-
|
|
297
|
-
const authors = await safeFetchAuthors(config);
|
|
298
|
-
const base = trimSlash(opts.authorBasePath ?? "/blog/author");
|
|
299
|
-
return authors.map((a) => ({
|
|
300
|
-
url: `${siteUrl}${base}/${encodeURIComponent(a.slug)}`,
|
|
301
|
-
lastModified: a.lastUpdatedAt ?? void 0
|
|
302
|
-
}));
|
|
456
|
+
return authorEntries(config, siteUrl, settings, opts.authorBasePath);
|
|
303
457
|
}
|
|
304
458
|
const collections = await resolveCollections(config.collections);
|
|
305
|
-
|
|
459
|
+
if (id === "categories") {
|
|
460
|
+
return categoryEntries(
|
|
461
|
+
config,
|
|
462
|
+
siteUrl,
|
|
463
|
+
collections,
|
|
464
|
+
settings.promotedCategorySlugs
|
|
465
|
+
);
|
|
466
|
+
}
|
|
306
467
|
if (id === "blog") {
|
|
468
|
+
const posts = await safeFetchPosts(config, ARCHIVE_POST_COUNT_LIMIT);
|
|
307
469
|
return postEntries(config, siteUrl, posts, collections, settings, defaultLocale);
|
|
308
470
|
}
|
|
309
|
-
if (id === "categories") {
|
|
310
|
-
return categoryEntries(config, siteUrl, posts, collections);
|
|
311
|
-
}
|
|
312
471
|
return [];
|
|
313
472
|
}
|
|
314
473
|
return { generateSitemaps, sitemap };
|
|
315
474
|
}
|
|
316
475
|
|
|
317
476
|
// src/routes-llms.ts
|
|
318
|
-
import { isInCollectionMode as
|
|
477
|
+
import { isInCollectionMode as isInCollectionMode3, resolvePostUrl as resolvePostUrl4 } from "@roottale/cms-core";
|
|
319
478
|
function mdLinkSafe(text) {
|
|
320
479
|
return text.replace(/[[\]()]/g, "").trim();
|
|
321
480
|
}
|
|
@@ -340,10 +499,10 @@ function createLlmsTxtRoute(config) {
|
|
|
340
499
|
}
|
|
341
500
|
}
|
|
342
501
|
if (posts.length > 0) {
|
|
343
|
-
const inCollectionMode =
|
|
502
|
+
const inCollectionMode = isInCollectionMode3(collections);
|
|
344
503
|
lines.push("", inCollectionMode ? "## \uCF58\uD150\uCE20" : "## \uBE14\uB85C\uADF8");
|
|
345
504
|
for (const p of posts) {
|
|
346
|
-
const url = inCollectionMode ?
|
|
505
|
+
const url = inCollectionMode ? resolvePostUrl4(siteUrl, p, collections) : `${siteUrl}${blogBase}/${p.slug}`;
|
|
347
506
|
if (!url) continue;
|
|
348
507
|
const excerpt = p.excerpt ? `: ${oneLine(p.excerpt)}` : "";
|
|
349
508
|
lines.push(`- [${mdLinkSafe(p.title)}](${url})${excerpt}`);
|
|
@@ -364,7 +523,7 @@ function createLlmsTxtRoute(config) {
|
|
|
364
523
|
import {
|
|
365
524
|
verifyRootTaleWebhook
|
|
366
525
|
} from "@roottale/cms-client/webhook";
|
|
367
|
-
import { isInCollectionMode as
|
|
526
|
+
import { isInCollectionMode as isInCollectionMode4 } from "@roottale/cms-core";
|
|
368
527
|
function pathsFromBody(rawBody) {
|
|
369
528
|
try {
|
|
370
529
|
const body = JSON.parse(rawBody);
|
|
@@ -420,7 +579,7 @@ function createRevalidateRoute(config) {
|
|
|
420
579
|
if (failed) {
|
|
421
580
|
alsoRevalidate = INVARIANTS;
|
|
422
581
|
warning = "collections_resolve_failed";
|
|
423
|
-
} else if (
|
|
582
|
+
} else if (isInCollectionMode4(collections)) {
|
|
424
583
|
alsoRevalidate = [
|
|
425
584
|
...INVARIANTS,
|
|
426
585
|
// 주소 없는 유형(basePath === "")은 라우트가 없으므로 revalidate 대상에서
|
|
@@ -671,7 +830,7 @@ function createFleetInfoRoute(config = {}) {
|
|
|
671
830
|
site: config.site ?? env.VERCEL_PROJECT_PRODUCTION_URL ?? null,
|
|
672
831
|
framework: "next",
|
|
673
832
|
cms_client: CMS_CLIENT_VERSION,
|
|
674
|
-
cms_renderer: true ? "0.
|
|
833
|
+
cms_renderer: true ? "0.51.0" : "dev",
|
|
675
834
|
build_sha: env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7) ?? null
|
|
676
835
|
},
|
|
677
836
|
{ headers: { "cache-control": "public, max-age=300" } }
|
|
@@ -679,8 +838,10 @@ function createFleetInfoRoute(config = {}) {
|
|
|
679
838
|
};
|
|
680
839
|
}
|
|
681
840
|
export {
|
|
841
|
+
ARCHIVE_POST_COUNT_LIMIT,
|
|
682
842
|
OG_IMAGE_CONTENT_TYPE,
|
|
683
843
|
OG_IMAGE_SIZE,
|
|
844
|
+
buildArchiveMetadata,
|
|
684
845
|
buildHreflangLanguages,
|
|
685
846
|
buildPostMetadata,
|
|
686
847
|
createFeedRoute,
|
|
@@ -691,13 +852,19 @@ export {
|
|
|
691
852
|
createRevalidateRoute,
|
|
692
853
|
createSitemap,
|
|
693
854
|
createSitemapIndex,
|
|
855
|
+
decideArchiveIndex,
|
|
856
|
+
fetchBlogArchiveCategories,
|
|
857
|
+
fetchBlogArchivePosts,
|
|
694
858
|
matchRedirect,
|
|
695
859
|
normalizeRedirectPath,
|
|
696
860
|
postRedirectPath,
|
|
861
|
+
resolveAuthorPromotion,
|
|
862
|
+
resolveCategoryPromotion,
|
|
697
863
|
resolveCollections,
|
|
698
864
|
resolveCollectionsResult,
|
|
699
865
|
resolvePostCollection,
|
|
700
866
|
resolvePostUrl,
|
|
867
|
+
resolveRobotsMeta,
|
|
701
868
|
safeFetchPosts,
|
|
702
869
|
trimSlash
|
|
703
870
|
};
|