@windrun-huaiin/third-ui 5.12.3 → 5.13.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/fuma/server.d.mts +12 -1
- package/dist/fuma/server.d.ts +12 -1
- package/dist/fuma/server.js +20 -4
- package/dist/fuma/server.js.map +1 -1
- package/dist/fuma/server.mjs +20 -4
- package/dist/fuma/server.mjs.map +1 -1
- package/dist/lib/server.d.mts +33 -1
- package/dist/lib/server.d.ts +33 -1
- package/dist/lib/server.js +75 -0
- package/dist/lib/server.js.map +1 -1
- package/dist/lib/server.mjs +61 -0
- package/dist/lib/server.mjs.map +1 -1
- package/package.json +1 -1
- package/src/fuma/fuma-page-genarator.tsx +30 -3
- package/src/lib/seo-util.ts +107 -0
- package/src/lib/server.ts +2 -1
package/dist/lib/server.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Translations } from 'fumadocs-ui/i18n';
|
|
2
2
|
import * as _clerk_types from '@clerk/types';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { MetadataRoute } from 'next';
|
|
4
5
|
|
|
5
6
|
declare const fumaI18nCn: Partial<Translations>;
|
|
6
7
|
|
|
@@ -4443,4 +4444,35 @@ declare const remarkInstallOptions: {
|
|
|
4443
4444
|
};
|
|
4444
4445
|
};
|
|
4445
4446
|
|
|
4446
|
-
|
|
4447
|
+
/**
|
|
4448
|
+
* Generate robots.txt content
|
|
4449
|
+
* @param baseUrl - The base URL of the website
|
|
4450
|
+
* @returns Robots configuration
|
|
4451
|
+
*/
|
|
4452
|
+
declare function generateRobots(baseUrl: string): MetadataRoute.Robots;
|
|
4453
|
+
/**
|
|
4454
|
+
* Generate sitemap.xml content
|
|
4455
|
+
* @param baseUrl - The base URL of the website
|
|
4456
|
+
* @param locales - Supported locales array
|
|
4457
|
+
* @param mdxSourceDir - MDX source directory path
|
|
4458
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
4459
|
+
* @returns Sitemap entries
|
|
4460
|
+
*/
|
|
4461
|
+
declare function generateSitemap(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): MetadataRoute.Sitemap;
|
|
4462
|
+
/**
|
|
4463
|
+
* Create robots.txt handler function
|
|
4464
|
+
* @param baseUrl - The base URL of the website
|
|
4465
|
+
* @returns Robots handler function
|
|
4466
|
+
*/
|
|
4467
|
+
declare function createRobotsHandler(baseUrl: string): () => MetadataRoute.Robots;
|
|
4468
|
+
/**
|
|
4469
|
+
* Create sitemap.xml handler function
|
|
4470
|
+
* @param baseUrl - The base URL of the website
|
|
4471
|
+
* @param locales - Supported locales array
|
|
4472
|
+
* @param mdxSourceDir - MDX source directory path
|
|
4473
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
4474
|
+
* @returns Sitemap handler function
|
|
4475
|
+
*/
|
|
4476
|
+
declare function createSitemapHandler(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): () => MetadataRoute.Sitemap;
|
|
4477
|
+
|
|
4478
|
+
export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createRobotsHandler, createSitemapHandler, createTitleSchema, fumaI18nCn, generateRobots, generateSitemap, remarkInstallOptions };
|
package/dist/lib/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Translations } from 'fumadocs-ui/i18n';
|
|
2
2
|
import * as _clerk_types from '@clerk/types';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { MetadataRoute } from 'next';
|
|
4
5
|
|
|
5
6
|
declare const fumaI18nCn: Partial<Translations>;
|
|
6
7
|
|
|
@@ -4443,4 +4444,35 @@ declare const remarkInstallOptions: {
|
|
|
4443
4444
|
};
|
|
4444
4445
|
};
|
|
4445
4446
|
|
|
4446
|
-
|
|
4447
|
+
/**
|
|
4448
|
+
* Generate robots.txt content
|
|
4449
|
+
* @param baseUrl - The base URL of the website
|
|
4450
|
+
* @returns Robots configuration
|
|
4451
|
+
*/
|
|
4452
|
+
declare function generateRobots(baseUrl: string): MetadataRoute.Robots;
|
|
4453
|
+
/**
|
|
4454
|
+
* Generate sitemap.xml content
|
|
4455
|
+
* @param baseUrl - The base URL of the website
|
|
4456
|
+
* @param locales - Supported locales array
|
|
4457
|
+
* @param mdxSourceDir - MDX source directory path
|
|
4458
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
4459
|
+
* @returns Sitemap entries
|
|
4460
|
+
*/
|
|
4461
|
+
declare function generateSitemap(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): MetadataRoute.Sitemap;
|
|
4462
|
+
/**
|
|
4463
|
+
* Create robots.txt handler function
|
|
4464
|
+
* @param baseUrl - The base URL of the website
|
|
4465
|
+
* @returns Robots handler function
|
|
4466
|
+
*/
|
|
4467
|
+
declare function createRobotsHandler(baseUrl: string): () => MetadataRoute.Robots;
|
|
4468
|
+
/**
|
|
4469
|
+
* Create sitemap.xml handler function
|
|
4470
|
+
* @param baseUrl - The base URL of the website
|
|
4471
|
+
* @param locales - Supported locales array
|
|
4472
|
+
* @param mdxSourceDir - MDX source directory path
|
|
4473
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
4474
|
+
* @returns Sitemap handler function
|
|
4475
|
+
*/
|
|
4476
|
+
declare function createSitemapHandler(baseUrl: string, locales: string[], mdxSourceDir: string, openMdxSEOSiteMap?: boolean): () => MetadataRoute.Sitemap;
|
|
4477
|
+
|
|
4478
|
+
export { clerkIntl, createCommonDocsSchema, createCommonMetaSchema, createDateSchema, createDescriptionSchema, createIconSchema, createRobotsHandler, createSitemapHandler, createTitleSchema, fumaI18nCn, generateRobots, generateSitemap, remarkInstallOptions };
|
package/dist/lib/server.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
6
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
10
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -29,6 +31,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
29
31
|
}
|
|
30
32
|
return to;
|
|
31
33
|
};
|
|
34
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
35
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
36
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
37
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
38
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
39
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
40
|
+
mod
|
|
41
|
+
));
|
|
32
42
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
43
|
|
|
34
44
|
// src/lib/server.ts
|
|
@@ -40,8 +50,12 @@ __export(server_exports, {
|
|
|
40
50
|
createDateSchema: () => createDateSchema,
|
|
41
51
|
createDescriptionSchema: () => createDescriptionSchema,
|
|
42
52
|
createIconSchema: () => createIconSchema,
|
|
53
|
+
createRobotsHandler: () => createRobotsHandler,
|
|
54
|
+
createSitemapHandler: () => createSitemapHandler,
|
|
43
55
|
createTitleSchema: () => createTitleSchema,
|
|
44
56
|
fumaI18nCn: () => fumaI18nCn,
|
|
57
|
+
generateRobots: () => generateRobots,
|
|
58
|
+
generateSitemap: () => generateSitemap,
|
|
45
59
|
remarkInstallOptions: () => remarkInstallOptions
|
|
46
60
|
});
|
|
47
61
|
module.exports = __toCommonJS(server_exports);
|
|
@@ -111,6 +125,63 @@ var remarkInstallOptions = {
|
|
|
111
125
|
id: "package-manager"
|
|
112
126
|
}
|
|
113
127
|
};
|
|
128
|
+
|
|
129
|
+
// src/lib/seo-util.ts
|
|
130
|
+
var import_fs = __toESM(require("fs"));
|
|
131
|
+
var import_path = __toESM(require("path"));
|
|
132
|
+
function generateRobots(baseUrl) {
|
|
133
|
+
return {
|
|
134
|
+
rules: {
|
|
135
|
+
userAgent: "*",
|
|
136
|
+
allow: "/"
|
|
137
|
+
},
|
|
138
|
+
sitemap: `${baseUrl}/sitemap.xml`
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
|
|
142
|
+
const blogDir = import_path.default.join(process.cwd(), mdxSourceDir);
|
|
143
|
+
const blogFiles = import_fs.default.readdirSync(blogDir).filter((f) => f.endsWith(".mdx"));
|
|
144
|
+
const blogRoutes = [];
|
|
145
|
+
for (const locale of locales) {
|
|
146
|
+
for (const f of blogFiles) {
|
|
147
|
+
if (f === "index.mdx") {
|
|
148
|
+
blogRoutes.push({
|
|
149
|
+
url: `${baseUrl}/${locale}/blog`,
|
|
150
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
151
|
+
changeFrequency: "daily",
|
|
152
|
+
priority: 1
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
const slug = f.replace(/\.mdx$/, "");
|
|
156
|
+
blogRoutes.push({
|
|
157
|
+
url: `${baseUrl}/${locale}/blog/${slug}`,
|
|
158
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
159
|
+
changeFrequency: f === "ioc.mdx" ? "daily" : "monthly",
|
|
160
|
+
priority: 0.8
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const mainRoutes = locales.map((locale) => ({
|
|
166
|
+
url: `${baseUrl}/${locale}`,
|
|
167
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
168
|
+
changeFrequency: "weekly",
|
|
169
|
+
priority: 1
|
|
170
|
+
}));
|
|
171
|
+
return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
|
|
172
|
+
}
|
|
173
|
+
function createRobotsHandler(baseUrl) {
|
|
174
|
+
return function robots() {
|
|
175
|
+
return generateRobots(baseUrl);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function createSitemapHandler(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
|
|
179
|
+
const sitemapHandler = function sitemap() {
|
|
180
|
+
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
|
|
181
|
+
};
|
|
182
|
+
sitemapHandler.dynamic = "force-static";
|
|
183
|
+
return sitemapHandler;
|
|
184
|
+
}
|
|
114
185
|
// Annotate the CommonJS export names for ESM import in node:
|
|
115
186
|
0 && (module.exports = {
|
|
116
187
|
clerkIntl,
|
|
@@ -119,8 +190,12 @@ var remarkInstallOptions = {
|
|
|
119
190
|
createDateSchema,
|
|
120
191
|
createDescriptionSchema,
|
|
121
192
|
createIconSchema,
|
|
193
|
+
createRobotsHandler,
|
|
194
|
+
createSitemapHandler,
|
|
122
195
|
createTitleSchema,
|
|
123
196
|
fumaI18nCn,
|
|
197
|
+
generateRobots,
|
|
198
|
+
generateSitemap,
|
|
124
199
|
remarkInstallOptions
|
|
125
200
|
});
|
|
126
201
|
//# sourceMappingURL=server.js.map
|
package/dist/lib/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/server.ts","../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts"],"sourcesContent":["// This is a server component!\n\nexport * from './fuma-search-util';\nexport * from './clerk-intl';\nexport * from './fuma-schema-check-util';","import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/lib/server.ts","../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts","../../src/lib/seo-util.ts"],"sourcesContent":["// This is a server component!\n\nexport * from './fuma-search-util';\nexport * from './clerk-intl';\nexport * from './fuma-schema-check-util';\nexport * from './seo-util';","import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};","import type { MetadataRoute } from 'next';\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * Generate robots.txt content\n * @param baseUrl - The base URL of the website\n * @returns Robots configuration\n */\nexport function generateRobots(baseUrl: string): MetadataRoute.Robots {\n return {\n rules: {\n userAgent: \"*\",\n allow: \"/\",\n },\n sitemap: `${baseUrl}/sitemap.xml`,\n };\n}\n\n/**\n * Generate sitemap.xml content\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap entries\n */\nexport function generateSitemap(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n): MetadataRoute.Sitemap {\n // 1. read all blog mdx file names\n const blogDir = path.join(process.cwd(), mdxSourceDir);\n const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));\n\n // 2. handle index.mdx (blog start page) and other slugs\n const blogRoutes: MetadataRoute.Sitemap = [];\n\n for (const locale of locales) {\n for (const f of blogFiles) {\n if (f === 'index.mdx') {\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog`,\n lastModified: new Date(),\n changeFrequency: 'daily',\n priority: 1.0\n });\n } else {\n const slug = f.replace(/\\.mdx$/, '');\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog/${slug}`,\n lastModified: new Date(),\n changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',\n priority: 0.8\n });\n }\n }\n }\n\n // 3. main page (all language versions)\n const mainRoutes = locales.map(locale => ({\n url: `${baseUrl}/${locale}`,\n lastModified: new Date(),\n changeFrequency: 'weekly' as const,\n priority: 1.0\n }));\n\n return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];\n}\n\n/**\n * Create robots.txt handler function\n * @param baseUrl - The base URL of the website\n * @returns Robots handler function\n */\nexport function createRobotsHandler(baseUrl: string) {\n return function robots(): MetadataRoute.Robots {\n return generateRobots(baseUrl);\n };\n}\n\n/**\n * Create sitemap.xml handler function\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap handler function\n */\nexport function createSitemapHandler(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n) {\n // force static generation\n const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {\n return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);\n };\n \n // Add static generation directive\n (sitemapHandler as any).dynamic = 'force-static';\n \n return sitemapHandler;\n}"],"mappings":"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","names":["path","fs"]}
|
package/dist/lib/server.mjs
CHANGED
|
@@ -80,6 +80,63 @@ var remarkInstallOptions = {
|
|
|
80
80
|
id: "package-manager"
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
|
+
|
|
84
|
+
// src/lib/seo-util.ts
|
|
85
|
+
import fs from "fs";
|
|
86
|
+
import path from "path";
|
|
87
|
+
function generateRobots(baseUrl) {
|
|
88
|
+
return {
|
|
89
|
+
rules: {
|
|
90
|
+
userAgent: "*",
|
|
91
|
+
allow: "/"
|
|
92
|
+
},
|
|
93
|
+
sitemap: `${baseUrl}/sitemap.xml`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
|
|
97
|
+
const blogDir = path.join(process.cwd(), mdxSourceDir);
|
|
98
|
+
const blogFiles = fs.readdirSync(blogDir).filter((f) => f.endsWith(".mdx"));
|
|
99
|
+
const blogRoutes = [];
|
|
100
|
+
for (const locale of locales) {
|
|
101
|
+
for (const f of blogFiles) {
|
|
102
|
+
if (f === "index.mdx") {
|
|
103
|
+
blogRoutes.push({
|
|
104
|
+
url: `${baseUrl}/${locale}/blog`,
|
|
105
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
106
|
+
changeFrequency: "daily",
|
|
107
|
+
priority: 1
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
const slug = f.replace(/\.mdx$/, "");
|
|
111
|
+
blogRoutes.push({
|
|
112
|
+
url: `${baseUrl}/${locale}/blog/${slug}`,
|
|
113
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
114
|
+
changeFrequency: f === "ioc.mdx" ? "daily" : "monthly",
|
|
115
|
+
priority: 0.8
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const mainRoutes = locales.map((locale) => ({
|
|
121
|
+
url: `${baseUrl}/${locale}`,
|
|
122
|
+
lastModified: /* @__PURE__ */ new Date(),
|
|
123
|
+
changeFrequency: "weekly",
|
|
124
|
+
priority: 1
|
|
125
|
+
}));
|
|
126
|
+
return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
|
|
127
|
+
}
|
|
128
|
+
function createRobotsHandler(baseUrl) {
|
|
129
|
+
return function robots() {
|
|
130
|
+
return generateRobots(baseUrl);
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function createSitemapHandler(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap = true) {
|
|
134
|
+
const sitemapHandler = function sitemap() {
|
|
135
|
+
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
|
|
136
|
+
};
|
|
137
|
+
sitemapHandler.dynamic = "force-static";
|
|
138
|
+
return sitemapHandler;
|
|
139
|
+
}
|
|
83
140
|
export {
|
|
84
141
|
clerkIntl,
|
|
85
142
|
createCommonDocsSchema,
|
|
@@ -87,8 +144,12 @@ export {
|
|
|
87
144
|
createDateSchema,
|
|
88
145
|
createDescriptionSchema,
|
|
89
146
|
createIconSchema,
|
|
147
|
+
createRobotsHandler,
|
|
148
|
+
createSitemapHandler,
|
|
90
149
|
createTitleSchema,
|
|
91
150
|
fumaI18nCn,
|
|
151
|
+
generateRobots,
|
|
152
|
+
generateSitemap,
|
|
92
153
|
remarkInstallOptions
|
|
93
154
|
};
|
|
94
155
|
//# sourceMappingURL=server.mjs.map
|
package/dist/lib/server.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts"],"sourcesContent":["import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};"],"mappings":";;;;;;;;;;;;;;;;;;AAEO,IAAM,aAAoC;AAAA,EAC/C,QAAQ;AAAA;AAEV;;;ACLA,SAAS,MAAM,YAAY;AAK3B,IAAM,WAAiC,mBAClC;AAGE,IAAM,YAAY;AAAA,EACvB,IAAI;AAAA,EACJ,IAAI;AACN;;;ACZA,SAAS,SAAS;AAClB,SAAS,mBAAmB,kBAAkB;AAIvC,IAAM,oBAAoB,MAC/B,EAAE,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,oBAAoB;AACtB,CAAC,EACA,KAAK,EACL,IAAI,GAAG,EAAE,SAAS,sDAAsD,CAAC;AAGrE,IAAM,0BAA0B,MACrC,EAAE;AAAA,EACA,CAAC,QAAa;AACZ,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK,MAAM,MAAM,QAAQ,OAAO,SAAY,IAAI,KAAK;AAAA,IAClE;AACA,WAAO,QAAQ,OAAO,SAAY;AAAA,EACpC;AAAA,EACA,EAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,EAAE;AAAA,EACA,CAAC,QAAc,QAAQ,MAAM,QAAQ,OAAO,SAAY;AAAA,EACxD,EAAE,OAAO,EAAE,SAAS;AACtB;AAGK,IAAM,mBAAmB,MAC9B,EAAE;AAAA,EAAW,CAAC,QAAa;AACzB,QAAI,eAAe,MAAM;AAEvB,YAAM,OAAO,IAAI,YAAY;AAC7B,YAAM,SAAS,IAAI,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAC7D,YAAM,MAAM,IAAI,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACpD,aAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA,IAChC;AACA,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,IAAI,KAAK;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA,EACA,EAAE,OAAO,EACN,MAAM,uBAAuB,0DAA0D,EACvF,OAAO,CAAC,QAAa,CAAC,MAAM,IAAI,KAAK,GAAG,EAAE,QAAQ,CAAC,GAAG,eAAe;AACxE;AAGK,IAAM,yBAAyB,MAAM,kBAAkB,OAAO;AAAA,EACnE,OAAO,kBAAkB;AAAA,EACzB,aAAa,wBAAwB;AAAA,EACrC,MAAM,iBAAiB;AAAA,EACvB,MAAM,iBAAiB;AAAA,EACvB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AACzC,CAAC;AAGM,IAAM,yBAAyB,MAAM,WAAW,OAAO;AAAA,EAC5D,aAAa,EAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAEM,IAAM,uBAAuB;AAAA,EAClC,SAAS;AAAA,IACP,IAAI;AAAA,EACN;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/fuma-search-util.ts","../../src/lib/clerk-intl.ts","../../src/lib/fuma-schema-check-util.ts","../../src/lib/seo-util.ts"],"sourcesContent":["import { Translations } from 'fumadocs-ui/i18n';\n\nexport const fumaI18nCn: Partial<Translations> = {\n search: 'Translated Content',\n // other translations\n};\n","import { enUS, zhCN } from '@clerk/localizations';\nimport type { LocalizationResource } from '@clerk/types';\n\n// https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts#L492\n// https://clerk.com/docs/customization/localization\nconst customZH: LocalizationResource = {\n ...zhCN,\n}\n\nexport const clerkIntl = {\n en: enUS,\n zh: customZH,\n}","import { z } from 'zod';\nimport { frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';\n\n\n// Reusable schema for title\nexport const createTitleSchema = () =>\n z.string({\n required_error: \"Title is required\",\n invalid_type_error: \"Title must be a string and cannot be null\",\n })\n .trim()\n .min(1, { message: \"Title cannot be empty or consist only of whitespace\" });\n\n// Reusable schema for description\nexport const createDescriptionSchema = () =>\n z.preprocess(\n (val: any) => {\n if (typeof val === 'string') {\n return val.trim() === \"\" || val === null ? undefined : val.trim();\n }\n return val === null ? undefined : val;\n },\n z.string().optional()\n );\n\n// Reusable schema for icon\nexport const createIconSchema = () =>\n z.preprocess(\n (val: any) => (val === \"\" || val === null ? undefined : val),\n z.string().optional()\n );\n\n// Reusable schema for date\nexport const createDateSchema = () =>\n z.preprocess((arg: any) => {\n if (arg instanceof Date) {\n // Format Date object to YYYY-MM-DD string\n const year = arg.getFullYear();\n const month = (arg.getMonth() + 1).toString().padStart(2, '0');\n const day = arg.getDate().toString().padStart(2, '0');\n return `${year}-${month}-${day}`;\n }\n if (typeof arg === 'string') {\n return arg.trim();\n }\n // For other types or null/undefined, let the subsequent string validation handle it\n return arg; \n },\n z.string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"Date must be in YYYY-MM-DD format or a valid Date object\")\n .refine((val: any) => !isNaN(new Date(val).getTime()), 'Invalid date!')\n );\n\n// common docs frontmatter schema\nexport const createCommonDocsSchema = () => frontmatterSchema.extend({\n title: createTitleSchema(),\n description: createDescriptionSchema(),\n icon: createIconSchema(),\n date: createDateSchema(),\n author: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n});\n\n// common meta schema\nexport const createCommonMetaSchema = () => metaSchema.extend({\n description: z.string().optional(),\n});\n\nexport const remarkInstallOptions = {\n persist: {\n id: 'package-manager',\n },\n};","import type { MetadataRoute } from 'next';\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * Generate robots.txt content\n * @param baseUrl - The base URL of the website\n * @returns Robots configuration\n */\nexport function generateRobots(baseUrl: string): MetadataRoute.Robots {\n return {\n rules: {\n userAgent: \"*\",\n allow: \"/\",\n },\n sitemap: `${baseUrl}/sitemap.xml`,\n };\n}\n\n/**\n * Generate sitemap.xml content\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap entries\n */\nexport function generateSitemap(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n): MetadataRoute.Sitemap {\n // 1. read all blog mdx file names\n const blogDir = path.join(process.cwd(), mdxSourceDir);\n const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));\n\n // 2. handle index.mdx (blog start page) and other slugs\n const blogRoutes: MetadataRoute.Sitemap = [];\n\n for (const locale of locales) {\n for (const f of blogFiles) {\n if (f === 'index.mdx') {\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog`,\n lastModified: new Date(),\n changeFrequency: 'daily',\n priority: 1.0\n });\n } else {\n const slug = f.replace(/\\.mdx$/, '');\n blogRoutes.push({\n url: `${baseUrl}/${locale}/blog/${slug}`,\n lastModified: new Date(),\n changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',\n priority: 0.8\n });\n }\n }\n }\n\n // 3. main page (all language versions)\n const mainRoutes = locales.map(locale => ({\n url: `${baseUrl}/${locale}`,\n lastModified: new Date(),\n changeFrequency: 'weekly' as const,\n priority: 1.0\n }));\n\n return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];\n}\n\n/**\n * Create robots.txt handler function\n * @param baseUrl - The base URL of the website\n * @returns Robots handler function\n */\nexport function createRobotsHandler(baseUrl: string) {\n return function robots(): MetadataRoute.Robots {\n return generateRobots(baseUrl);\n };\n}\n\n/**\n * Create sitemap.xml handler function\n * @param baseUrl - The base URL of the website\n * @param locales - Supported locales array\n * @param mdxSourceDir - MDX source directory path\n * @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true\n * @returns Sitemap handler function\n */\nexport function createSitemapHandler(\n baseUrl: string,\n locales: string[],\n mdxSourceDir: string,\n openMdxSEOSiteMap: boolean = true\n) {\n // force static generation\n const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {\n return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);\n };\n \n // Add static generation directive\n (sitemapHandler as any).dynamic = 'force-static';\n \n return sitemapHandler;\n}"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -35,7 +35,11 @@ interface FumaPageParams {
|
|
|
35
35
|
/*
|
|
36
36
|
* The fallback page component to use when the page is not found
|
|
37
37
|
*/
|
|
38
|
-
FallbackPage: React.ComponentType<{ siteIcon: ReactNode }>;
|
|
38
|
+
FallbackPage: React.ComponentType<{ siteIcon: ReactNode }>;
|
|
39
|
+
/*
|
|
40
|
+
* Supported locales for generating alternates metadata, defaults to ['en']
|
|
41
|
+
*/
|
|
42
|
+
supportedLocales?: string[];
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export function createFumaPage({
|
|
@@ -47,6 +51,7 @@ export function createFumaPage({
|
|
|
47
51
|
copyButtonComponent,
|
|
48
52
|
siteIcon,
|
|
49
53
|
FallbackPage,
|
|
54
|
+
supportedLocales = ['en'],
|
|
50
55
|
}: FumaPageParams) {
|
|
51
56
|
const Page = async function Page({ params }: { params: Promise<{ locale: string; slug?: string[] }> }) {
|
|
52
57
|
const { slug, locale } = await params;
|
|
@@ -92,17 +97,39 @@ export function createFumaPage({
|
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
async function generateMetadata(props: { params: Promise<{ slug?: string[]; locale?: string }> }) {
|
|
95
|
-
const
|
|
96
|
-
const page = mdxContentSource.getPage(
|
|
100
|
+
const { slug, locale } = await props.params;
|
|
101
|
+
const page = mdxContentSource.getPage(slug, locale);
|
|
97
102
|
if (!page) {
|
|
98
103
|
return {
|
|
99
104
|
title: '404 - Page Not Found',
|
|
100
105
|
description: 'This page could not be found.',
|
|
101
106
|
};
|
|
102
107
|
}
|
|
108
|
+
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL!;
|
|
109
|
+
const baseRoute = mdxSourceDir.replace('src/mdx/', '');
|
|
110
|
+
// build the current page path
|
|
111
|
+
const currentPath = slug ? slug.join('/') : '';
|
|
112
|
+
const currentUrl = `${baseUrl}/${locale}/${baseRoute}${currentPath ? `/${currentPath}` : ''}`;
|
|
113
|
+
|
|
114
|
+
// generate the seo language map
|
|
115
|
+
const seoLanguageMap: Record<string, string> = {};
|
|
116
|
+
|
|
117
|
+
console.log('supportedLocales', supportedLocales);
|
|
118
|
+
|
|
119
|
+
supportedLocales.forEach(loc => {
|
|
120
|
+
seoLanguageMap[loc] = `${baseUrl}/${loc}/${baseRoute}${currentPath ? `/${currentPath}` : ''}`;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
console.log('seoLanguageMap', seoLanguageMap);
|
|
124
|
+
|
|
103
125
|
return {
|
|
126
|
+
metadataBase: new URL(baseUrl),
|
|
104
127
|
title: page.data.title,
|
|
105
128
|
description: page.data.description,
|
|
129
|
+
alternates: {
|
|
130
|
+
canonical: currentUrl,
|
|
131
|
+
languages: seoLanguageMap
|
|
132
|
+
},
|
|
106
133
|
};
|
|
107
134
|
}
|
|
108
135
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { MetadataRoute } from 'next';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate robots.txt content
|
|
7
|
+
* @param baseUrl - The base URL of the website
|
|
8
|
+
* @returns Robots configuration
|
|
9
|
+
*/
|
|
10
|
+
export function generateRobots(baseUrl: string): MetadataRoute.Robots {
|
|
11
|
+
return {
|
|
12
|
+
rules: {
|
|
13
|
+
userAgent: "*",
|
|
14
|
+
allow: "/",
|
|
15
|
+
},
|
|
16
|
+
sitemap: `${baseUrl}/sitemap.xml`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generate sitemap.xml content
|
|
22
|
+
* @param baseUrl - The base URL of the website
|
|
23
|
+
* @param locales - Supported locales array
|
|
24
|
+
* @param mdxSourceDir - MDX source directory path
|
|
25
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
26
|
+
* @returns Sitemap entries
|
|
27
|
+
*/
|
|
28
|
+
export function generateSitemap(
|
|
29
|
+
baseUrl: string,
|
|
30
|
+
locales: string[],
|
|
31
|
+
mdxSourceDir: string,
|
|
32
|
+
openMdxSEOSiteMap: boolean = true
|
|
33
|
+
): MetadataRoute.Sitemap {
|
|
34
|
+
// 1. read all blog mdx file names
|
|
35
|
+
const blogDir = path.join(process.cwd(), mdxSourceDir);
|
|
36
|
+
const blogFiles = fs.readdirSync(blogDir).filter(f => f.endsWith('.mdx'));
|
|
37
|
+
|
|
38
|
+
// 2. handle index.mdx (blog start page) and other slugs
|
|
39
|
+
const blogRoutes: MetadataRoute.Sitemap = [];
|
|
40
|
+
|
|
41
|
+
for (const locale of locales) {
|
|
42
|
+
for (const f of blogFiles) {
|
|
43
|
+
if (f === 'index.mdx') {
|
|
44
|
+
blogRoutes.push({
|
|
45
|
+
url: `${baseUrl}/${locale}/blog`,
|
|
46
|
+
lastModified: new Date(),
|
|
47
|
+
changeFrequency: 'daily',
|
|
48
|
+
priority: 1.0
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
const slug = f.replace(/\.mdx$/, '');
|
|
52
|
+
blogRoutes.push({
|
|
53
|
+
url: `${baseUrl}/${locale}/blog/${slug}`,
|
|
54
|
+
lastModified: new Date(),
|
|
55
|
+
changeFrequency: f === 'ioc.mdx' ? 'daily' : 'monthly',
|
|
56
|
+
priority: 0.8
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 3. main page (all language versions)
|
|
63
|
+
const mainRoutes = locales.map(locale => ({
|
|
64
|
+
url: `${baseUrl}/${locale}`,
|
|
65
|
+
lastModified: new Date(),
|
|
66
|
+
changeFrequency: 'weekly' as const,
|
|
67
|
+
priority: 1.0
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
return openMdxSEOSiteMap ? [...mainRoutes, ...blogRoutes] : [...mainRoutes];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create robots.txt handler function
|
|
75
|
+
* @param baseUrl - The base URL of the website
|
|
76
|
+
* @returns Robots handler function
|
|
77
|
+
*/
|
|
78
|
+
export function createRobotsHandler(baseUrl: string) {
|
|
79
|
+
return function robots(): MetadataRoute.Robots {
|
|
80
|
+
return generateRobots(baseUrl);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Create sitemap.xml handler function
|
|
86
|
+
* @param baseUrl - The base URL of the website
|
|
87
|
+
* @param locales - Supported locales array
|
|
88
|
+
* @param mdxSourceDir - MDX source directory path
|
|
89
|
+
* @param openMdxSEOSiteMap - Whether to include MDX content in sitemap, default is true
|
|
90
|
+
* @returns Sitemap handler function
|
|
91
|
+
*/
|
|
92
|
+
export function createSitemapHandler(
|
|
93
|
+
baseUrl: string,
|
|
94
|
+
locales: string[],
|
|
95
|
+
mdxSourceDir: string,
|
|
96
|
+
openMdxSEOSiteMap: boolean = true
|
|
97
|
+
) {
|
|
98
|
+
// force static generation
|
|
99
|
+
const sitemapHandler = function sitemap(): MetadataRoute.Sitemap {
|
|
100
|
+
return generateSitemap(baseUrl, locales, mdxSourceDir, openMdxSEOSiteMap);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Add static generation directive
|
|
104
|
+
(sitemapHandler as any).dynamic = 'force-static';
|
|
105
|
+
|
|
106
|
+
return sitemapHandler;
|
|
107
|
+
}
|
package/src/lib/server.ts
CHANGED