fumapress 0.5.1 → 0.5.2
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/css/generated.css +13 -0
- package/dist/client.d.ts +2 -22
- package/dist/client.js +3 -9
- package/dist/components/blog.js +3 -3
- package/dist/components/link.d.ts +25 -0
- package/dist/components/link.js +18 -0
- package/dist/components/provider.js +2 -1
- package/dist/layouts/blog.index.js +2 -2
- package/dist/layouts/blog.js +2 -2
- package/dist/layouts/blog.tags.js +2 -2
- package/dist/lib/types.d.ts +5 -2
- package/dist/plugins/link-validation.d.ts +24 -0
- package/dist/plugins/link-validation.js +30 -0
- package/dist/plugins/llms.txt.js +1 -1
- package/dist/plugins/sitemap.d.ts +196 -0
- package/dist/plugins/sitemap.js +90 -0
- package/dist/plugins/takumi.js +2 -3
- package/dist/router/index.d.ts +2 -2
- package/dist/router/index.js +16 -21
- package/dist/vite.js +2 -2
- package/package.json +8 -3
package/css/generated.css
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
@source inline("allTags");
|
|
16
16
|
@source inline("allowed");
|
|
17
17
|
@source inline("allows");
|
|
18
|
+
@source inline("always");
|
|
18
19
|
@source inline("and");
|
|
19
20
|
@source inline("and/or");
|
|
20
21
|
@source inline("any");
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
@source inline("cases");
|
|
63
64
|
@source inline("cause");
|
|
64
65
|
@source inline("causes");
|
|
66
|
+
@source inline("change");
|
|
65
67
|
@source inline("check");
|
|
66
68
|
@source inline("children");
|
|
67
69
|
@source inline("class-variance-authority");
|
|
@@ -147,6 +149,7 @@
|
|
|
147
149
|
@source inline("flex-row");
|
|
148
150
|
@source inline("flex-wrap");
|
|
149
151
|
@source inline("flexsearchStaticClient");
|
|
152
|
+
@source inline("fn");
|
|
150
153
|
@source inline("following");
|
|
151
154
|
@source inline("font-medium");
|
|
152
155
|
@source inline("font-mono");
|
|
@@ -155,6 +158,7 @@
|
|
|
155
158
|
@source inline("framework");
|
|
156
159
|
@source inline("free");
|
|
157
160
|
@source inline("from");
|
|
161
|
+
@source inline("fromPathname");
|
|
158
162
|
@source inline("full");
|
|
159
163
|
@source inline("fumadocs-core/framework");
|
|
160
164
|
@source inline("fumadocs-core/i18n");
|
|
@@ -176,6 +180,7 @@
|
|
|
176
180
|
@source inline("ghost");
|
|
177
181
|
@source inline("githubUrl");
|
|
178
182
|
@source inline("given");
|
|
183
|
+
@source inline("global");
|
|
179
184
|
@source inline("green");
|
|
180
185
|
@source inline("grid");
|
|
181
186
|
@source inline("grid-cols-1");
|
|
@@ -211,6 +216,7 @@
|
|
|
211
216
|
@source inline("including");
|
|
212
217
|
@source inline("incorrect");
|
|
213
218
|
@source inline("indexPath");
|
|
219
|
+
@source inline("indicates");
|
|
214
220
|
@source inline("inherit");
|
|
215
221
|
@source inline("inheritLayoutProps");
|
|
216
222
|
@source inline("inherited");
|
|
@@ -247,6 +253,7 @@
|
|
|
247
253
|
@source inline("level");
|
|
248
254
|
@source inline("like");
|
|
249
255
|
@source inline("limitation");
|
|
256
|
+
@source inline("link");
|
|
250
257
|
@source inline("loading");
|
|
251
258
|
@source inline("locale");
|
|
252
259
|
@source inline("lucide-react");
|
|
@@ -277,6 +284,8 @@
|
|
|
277
284
|
@source inline("multiple");
|
|
278
285
|
@source inline("mx-auto");
|
|
279
286
|
@source inline("name");
|
|
287
|
+
@source inline("navigation");
|
|
288
|
+
@source inline("never");
|
|
280
289
|
@source inline("new");
|
|
281
290
|
@source inline("normal");
|
|
282
291
|
@source inline("not");
|
|
@@ -309,6 +318,7 @@
|
|
|
309
318
|
@source inline("params");
|
|
310
319
|
@source inline("parsed");
|
|
311
320
|
@source inline("path");
|
|
321
|
+
@source inline("path/hash");
|
|
312
322
|
@source inline("pathname");
|
|
313
323
|
@source inline("payload");
|
|
314
324
|
@source inline("pb-6");
|
|
@@ -345,6 +355,7 @@
|
|
|
345
355
|
@source inline("py-6");
|
|
346
356
|
@source inline("quality");
|
|
347
357
|
@source inline("query");
|
|
358
|
+
@source inline("query-only");
|
|
348
359
|
@source inline("r");
|
|
349
360
|
@source inline("react");
|
|
350
361
|
@source inline("react-dom");
|
|
@@ -382,6 +393,7 @@
|
|
|
382
393
|
@source inline("schema");
|
|
383
394
|
@source inline("schemaId");
|
|
384
395
|
@source inline("screens");
|
|
396
|
+
@source inline("scroll");
|
|
385
397
|
@source inline("search");
|
|
386
398
|
@source inline("see");
|
|
387
399
|
@source inline("sell");
|
|
@@ -391,6 +403,7 @@
|
|
|
391
403
|
@source inline("shadow-md");
|
|
392
404
|
@source inline("shadow-sm");
|
|
393
405
|
@source inline("shall");
|
|
406
|
+
@source inline("should");
|
|
394
407
|
@source inline("shrink-0");
|
|
395
408
|
@source inline("significantly");
|
|
396
409
|
@source inline("size-3.5");
|
package/dist/client.d.ts
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
|
+
import { Link, LinkProps } from "./components/link.js";
|
|
1
2
|
import { Unstable_ChangeRouteCallback, Unstable_ChangeRouteEvent } from "waku/router/client";
|
|
2
|
-
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
|
-
import { ComponentProps, ReactNode, TransitionFunction } from "react";
|
|
4
3
|
|
|
5
4
|
//#region src/client.d.ts
|
|
6
|
-
interface LinkProps extends ComponentProps<"a"> {
|
|
7
|
-
/**
|
|
8
|
-
* indicates if the link should scroll or not on navigation
|
|
9
|
-
* - `true`: always scroll
|
|
10
|
-
* - `false`: never scroll
|
|
11
|
-
* - `undefined`: scroll on path/hash change (not on query-only change)
|
|
12
|
-
*/
|
|
13
|
-
scroll?: boolean;
|
|
14
|
-
unstable_pending?: ReactNode;
|
|
15
|
-
unstable_notPending?: ReactNode;
|
|
16
|
-
unstable_prefetchOnEnter?: boolean;
|
|
17
|
-
unstable_prefetchOnView?: boolean;
|
|
18
|
-
unstable_startTransition?: ((fn: TransitionFunction) => void) | undefined;
|
|
19
|
-
}
|
|
20
5
|
interface Router {
|
|
21
6
|
push: (to: string, options?: {
|
|
22
7
|
/**
|
|
@@ -45,11 +30,6 @@ interface Router {
|
|
|
45
30
|
query: string;
|
|
46
31
|
hash: string;
|
|
47
32
|
}
|
|
48
|
-
declare function Link({
|
|
49
|
-
href,
|
|
50
|
-
children,
|
|
51
|
-
...props
|
|
52
|
-
}: LinkProps): _$react_jsx_runtime0.JSX.Element;
|
|
53
33
|
declare function useRouter(): Router;
|
|
54
34
|
//#endregion
|
|
55
|
-
export { Link, LinkProps, Router, useRouter };
|
|
35
|
+
export { Link, type LinkProps, Router, useRouter };
|
package/dist/client.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Link
|
|
3
|
-
import {
|
|
2
|
+
import { Link } from "./components/link.js";
|
|
3
|
+
import { useRouter as useRouter$1 } from "waku/router/client";
|
|
4
4
|
//#region src/client.tsx
|
|
5
|
-
|
|
6
|
-
return /* @__PURE__ */ jsx(Link$1, {
|
|
7
|
-
to: href,
|
|
8
|
-
...props,
|
|
9
|
-
children
|
|
10
|
-
});
|
|
11
|
-
}
|
|
5
|
+
/** tiny wrapper of `waku` */
|
|
12
6
|
function useRouter() {
|
|
13
7
|
return useRouter$1();
|
|
14
8
|
}
|
package/dist/components/blog.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { Link } from "./link.js";
|
|
1
2
|
import { getCreationDate, getPressContext } from "../lib/shared.js";
|
|
2
3
|
import { cn } from "../lib/cn.js";
|
|
3
4
|
import { I18nLabel } from "./i18n.js";
|
|
4
5
|
import { joinPathname } from "../lib/pathname.js";
|
|
5
6
|
import { getBlogContext } from "../plugins/blog.js";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Link } from "waku";
|
|
8
8
|
import { CornerLeftUpIcon } from "lucide-react";
|
|
9
9
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
10
10
|
//#region src/components/blog.tsx
|
|
11
11
|
function BlogItem({ page, date }) {
|
|
12
12
|
return /* @__PURE__ */ jsxs(Link, {
|
|
13
|
-
|
|
13
|
+
href: page.url,
|
|
14
14
|
className: "flex flex-col bg-fd-card rounded-2xl border shadow-sm p-4 transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground",
|
|
15
15
|
children: [
|
|
16
16
|
/* @__PURE__ */ jsx("p", {
|
|
@@ -52,7 +52,7 @@ function LinkToHome({ lang }) {
|
|
|
52
52
|
const { indexPath } = getBlogContext();
|
|
53
53
|
if (!indexPath) return;
|
|
54
54
|
return /* @__PURE__ */ jsxs(Link, {
|
|
55
|
-
|
|
55
|
+
href: lang ? joinPathname(lang, indexPath) : indexPath,
|
|
56
56
|
className: cn(buttonVariants({
|
|
57
57
|
variant: "ghost",
|
|
58
58
|
className: "text-fd-muted-foreground gap-2"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import { ComponentProps, ReactNode, TransitionFunction } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/link.d.ts
|
|
5
|
+
interface LinkProps extends ComponentProps<"a"> {
|
|
6
|
+
/**
|
|
7
|
+
* indicates if the link should scroll or not on navigation
|
|
8
|
+
* - `true`: always scroll
|
|
9
|
+
* - `false`: never scroll
|
|
10
|
+
* - `undefined`: scroll on path/hash change (not on query-only change)
|
|
11
|
+
*/
|
|
12
|
+
scroll?: boolean;
|
|
13
|
+
unstable_pending?: ReactNode;
|
|
14
|
+
unstable_notPending?: ReactNode;
|
|
15
|
+
unstable_prefetchOnEnter?: boolean;
|
|
16
|
+
unstable_prefetchOnView?: boolean;
|
|
17
|
+
unstable_startTransition?: ((fn: TransitionFunction) => void) | undefined;
|
|
18
|
+
}
|
|
19
|
+
declare function Link({
|
|
20
|
+
href,
|
|
21
|
+
children,
|
|
22
|
+
...props
|
|
23
|
+
}: LinkProps): _$react_jsx_runtime0.JSX.Element;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { Link, LinkProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRouter as useRouter$1 } from "../client.js";
|
|
3
|
+
import { Link } from "waku/router/client";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/link.tsx
|
|
6
|
+
function Link$1({ href = "#", children, ...props }) {
|
|
7
|
+
if (typeof global !== "undefined" && global.LINK_SSG_CONTEXT) global.LINK_SSG_CONTEXT.links.push({
|
|
8
|
+
href,
|
|
9
|
+
fromPathname: useRouter$1().path
|
|
10
|
+
});
|
|
11
|
+
return /* @__PURE__ */ jsx(Link, {
|
|
12
|
+
to: href,
|
|
13
|
+
...props,
|
|
14
|
+
children
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { Link$1 as Link };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Link } from "../components/link.js";
|
|
1
2
|
import { getPressContext } from "../lib/shared.js";
|
|
2
3
|
import { cn } from "../lib/cn.js";
|
|
3
4
|
import { I18nLabel } from "../components/i18n.js";
|
|
@@ -5,7 +6,6 @@ import { joinPathname } from "../lib/pathname.js";
|
|
|
5
6
|
import { getBlogContext } from "../plugins/blog.js";
|
|
6
7
|
import { OrderedBlogGrid } from "../components/blog.js";
|
|
7
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { Link } from "waku";
|
|
9
9
|
import { ListIcon } from "lucide-react";
|
|
10
10
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
11
11
|
//#region src/layouts/blog.index.tsx
|
|
@@ -26,7 +26,7 @@ function createBlogIndexPage({ heading, description } = {}) {
|
|
|
26
26
|
children: description
|
|
27
27
|
}),
|
|
28
28
|
tagsPath !== false && /* @__PURE__ */ jsxs(Link, {
|
|
29
|
-
|
|
29
|
+
href: lang ? joinPathname(lang, tagsPath) : tagsPath,
|
|
30
30
|
className: cn(buttonVariants({ variant: "primary" }), "gap-2"),
|
|
31
31
|
children: [/* @__PURE__ */ jsx(ListIcon, { className: "size-4" }), /* @__PURE__ */ jsx(I18nLabel, { label: "allTags" })]
|
|
32
32
|
})
|
package/dist/layouts/blog.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Link } from "../components/link.js";
|
|
1
2
|
import { getCreationDate, getPressContext, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
|
|
2
3
|
import { BlogPanel, BlogProvider } from "../components/blog-panel.js";
|
|
3
4
|
import { getTags } from "../lib/shared/blog.js";
|
|
@@ -6,7 +7,6 @@ import { createHomeLayout } from "./home.js";
|
|
|
6
7
|
import { getBlogContext } from "../plugins/blog.js";
|
|
7
8
|
import { LinkToHome } from "../components/blog.js";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { Link } from "waku";
|
|
10
10
|
import { TagIcon } from "lucide-react";
|
|
11
11
|
//#region src/layouts/blog.tsx
|
|
12
12
|
/** You can use `createHomeLayout()` directly, this is only a wrapper */
|
|
@@ -48,7 +48,7 @@ function createBlogLayoutPage(options = {}) {
|
|
|
48
48
|
className: "flex flex-row items-center gap-2 flex-wrap w-full max-w-[900px] text-sm text-fd-primary-foreground font-mono",
|
|
49
49
|
children: [/* @__PURE__ */ jsx(TagIcon, { className: "size-4 text-fd-muted-foreground" }), tags.map((t) => {
|
|
50
50
|
if (tagsPath !== false) return /* @__PURE__ */ jsx(Link, {
|
|
51
|
-
|
|
51
|
+
href: joinPathname(lang ?? "", tagsPath, t),
|
|
52
52
|
className: "px-1.5 py-0.5 rounded-lg bg-fd-primary",
|
|
53
53
|
children: t
|
|
54
54
|
}, t);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { Link } from "../components/link.js";
|
|
1
2
|
import { getPressContext } from "../lib/shared.js";
|
|
2
3
|
import { I18nLabel } from "../components/i18n.js";
|
|
3
4
|
import { getTags, groupTags } from "../lib/shared/blog.js";
|
|
4
5
|
import { getBlogContext } from "../plugins/blog.js";
|
|
5
6
|
import { LinkToHome, OrderedBlogGrid } from "../components/blog.js";
|
|
6
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { Link } from "waku";
|
|
8
8
|
import { NewspaperIcon, TagIcon } from "lucide-react";
|
|
9
9
|
//#region src/layouts/blog.tags.tsx
|
|
10
10
|
function createBlogTagsPage({ heading, description } = {}) {
|
|
@@ -34,7 +34,7 @@ function createBlogTagsPage({ heading, description } = {}) {
|
|
|
34
34
|
}), /* @__PURE__ */ jsx("div", {
|
|
35
35
|
className: "grid grid-cols-2 sm:grid-cols-3 gap-2 mt-4 md:grid-cols-4 xl:grid-cols-6",
|
|
36
36
|
children: Array.from(grouped.entries()).sort((a, b) => b[1] - a[1]).map(([tag, count]) => /* @__PURE__ */ jsxs(Link, {
|
|
37
|
-
|
|
37
|
+
href: `/blog/tags/${tag}`,
|
|
38
38
|
className: "flex flex-row items-center gap-2 bg-fd-card text-fd-card-foreground border font-mono rounded-lg px-2 py-1 transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground",
|
|
39
39
|
children: [
|
|
40
40
|
/* @__PURE__ */ jsx(TagIcon, { className: "size-3.5 text-fd-muted-foreground" }),
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { RootLayoutContextData } from "../layouts/root.js";
|
|
|
7
7
|
import { ReactNode } from "react";
|
|
8
8
|
import { ContentStorage, LoaderOptions, LoaderPluginOption, Page } from "fumadocs-core/source";
|
|
9
9
|
import { I18nConfig } from "fumadocs-core/i18n";
|
|
10
|
-
import { CreateApi, CreateLayout, CreatePage, CreateRoot, CreateSlice } from "waku/router/server";
|
|
10
|
+
import { CreateApi, CreateLayout, CreatePage, CreateRoot, CreateSlice, createPages } from "waku/router/server";
|
|
11
11
|
import { TOCItemType } from "fumadocs-core/toc";
|
|
12
12
|
import { StructuredData } from "fumadocs-core/mdx-plugins";
|
|
13
13
|
import { MiddlewareHandler } from "hono";
|
|
@@ -56,7 +56,7 @@ interface ServerPlugin<C extends ConfigContext = ConfigContext> {
|
|
|
56
56
|
/** resolve content loader options */
|
|
57
57
|
configureLoader?: (this: AppContext<C>, options: PressLoaderOptions) => Awaitable<PressLoaderOptions>;
|
|
58
58
|
/** create Hono middlewares */
|
|
59
|
-
createMiddlewares?: (this: AppContext<C>) => MiddlewareHandler[] | undefined
|
|
59
|
+
createMiddlewares?: (this: AppContext<C>) => Awaitable<MiddlewareHandler[] | undefined>;
|
|
60
60
|
unstable_onSSGRequest?: <T>(req: Request, next: () => T) => T;
|
|
61
61
|
unstable_onServerEntry?: (entry: ReturnType<ReturnType<typeof unstable_createServerEntryAdapter>>) => ReturnType<ReturnType<typeof unstable_createServerEntryAdapter>>;
|
|
62
62
|
}
|
|
@@ -67,6 +67,7 @@ interface BaseRouteFns {
|
|
|
67
67
|
createApi: CreateApi;
|
|
68
68
|
createSlice: CreateSlice;
|
|
69
69
|
}
|
|
70
|
+
type CreatePagesResult = ReturnType<typeof createPages>;
|
|
70
71
|
interface RouteFns extends BaseRouteFns {
|
|
71
72
|
createApiIsomorphic: (config: {
|
|
72
73
|
render: "static" | "dynamic";
|
|
@@ -76,6 +77,8 @@ interface RouteFns extends BaseRouteFns {
|
|
|
76
77
|
params: Record<string, string | string[]>;
|
|
77
78
|
}) => Promise<Response>;
|
|
78
79
|
}) => void;
|
|
80
|
+
/** access `createPages()` output */
|
|
81
|
+
unstable_getCreated: () => CreatePagesResult;
|
|
79
82
|
}
|
|
80
83
|
type ServerPluginOption<C extends ConfigContext = ConfigContext> = ServerPlugin<C> | false | undefined | null | ServerPluginOption<C>[];
|
|
81
84
|
/** can be extended from other libraries */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ConfigContext } from "../config.js";
|
|
2
|
+
import { Awaitable, ServerPlugin } from "../lib/types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/plugins/link-validation.d.ts
|
|
5
|
+
interface LinkSSGContext {
|
|
6
|
+
links: {
|
|
7
|
+
href: string;
|
|
8
|
+
fromPathname: string;
|
|
9
|
+
}[];
|
|
10
|
+
}
|
|
11
|
+
type ValidateResult = "not-found" | null;
|
|
12
|
+
declare global {
|
|
13
|
+
/** server always share the same `global` during build, we can use it to collect pre-rendered links */
|
|
14
|
+
var LINK_SSG_CONTEXT: LinkSSGContext | undefined;
|
|
15
|
+
}
|
|
16
|
+
interface LinkValidationOptions {
|
|
17
|
+
/** whether the link is skipped for validation */
|
|
18
|
+
ignored?: (href: string) => boolean;
|
|
19
|
+
/** when external link is discovered */
|
|
20
|
+
externalLink?: (href: string) => Awaitable<ValidateResult>;
|
|
21
|
+
}
|
|
22
|
+
declare function linkValidationPlugin<C extends ConfigContext>(options?: LinkValidationOptions): ServerPlugin<C>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { LinkValidationOptions, linkValidationPlugin };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/plugins/link-validation.tsx
|
|
2
|
+
function linkValidationPlugin(options = {}) {
|
|
3
|
+
const { ignored, externalLink } = options;
|
|
4
|
+
return { unstable_onServerEntry(entry) {
|
|
5
|
+
const build = entry.build;
|
|
6
|
+
entry.build = async (...args) => {
|
|
7
|
+
const context = global.LINK_SSG_CONTEXT = { links: [] };
|
|
8
|
+
const res = await build(...args);
|
|
9
|
+
const hrefMap = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const link of context.links) hrefMap.set(link.href, null);
|
|
11
|
+
await Promise.all(Array.from(hrefMap.keys()).map(async (href) => {
|
|
12
|
+
if (href.startsWith("mailto:") || href.startsWith("#")) return;
|
|
13
|
+
if (ignored && ignored(href)) return;
|
|
14
|
+
if (URL.canParse(href)) {
|
|
15
|
+
if (externalLink) hrefMap.set(href, await externalLink(href));
|
|
16
|
+
} else if ((await entry.fetch(new Request(new URL(href, "http://localhost")))).status === 404) hrefMap.set(href, "not-found");
|
|
17
|
+
}));
|
|
18
|
+
const errors = [];
|
|
19
|
+
for (const link of context.links) {
|
|
20
|
+
const info = hrefMap.get(link.href);
|
|
21
|
+
if (info) errors.push(`In "${link.fromPathname}": link "${link.href}" ${info}`);
|
|
22
|
+
}
|
|
23
|
+
if (errors.length > 0) throw new Error("\n" + errors.join("\n"));
|
|
24
|
+
return res;
|
|
25
|
+
};
|
|
26
|
+
return entry;
|
|
27
|
+
} };
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { linkValidationPlugin };
|
package/dist/plugins/llms.txt.js
CHANGED
|
@@ -92,7 +92,7 @@ function llmsPlugin(options = {}) {
|
|
|
92
92
|
createApiIsomorphic({
|
|
93
93
|
render: renderMode,
|
|
94
94
|
path: joinPathname(this.i18nConfig ? "[lang]" : "", basePath, "[...slugs]"),
|
|
95
|
-
staticPaths:
|
|
95
|
+
staticPaths: (await this.getLoader()).getPages().map((page) => slugsToMarkdownPath(page.slugs, page.locale).staticPath),
|
|
96
96
|
handler: async (_req, { params }) => {
|
|
97
97
|
const page = (await this.getLoader()).getPage(markdownPathToSlugs(params.slugs), params.lang);
|
|
98
98
|
if (!page) unstable_notFound();
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { AppContext } from "../lib/shared.js";
|
|
2
|
+
import { ConfigContext } from "../config.js";
|
|
3
|
+
import { Awaitable, ServerPlugin } from "../lib/types.js";
|
|
4
|
+
|
|
5
|
+
//#region src/plugins/sitemap.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* How frequently a page is likely to change.
|
|
8
|
+
*
|
|
9
|
+
* @see https://www.sitemaps.org/protocol.html#changefreqdef
|
|
10
|
+
*/
|
|
11
|
+
type SitemapChangeFrequency = "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
|
|
12
|
+
/**
|
|
13
|
+
* Last modification timestamp in W3C Datetime format (ISO 8601 subset).
|
|
14
|
+
*
|
|
15
|
+
* @see https://www.sitemaps.org/protocol.html#xmlDefinition
|
|
16
|
+
*/
|
|
17
|
+
type SitemapLastMod = Date | string;
|
|
18
|
+
/**
|
|
19
|
+
* Priority of a URL relative to other URLs on the site.
|
|
20
|
+
*
|
|
21
|
+
* Valid values are decimals between `0.0` and `1.0` inclusive.
|
|
22
|
+
*
|
|
23
|
+
* @see https://www.sitemaps.org/protocol.html#prioritydef
|
|
24
|
+
*/
|
|
25
|
+
type SitemapPriority = number;
|
|
26
|
+
/**
|
|
27
|
+
* `rel` attribute for sitemap link elements. The protocol only defines `alternate` for hreflang.
|
|
28
|
+
*
|
|
29
|
+
* @see https://www.sitemaps.org/protocol.html#xmlDefinition
|
|
30
|
+
*/
|
|
31
|
+
type SitemapLinkRel = "alternate";
|
|
32
|
+
/**
|
|
33
|
+
* An `xhtml:link` alternate language reference on a URL entry.
|
|
34
|
+
*
|
|
35
|
+
* @see https://www.sitemaps.org/protocol.html#xmlDefinition
|
|
36
|
+
*/
|
|
37
|
+
interface SitemapAlternateLink {
|
|
38
|
+
rel: SitemapLinkRel;
|
|
39
|
+
/** BCP 47 language tag (e.g. `en`, `de`, `x-default`). */
|
|
40
|
+
hreflang: string;
|
|
41
|
+
/** Fully-qualified URL of the alternate page. */
|
|
42
|
+
href: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* An `image:image` entry (Google image sitemap extension).
|
|
46
|
+
*
|
|
47
|
+
* @see https://developers.google.com/search/docs/crawling-indexing/sitemaps/image-sitemaps
|
|
48
|
+
*/
|
|
49
|
+
interface SitemapImage {
|
|
50
|
+
/** URL of the image. */
|
|
51
|
+
loc: string;
|
|
52
|
+
caption?: string;
|
|
53
|
+
geo_location?: string;
|
|
54
|
+
title?: string;
|
|
55
|
+
license?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Publication metadata for a `news:news` entry (Google News sitemap extension).
|
|
59
|
+
*
|
|
60
|
+
* @see https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap
|
|
61
|
+
*/
|
|
62
|
+
interface SitemapNewsPublication {
|
|
63
|
+
/** Publication name; must match Google News exactly if submitted there. */
|
|
64
|
+
name: string;
|
|
65
|
+
/** Primary language of the publication in ISO 639 format (two or three letter code). */
|
|
66
|
+
language: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A `news:news` entry (Google News sitemap extension).
|
|
70
|
+
*
|
|
71
|
+
* @see https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap
|
|
72
|
+
*/
|
|
73
|
+
interface SitemapNews {
|
|
74
|
+
publication: SitemapNewsPublication;
|
|
75
|
+
/** Publication date in W3C Datetime format. */
|
|
76
|
+
publication_date: SitemapLastMod;
|
|
77
|
+
/** Title of the news article. */
|
|
78
|
+
title: string;
|
|
79
|
+
/** Comma-separated stock tickers (optional). */
|
|
80
|
+
stock_tickers?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A `video:video` entry (Google video sitemap extension).
|
|
84
|
+
*
|
|
85
|
+
* Only common fields are listed; see Google's schema for the full set.
|
|
86
|
+
*
|
|
87
|
+
* @see https://developers.google.com/search/docs/crawling-indexing/sitemaps/video-sitemaps
|
|
88
|
+
*/
|
|
89
|
+
interface SitemapVideo {
|
|
90
|
+
/** URL of the player page or direct link to the video. */
|
|
91
|
+
content_loc?: string;
|
|
92
|
+
/** URL of the player page for this video. */
|
|
93
|
+
player_loc?: string;
|
|
94
|
+
/** Whether the video may be embedded. */
|
|
95
|
+
"player_loc@allow_embed"?: boolean;
|
|
96
|
+
/** Whether to show a paywall to users from the given countries. */
|
|
97
|
+
"player_loc@restrict"?: string;
|
|
98
|
+
/** A URL pointing to the video thumbnail image. */
|
|
99
|
+
thumbnail_loc: string;
|
|
100
|
+
title: string;
|
|
101
|
+
description: string;
|
|
102
|
+
/** Duration in seconds (max 28800). */
|
|
103
|
+
duration?: number;
|
|
104
|
+
/** Expiration date in W3C Datetime format; omit if the video does not expire. */
|
|
105
|
+
expiration_date?: SitemapLastMod;
|
|
106
|
+
/** Rating value. 0.0–5.0 or unrated if omitted. */
|
|
107
|
+
rating?: number;
|
|
108
|
+
/** Number of times the video has been viewed. */
|
|
109
|
+
view_count?: number;
|
|
110
|
+
/** Publication date in W3C Datetime format. */
|
|
111
|
+
publication_date?: SitemapLastMod;
|
|
112
|
+
/** Whether the video is family friendly. */
|
|
113
|
+
family_friendly?: "yes" | "no";
|
|
114
|
+
/** Comma-separated list of tags. */
|
|
115
|
+
tag?: string | string[];
|
|
116
|
+
/** Comma-separated domains the video may not be played on. */
|
|
117
|
+
restriction?: string;
|
|
118
|
+
/** Whether search engines may download the video file. */
|
|
119
|
+
"restriction@relationship"?: "allow" | "deny";
|
|
120
|
+
gallery_loc?: string;
|
|
121
|
+
/** Price currency in ISO 4217 format. */
|
|
122
|
+
price?: string;
|
|
123
|
+
"price@currency"?: string;
|
|
124
|
+
"price@type"?: "rent" | "purchase" | "own" | "subscription";
|
|
125
|
+
/** Platform restriction (e.g. `web`, `mobile`, `tv`). */
|
|
126
|
+
platform?: string;
|
|
127
|
+
"platform@relationship"?: "allow" | "deny";
|
|
128
|
+
/** Whether a subscription is required. */
|
|
129
|
+
requires_subscription?: "yes" | "no";
|
|
130
|
+
uploader?: string;
|
|
131
|
+
"uploader@info"?: string;
|
|
132
|
+
live?: "yes" | "no";
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A single `<url>` entry in a sitemap.
|
|
136
|
+
*
|
|
137
|
+
* @see https://www.sitemaps.org/protocol.html#xmlDefinition
|
|
138
|
+
*/
|
|
139
|
+
interface SitemapUrl {
|
|
140
|
+
/**
|
|
141
|
+
* Fully-qualified URL of the page.
|
|
142
|
+
*
|
|
143
|
+
* Must be less than 2,048 characters and include protocol + host per the spec.
|
|
144
|
+
*/
|
|
145
|
+
loc: string;
|
|
146
|
+
/**
|
|
147
|
+
* Last modification date of the file.
|
|
148
|
+
*
|
|
149
|
+
* Search engines may use the full W3C Datetime or the date portion only.
|
|
150
|
+
*/
|
|
151
|
+
lastmod?: SitemapLastMod;
|
|
152
|
+
/**
|
|
153
|
+
* Hint for how often the page changes.
|
|
154
|
+
*
|
|
155
|
+
* Note: The value is a hint, not a command.
|
|
156
|
+
*/
|
|
157
|
+
changefreq?: SitemapChangeFrequency;
|
|
158
|
+
/**
|
|
159
|
+
* Priority relative to other URLs on your site (`0.0`–`1.0`).
|
|
160
|
+
*
|
|
161
|
+
* Default priority of pages is `0.5`; this does not affect comparison across different sites.
|
|
162
|
+
*/
|
|
163
|
+
priority?: SitemapPriority;
|
|
164
|
+
/**
|
|
165
|
+
* Alternate language or regional URLs (`xhtml:link`).
|
|
166
|
+
*
|
|
167
|
+
* Requires the `xhtml` namespace on the root `urlset` when serialized.
|
|
168
|
+
*/
|
|
169
|
+
alternates?: readonly SitemapAlternateLink[];
|
|
170
|
+
/** Image URLs associated with this page (Google image extension). */
|
|
171
|
+
images?: readonly SitemapImage[];
|
|
172
|
+
/** Video metadata associated with this page (Google video extension). */
|
|
173
|
+
videos?: readonly SitemapVideo[];
|
|
174
|
+
/** News article metadata (Google News extension). */
|
|
175
|
+
news?: readonly SitemapNews[];
|
|
176
|
+
}
|
|
177
|
+
interface SitemapOptions<C extends ConfigContext = ConfigContext> {
|
|
178
|
+
/**
|
|
179
|
+
* Path for the sitemap route.
|
|
180
|
+
*
|
|
181
|
+
* @default "/sitemap.xml"
|
|
182
|
+
*/
|
|
183
|
+
path?: string;
|
|
184
|
+
/**
|
|
185
|
+
* Customize or exclude sitemap entries.
|
|
186
|
+
* Return `undefined` to exclude a page.
|
|
187
|
+
*/
|
|
188
|
+
getEntry?: (this: AppContext<C>, page: C["page"]) => Awaitable<SitemapUrl | undefined>;
|
|
189
|
+
/**
|
|
190
|
+
* Additional entries to include in the sitemap, be careful the `loc` field must be a fully-qualified URL.
|
|
191
|
+
*/
|
|
192
|
+
additionalEntries?: SitemapUrl[] | ((this: AppContext<C>) => Awaitable<SitemapUrl[]>);
|
|
193
|
+
}
|
|
194
|
+
declare function sitemapPlugin<C extends ConfigContext = ConfigContext>(options?: SitemapOptions<NoInfer<C>>): ServerPlugin<C>;
|
|
195
|
+
//#endregion
|
|
196
|
+
export { SitemapAlternateLink, SitemapChangeFrequency, SitemapImage, SitemapLastMod, SitemapLinkRel, SitemapNews, SitemapNewsPublication, SitemapOptions, SitemapPriority, SitemapUrl, SitemapVideo, sitemapPlugin };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { getLastModifiedDate } from "../lib/shared.js";
|
|
2
|
+
import { js2xml } from "xml-js";
|
|
3
|
+
//#region src/plugins/sitemap.ts
|
|
4
|
+
function formatLastmod(value) {
|
|
5
|
+
return (value instanceof Date ? value : new Date(value)).toISOString();
|
|
6
|
+
}
|
|
7
|
+
function imageToElement(image) {
|
|
8
|
+
const element = { "image:loc": { _text: image.loc } };
|
|
9
|
+
if (image.caption) element["image:caption"] = { _text: image.caption };
|
|
10
|
+
if (image.geo_location) element["image:geo_location"] = { _text: image.geo_location };
|
|
11
|
+
if (image.title) element["image:title"] = { _text: image.title };
|
|
12
|
+
if (image.license) element["image:license"] = { _text: image.license };
|
|
13
|
+
return element;
|
|
14
|
+
}
|
|
15
|
+
function entryToUrlElement(entry) {
|
|
16
|
+
const url = { loc: { _text: entry.loc } };
|
|
17
|
+
if (entry.lastmod) url.lastmod = { _text: formatLastmod(entry.lastmod) };
|
|
18
|
+
if (entry.changefreq) url.changefreq = { _text: entry.changefreq };
|
|
19
|
+
if (entry.priority !== void 0) url.priority = { _text: String(entry.priority) };
|
|
20
|
+
if (entry.alternates?.length) url["xhtml:link"] = entry.alternates.map((alternate) => ({ _attributes: {
|
|
21
|
+
rel: alternate.rel,
|
|
22
|
+
hreflang: alternate.hreflang,
|
|
23
|
+
href: alternate.href
|
|
24
|
+
} }));
|
|
25
|
+
if (entry.images?.length) url["image:image"] = entry.images.map(imageToElement);
|
|
26
|
+
return url;
|
|
27
|
+
}
|
|
28
|
+
function buildSitemap(entries) {
|
|
29
|
+
return js2xml({
|
|
30
|
+
_declaration: { _attributes: {
|
|
31
|
+
version: "1.0",
|
|
32
|
+
encoding: "UTF-8"
|
|
33
|
+
} },
|
|
34
|
+
urlset: {
|
|
35
|
+
_attributes: {
|
|
36
|
+
xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9",
|
|
37
|
+
"xmlns:xhtml": "http://www.w3.org/1999/xhtml",
|
|
38
|
+
"xmlns:image": "http://www.google.com/schemas/sitemap-image/1.1"
|
|
39
|
+
},
|
|
40
|
+
url: entries.map(entryToUrlElement)
|
|
41
|
+
}
|
|
42
|
+
}, {
|
|
43
|
+
compact: true,
|
|
44
|
+
spaces: 0
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function sitemapPlugin(options = {}) {
|
|
48
|
+
const { path = "/sitemap.xml", getEntry: _getEntry = async function getEntryDefault(page) {
|
|
49
|
+
return {
|
|
50
|
+
loc: new URL(page.url, this.siteConfig.baseUrl).href,
|
|
51
|
+
lastmod: await getLastModifiedDate(this, page),
|
|
52
|
+
priority: .8
|
|
53
|
+
};
|
|
54
|
+
}, additionalEntries } = options;
|
|
55
|
+
return {
|
|
56
|
+
name: "core:sitemap",
|
|
57
|
+
async createPages({ createApiIsomorphic, unstable_getCreated }) {
|
|
58
|
+
const renderMode = this.mode === "default" ? "static" : this.mode;
|
|
59
|
+
const getEntry = _getEntry.bind(this);
|
|
60
|
+
createApiIsomorphic({
|
|
61
|
+
render: renderMode,
|
|
62
|
+
path,
|
|
63
|
+
handler: async () => {
|
|
64
|
+
const source = await this.getLoader();
|
|
65
|
+
const entries = [];
|
|
66
|
+
const pageLocs = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const entry of await Promise.all(source.getPages().map(getEntry))) {
|
|
68
|
+
if (!entry) continue;
|
|
69
|
+
pageLocs.add(entry.loc);
|
|
70
|
+
entries.push(entry);
|
|
71
|
+
}
|
|
72
|
+
for (const route of await unstable_getCreated().unstable_getRouterConfigs()) if (route.isStatic && route.type === "route") {
|
|
73
|
+
const segments = route.path.map((v) => v.name);
|
|
74
|
+
if (segments.at(-1) === "404") continue;
|
|
75
|
+
const loc = new URL("/" + segments.join("/"), this.siteConfig.baseUrl).href;
|
|
76
|
+
if (pageLocs.has(loc)) continue;
|
|
77
|
+
entries.push({
|
|
78
|
+
loc,
|
|
79
|
+
priority: 1
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (additionalEntries) entries.push(...typeof additionalEntries === "function" ? await additionalEntries.call(this) : additionalEntries);
|
|
83
|
+
return new Response(buildSitemap(entries), { headers: { "Content-Type": "application/xml" } });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { sitemapPlugin };
|
package/dist/plugins/takumi.js
CHANGED
|
@@ -57,11 +57,10 @@ function takumiPlugin(options = {}) {
|
|
|
57
57
|
});
|
|
58
58
|
},
|
|
59
59
|
async createPages({ createApiIsomorphic }) {
|
|
60
|
-
const renderMode = this.mode === "default" ? "static" : this.mode;
|
|
61
60
|
createApiIsomorphic({
|
|
62
|
-
render:
|
|
61
|
+
render: this.mode === "default" ? "static" : this.mode,
|
|
63
62
|
path: joinPathname(this.i18nConfig ? "[lang]" : "", basePath, "[...slugs]"),
|
|
64
|
-
staticPaths:
|
|
63
|
+
staticPaths: (await this.getLoader()).getPages().map((page) => slugsToImagePath(page.slugs, page.locale).staticPath),
|
|
65
64
|
handler: async (_, { params }) => {
|
|
66
65
|
const page = (await this.getLoader()).getPage(imagePathToSlugs(params.slugs), params.lang);
|
|
67
66
|
if (!page) unstable_notFound();
|
package/dist/router/index.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ import { unstable_createServerEntryAdapter } from "waku/adapter-builders";
|
|
|
10
10
|
interface Router<C extends ConfigContext = ConfigContext> {
|
|
11
11
|
createPages: (fn?: (this: AppContext<C>, fns: RouteFns) => Awaitable<void>, options?: Options) => ReturnType<typeof createPages>;
|
|
12
12
|
createMiddlewares: () => (() => MiddlewareHandler)[];
|
|
13
|
-
patchAdapter: <Options>(adapter: ReturnType<typeof unstable_createServerEntryAdapter<Options>>) =>
|
|
13
|
+
patchAdapter: <Options>(adapter: ReturnType<typeof unstable_createServerEntryAdapter<Options>>) => ReturnType<typeof unstable_createServerEntryAdapter<Options>>;
|
|
14
14
|
}
|
|
15
|
-
declare function createRouter<C extends ConfigContext>(userConfig: ConfigBuilder<C>): Router<C
|
|
15
|
+
declare function createRouter<C extends ConfigContext>(userConfig: ConfigBuilder<C>): Promise<Router<C>>;
|
|
16
16
|
//#endregion
|
|
17
17
|
export { Router, createRouter, notFound, redirect };
|
package/dist/router/index.js
CHANGED
|
@@ -4,17 +4,16 @@ import { Fragment as Fragment$1 } from "react";
|
|
|
4
4
|
import { createPages } from "waku";
|
|
5
5
|
import { unstable_notFound, unstable_notFound as notFound, unstable_redirect as redirect } from "waku/router/server";
|
|
6
6
|
//#region src/router/index.tsx
|
|
7
|
-
function createRouter(userConfig) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
function createPages$1(base, createPagesOptions) {
|
|
13
|
-
return createPages(async (_fns) => {
|
|
14
|
-
const context = await getAppContext();
|
|
7
|
+
async function createRouter(userConfig) {
|
|
8
|
+
const context = await initApp(userConfig);
|
|
9
|
+
function createPages$2(base, createPagesOptions) {
|
|
10
|
+
const result = createPages(async (_fns) => {
|
|
15
11
|
const layouts = context.layouts;
|
|
16
12
|
const fns = {
|
|
17
13
|
..._fns,
|
|
14
|
+
unstable_getCreated() {
|
|
15
|
+
return result;
|
|
16
|
+
},
|
|
18
17
|
createApiIsomorphic(config) {
|
|
19
18
|
if (config.render === "static") _fns.createApi({
|
|
20
19
|
render: "static",
|
|
@@ -44,7 +43,7 @@ function createRouter(userConfig) {
|
|
|
44
43
|
for (const plugin of context.plugins) await plugin.createPages?.call(context, fns);
|
|
45
44
|
const staticPaths = [];
|
|
46
45
|
const defaultRenderMode = context.mode === "default" ? "static" : context.mode;
|
|
47
|
-
|
|
46
|
+
outer: for (const page of (await context.getLoader()).getPages()) {
|
|
48
47
|
for (const plugin of context.plugins) if (await plugin.resolvePage?.call(context, page) === false) continue outer;
|
|
49
48
|
staticPaths.push(page.locale ? [page.locale, ...page.slugs] : page.slugs);
|
|
50
49
|
}
|
|
@@ -131,18 +130,15 @@ function createRouter(userConfig) {
|
|
|
131
130
|
}
|
|
132
131
|
return null;
|
|
133
132
|
}, createPagesOptions);
|
|
133
|
+
return result;
|
|
134
134
|
}
|
|
135
135
|
function contextMiddleware() {
|
|
136
|
-
return
|
|
137
|
-
const ctx = await getAppContext();
|
|
138
|
-
return appContext.run(ctx, next);
|
|
139
|
-
};
|
|
136
|
+
return (_c, next) => appContext.run(context, next);
|
|
140
137
|
}
|
|
141
138
|
function pluginsMiddleware() {
|
|
142
139
|
async function init() {
|
|
143
|
-
const ctx = await getAppContext();
|
|
144
140
|
const out = [];
|
|
145
|
-
const resolved = await Promise.all(
|
|
141
|
+
const resolved = await Promise.all(context.plugins.map((plugin) => plugin.createMiddlewares?.call(context)));
|
|
146
142
|
for (const v of resolved) if (v) out.push(...v);
|
|
147
143
|
return out;
|
|
148
144
|
}
|
|
@@ -162,16 +158,15 @@ function createRouter(userConfig) {
|
|
|
162
158
|
return response;
|
|
163
159
|
};
|
|
164
160
|
}
|
|
165
|
-
|
|
166
|
-
const ctx = await getAppContext();
|
|
161
|
+
function patchAdapter(adapter) {
|
|
167
162
|
return (handlers, options) => {
|
|
168
163
|
let entry = adapter({
|
|
169
164
|
...handlers,
|
|
170
165
|
handleBuild(utils) {
|
|
171
166
|
const hooks = [];
|
|
172
167
|
hooks.push(utils.withRequest);
|
|
173
|
-
hooks.push((_req, fn) => appContext.run(
|
|
174
|
-
for (const plugin of
|
|
168
|
+
hooks.push((_req, fn) => appContext.run(context, fn));
|
|
169
|
+
for (const plugin of context.plugins) if (plugin.unstable_onSSGRequest) hooks.push(plugin.unstable_onSSGRequest);
|
|
175
170
|
function runHook(req, fn, index = 0) {
|
|
176
171
|
const hook = hooks[index];
|
|
177
172
|
if (!hook) return fn();
|
|
@@ -183,12 +178,12 @@ function createRouter(userConfig) {
|
|
|
183
178
|
});
|
|
184
179
|
}
|
|
185
180
|
}, options);
|
|
186
|
-
for (const plugin of
|
|
181
|
+
for (const plugin of context.plugins) if (plugin.unstable_onServerEntry) entry = plugin.unstable_onServerEntry(entry);
|
|
187
182
|
return entry;
|
|
188
183
|
};
|
|
189
184
|
}
|
|
190
185
|
return {
|
|
191
|
-
createPages: createPages$
|
|
186
|
+
createPages: createPages$2,
|
|
192
187
|
patchAdapter,
|
|
193
188
|
createMiddlewares() {
|
|
194
189
|
return [contextMiddleware, pluginsMiddleware];
|
package/dist/vite.js
CHANGED
|
@@ -60,10 +60,10 @@ const modules = import.meta.glob("./pages/**/*.{ts,tsx,js,jsx}", {
|
|
|
60
60
|
base: '/src',
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
const router = createRouter(pressConfig);
|
|
63
|
+
const router = await createRouter(pressConfig);
|
|
64
64
|
const pages = router.createPages(fsRouterFn(modules));
|
|
65
65
|
const middlewareFns = router.createMiddlewares();
|
|
66
|
-
const adapter =
|
|
66
|
+
const adapter = router.patchAdapter(_adapter);
|
|
67
67
|
|
|
68
68
|
export default adapter(pages, { middlewareFns });
|
|
69
69
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumapress",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "An opinionated docs framework powered by Fumadocs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Docs",
|
|
@@ -37,9 +37,11 @@
|
|
|
37
37
|
"./plugins/image/self-hosted": "./dist/plugins/image/self-hosted.js",
|
|
38
38
|
"./plugins/image/vercel": "./dist/plugins/image/vercel.js",
|
|
39
39
|
"./plugins/image/vercel.enhancer": "./dist/plugins/image/vercel.enhancer.js",
|
|
40
|
+
"./plugins/link-validation": "./dist/plugins/link-validation.js",
|
|
40
41
|
"./plugins/llms.txt": "./dist/plugins/llms.txt.js",
|
|
41
42
|
"./plugins/openapi": "./dist/plugins/openapi.js",
|
|
42
43
|
"./plugins/orama-search": "./dist/plugins/orama-search.js",
|
|
44
|
+
"./plugins/sitemap": "./dist/plugins/sitemap.js",
|
|
43
45
|
"./plugins/takumi": "./dist/plugins/takumi.js",
|
|
44
46
|
"./router": "./dist/router/index.js",
|
|
45
47
|
"./router/fs": "./dist/router/fs.js",
|
|
@@ -56,11 +58,10 @@
|
|
|
56
58
|
"@takumi-rs/image-response": "^1.6.0",
|
|
57
59
|
"class-variance-authority": "^0.7.1",
|
|
58
60
|
"flexsearch": "^0.8.212",
|
|
59
|
-
"fumadocs-core": "^16.9.3",
|
|
60
|
-
"fumadocs-ui": "^16.9.3",
|
|
61
61
|
"lucide-react": "^1.17.0",
|
|
62
62
|
"tailwind-merge": "^3.6.0",
|
|
63
63
|
"vite": "^8.0.14",
|
|
64
|
+
"xml-js": "^1.6.11",
|
|
64
65
|
"zod": "^4.4.3"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
@@ -71,8 +72,10 @@
|
|
|
71
72
|
"@types/node": "^25.9.1",
|
|
72
73
|
"@types/react": "^19.2.15",
|
|
73
74
|
"@types/react-dom": "^19.2.3",
|
|
75
|
+
"fumadocs-core": "^16.9.3",
|
|
74
76
|
"fumadocs-mdx": "^15.0.10",
|
|
75
77
|
"fumadocs-openapi": "^10.9.1",
|
|
78
|
+
"fumadocs-ui": "^16.9.3",
|
|
76
79
|
"hono": "^4.12.23",
|
|
77
80
|
"http-cache-semantics": "^4.2.0",
|
|
78
81
|
"react": "^19.2.6",
|
|
@@ -85,8 +88,10 @@
|
|
|
85
88
|
"peerDependencies": {
|
|
86
89
|
"@types/mdx": "*",
|
|
87
90
|
"@types/react": "*",
|
|
91
|
+
"fumadocs-core": "^16.9.3",
|
|
88
92
|
"fumadocs-mdx": "^15.0.0",
|
|
89
93
|
"fumadocs-openapi": "^10.8.0",
|
|
94
|
+
"fumadocs-ui": "^16.9.3",
|
|
90
95
|
"hono": "*",
|
|
91
96
|
"react": "^19.2.0",
|
|
92
97
|
"react-dom": "^19.2.0",
|