@docubook/flame 2.0.0-beta.5 → 2.0.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/.docu/components/Theme.tsx +42 -34
- package/.docu/components/home/BackgroundBlobs.tsx +31 -0
- package/.docu/components/home/index.tsx +1 -0
- package/.docu/lib/build.deno.js +1 -1
- package/.docu/lib/{build.impl-BBlR3si3.js → build.impl-CAQr352X.js} +60 -29
- package/.docu/lib/build.impl-CAQr352X.js.map +1 -0
- package/.docu/lib/build.impl-NLhjTqTa.js +2 -0
- package/.docu/lib/build.node.js +1 -1
- package/.docu/lib/clean.js +1 -1
- package/.docu/lib/deploy.deno.js +1 -1
- package/.docu/lib/deploy.node.js +1 -1
- package/.docu/lib/{deploy.shared-Dxv3lsOb.js → deploy.shared-CvgObu6_.js} +45 -17
- package/.docu/lib/deploy.shared-CvgObu6_.js.map +1 -0
- package/.docu/lib/{html.shared-DBMwv_Z6.js → html.shared-CsEFmy_Y.js} +181 -158
- package/.docu/lib/html.shared-CsEFmy_Y.js.map +1 -0
- package/.docu/lib/{logger-DYmvFF1d.js → logger-DwxYdOL7.js} +4 -3
- package/.docu/lib/logger-DwxYdOL7.js.map +1 -0
- package/.docu/lib/{paths-Bl2cdp9E.js → paths-Cbz-dj4s.js} +5 -9
- package/.docu/lib/{paths-Bl2cdp9E.js.map → paths-Cbz-dj4s.js.map} +1 -1
- package/.docu/lib/preview.deno.js +1 -1
- package/.docu/lib/{preview.impl-anVcZv2Z.js → preview.impl-BwrVLNIQ.js} +3 -3
- package/.docu/lib/{preview.impl-anVcZv2Z.js.map → preview.impl-BwrVLNIQ.js.map} +1 -1
- package/.docu/lib/preview.node.js +1 -1
- package/.docu/lib/server.deno.js +1 -1
- package/.docu/lib/{server.impl-Cvoa6Diq.js → server.impl-Cs6DEy4V.js} +43 -52
- package/.docu/lib/server.impl-Cs6DEy4V.js.map +1 -0
- package/.docu/lib/server.node.js +1 -1
- package/.docu/node/build.impl.ts +71 -34
- package/.docu/node/build.ts +68 -34
- package/.docu/node/cache-key.ts +8 -4
- package/.docu/node/client.ts +36 -27
- package/.docu/node/deploy.shared.ts +44 -18
- package/.docu/node/deploy.ts +5 -20
- package/.docu/node/home-client.ts +6 -0
- package/.docu/node/html.shared.ts +5 -4
- package/.docu/node/html.ts +4 -3
- package/.docu/node/hydrate.node.ts +87 -115
- package/.docu/node/hydrate.ts +74 -80
- package/.docu/node/mdx-manifest.d.ts +2 -2
- package/.docu/node/paths.ts +2 -9
- package/.docu/node/plugin-builder.ts +25 -13
- package/.docu/node/plugin.ts +33 -9
- package/.docu/node/server-routes.ts +59 -50
- package/.docu/node/server.impl.ts +4 -2
- package/.docu/node/server.ts +12 -16
- package/.docu/node/types.ts +11 -0
- package/.docu/pages/404.tsx +12 -9
- package/.docu/pages/index.tsx +8 -29
- package/.docu/styles/base.css +128 -0
- package/.docu/styles/globals.css +5 -137
- package/.docu/styles/site.css +7 -0
- package/package.json +6 -5
- package/.docu/lib/build.impl-BBlR3si3.js.map +0 -1
- package/.docu/lib/build.impl-DpoDUmei.js +0 -2
- package/.docu/lib/deploy.shared-Dxv3lsOb.js.map +0 -1
- package/.docu/lib/html.shared-DBMwv_Z6.js.map +0 -1
- package/.docu/lib/logger-DYmvFF1d.js.map +0 -1
- package/.docu/lib/server.impl-Cvoa6Diq.js.map +0 -1
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { Pluggable } from "unified";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
BuildEndContext,
|
|
4
|
+
DevServerContext,
|
|
5
|
+
DocuConfig,
|
|
6
|
+
PageContext,
|
|
7
|
+
PageMeta,
|
|
8
|
+
PluginBuilder,
|
|
9
|
+
} from "./plugin";
|
|
3
10
|
|
|
4
11
|
type Awaitable<T> = T | Promise<T>;
|
|
5
12
|
|
|
@@ -20,7 +27,9 @@ export class BuildPluginBuilder implements PluginBuilder {
|
|
|
20
27
|
> = [];
|
|
21
28
|
private _injectBody: Array<(context: PageContext) => string | string[]> = [];
|
|
22
29
|
private _injectHead: Array<(context: PageContext) => string | string[]> = [];
|
|
23
|
-
private _onEnd: Array<
|
|
30
|
+
private _onEnd: Array<
|
|
31
|
+
(config: DocuConfig, pages: PageMeta[], context: BuildEndContext) => Awaitable<void>
|
|
32
|
+
> = [];
|
|
24
33
|
private _onLoad: OnLoadHandler[] = [];
|
|
25
34
|
private _onStart: Array<(config: DocuConfig) => Awaitable<void>> = [];
|
|
26
35
|
private _rehypePlugins: Array<() => Pluggable[]> = [];
|
|
@@ -185,22 +194,24 @@ export class BuildPluginBuilder implements PluginBuilder {
|
|
|
185
194
|
|
|
186
195
|
/**
|
|
187
196
|
* Register a callback to run once after all pages are built.
|
|
188
|
-
* Receives the resolved config and
|
|
189
|
-
*
|
|
197
|
+
* Receives the resolved config, aggregated docs metadata, and final build metadata.
|
|
198
|
+
* Callback errors are logged by `runOnEnd()` and do not stop later callbacks.
|
|
190
199
|
*
|
|
191
|
-
* @param callback - Receives config
|
|
200
|
+
* @param callback - Receives config, page metadata, and emitted assets. May return a Promise.
|
|
192
201
|
*
|
|
193
202
|
* @example
|
|
194
|
-
* build.onEnd(async (config, pages) => {
|
|
203
|
+
* build.onEnd(async (config, pages, { outDir }) => {
|
|
195
204
|
* const xml = generateSitemap(pages, config.meta.baseURL);
|
|
196
|
-
* const out = "
|
|
205
|
+
* const out = join(outDir, "sitemap.xml");
|
|
197
206
|
* // Bun.write on Bun for speed, writeFile on Node/Deno
|
|
198
207
|
* await (typeof Bun !== "undefined"
|
|
199
208
|
* ? Bun.write(out, xml)
|
|
200
209
|
* : writeFile(out, xml));
|
|
201
210
|
* });
|
|
202
211
|
*/
|
|
203
|
-
onEnd(
|
|
212
|
+
onEnd(
|
|
213
|
+
callback: (config: DocuConfig, pages: PageMeta[], context: BuildEndContext) => Awaitable<void>
|
|
214
|
+
): void {
|
|
204
215
|
this._onEnd.push(callback);
|
|
205
216
|
}
|
|
206
217
|
|
|
@@ -208,7 +219,7 @@ export class BuildPluginBuilder implements PluginBuilder {
|
|
|
208
219
|
* Register a callback to transform raw file content before MDX compilation.
|
|
209
220
|
* Filtered by regex against the file's relative path — only the **first** matching
|
|
210
221
|
* handler's result is used.
|
|
211
|
-
*
|
|
222
|
+
* Callback errors are logged by `runOnLoad()` before trying later matching handlers.
|
|
212
223
|
*
|
|
213
224
|
* @param args.filter - RegExp matched against the file's relative path.
|
|
214
225
|
* @param args.namespace - Optional namespace prefix (reserved for future use).
|
|
@@ -232,7 +243,7 @@ export class BuildPluginBuilder implements PluginBuilder {
|
|
|
232
243
|
/**
|
|
233
244
|
* Register a callback to run once before the build starts.
|
|
234
245
|
* Receives the resolved DocuConfig for validation or resource initialization.
|
|
235
|
-
*
|
|
246
|
+
* Callback errors are logged by `runOnStart()` and do not stop later callbacks.
|
|
236
247
|
*
|
|
237
248
|
* @param callback - Receives the resolved config. May return a Promise.
|
|
238
249
|
*
|
|
@@ -303,12 +314,13 @@ export class BuildPluginBuilder implements PluginBuilder {
|
|
|
303
314
|
* Errors inside individual callbacks are caught and logged — execution
|
|
304
315
|
* continues to the next callback without throwing.
|
|
305
316
|
*
|
|
306
|
-
* @param pages - Array of metadata for every built page.
|
|
317
|
+
* @param pages - Array of metadata for every built docs page.
|
|
318
|
+
* @param context - Final output directory and page-specific asset manifest.
|
|
307
319
|
*/
|
|
308
|
-
async runOnEnd(pages: PageMeta[]): Promise<void> {
|
|
320
|
+
async runOnEnd(pages: PageMeta[], context: BuildEndContext): Promise<void> {
|
|
309
321
|
for (let i = 0; i < this._onEnd.length; i++) {
|
|
310
322
|
try {
|
|
311
|
-
await this._onEnd[i](this.config, pages);
|
|
323
|
+
await this._onEnd[i](this.config, pages, context);
|
|
312
324
|
} catch (err) {
|
|
313
325
|
console.error(
|
|
314
326
|
`[plugin] onEnd callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`
|
package/.docu/node/plugin.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Pluggable } from "unified";
|
|
2
|
-
import type { DocuConfig } from "./types";
|
|
2
|
+
import type { AssetEntry, AssetManifest, DocuConfig } from "./types";
|
|
3
3
|
|
|
4
4
|
// ─── Config Types ───────────────────────────────────────
|
|
5
5
|
|
|
@@ -18,14 +18,20 @@ export type PluginEntry = string | [string, Record<string, unknown>];
|
|
|
18
18
|
/**
|
|
19
19
|
* Context passed to content-transform hooks for a single page.
|
|
20
20
|
*/
|
|
21
|
+
export type PageType = keyof AssetManifest;
|
|
22
|
+
|
|
21
23
|
export interface PageContext {
|
|
24
|
+
/** Page family used to select the page-specific asset bundle. */
|
|
25
|
+
pageType: PageType;
|
|
26
|
+
/** Hashed CSS and optional JavaScript entry used by this page. */
|
|
27
|
+
assets: Readonly<AssetEntry>;
|
|
22
28
|
/** Relative slug path: "getting-started/introduction" */
|
|
23
29
|
slug: string;
|
|
24
|
-
/** Absolute file path on disk */
|
|
30
|
+
/** Absolute or project-relative source file path on disk. */
|
|
25
31
|
filePath: string;
|
|
26
|
-
/** Parsed frontmatter metadata */
|
|
32
|
+
/** Parsed frontmatter metadata. Generated pages receive site metadata or an empty object. */
|
|
27
33
|
frontmatter: Record<string, unknown>;
|
|
28
|
-
/** Raw MDX/MD content
|
|
34
|
+
/** Raw MDX/MD content. Only docs pages provide content. */
|
|
29
35
|
content?: string;
|
|
30
36
|
/** Resolved site configuration */
|
|
31
37
|
config: DocuConfig;
|
|
@@ -53,9 +59,21 @@ export interface DevServerContext {
|
|
|
53
59
|
port: number;
|
|
54
60
|
/** Dev server hostname */
|
|
55
61
|
hostname: string;
|
|
62
|
+
/** Current page-specific asset manifest, refreshed after HMR rebuilds. */
|
|
63
|
+
assetManifest: Readonly<AssetManifest>;
|
|
56
64
|
}
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Final build metadata passed to `onEnd` after all HTML files are written.
|
|
68
|
+
*/
|
|
69
|
+
export interface BuildEndContext {
|
|
70
|
+
/** Page-specific hashed assets emitted under `outDir/assets`. */
|
|
71
|
+
assetManifest: Readonly<AssetManifest>;
|
|
72
|
+
/** Absolute static output directory. */
|
|
73
|
+
outDir: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type { AssetEntry, AssetManifest, DocuConfig };
|
|
59
77
|
|
|
60
78
|
// ─── PluginBuilder Interface ────────────────────────────
|
|
61
79
|
|
|
@@ -95,19 +113,25 @@ export interface PluginBuilder {
|
|
|
95
113
|
* Register a callback to run once after all pages are built.
|
|
96
114
|
* Use for: generating sitemaps, RSS feeds, manifests, post-build reports.
|
|
97
115
|
*
|
|
98
|
-
* @param callback - Receives config
|
|
116
|
+
* @param callback - Receives config, aggregated docs metadata, and final build metadata.
|
|
99
117
|
*
|
|
100
118
|
* @example
|
|
101
|
-
* build.onEnd(async (config, pages) => {
|
|
119
|
+
* build.onEnd(async (config, pages, { outDir }) => {
|
|
102
120
|
* const xml = generateSitemap(pages, config.meta.baseURL);
|
|
103
|
-
* const out = join(
|
|
121
|
+
* const out = join(outDir, "sitemap.xml");
|
|
104
122
|
* // Bun.write on Bun for speed, writeFile on Node/Deno
|
|
105
123
|
* await (typeof Bun !== "undefined"
|
|
106
124
|
* ? Bun.write(out, xml)
|
|
107
125
|
* : writeFile(out, xml));
|
|
108
126
|
* });
|
|
109
127
|
*/
|
|
110
|
-
onEnd(
|
|
128
|
+
onEnd(
|
|
129
|
+
callback: (
|
|
130
|
+
config: DocuConfig,
|
|
131
|
+
pages: PageMeta[],
|
|
132
|
+
context: BuildEndContext
|
|
133
|
+
) => void | Promise<void>
|
|
134
|
+
): void;
|
|
111
135
|
|
|
112
136
|
// ─── Content Transform ─────────────────────────────────
|
|
113
137
|
|
|
@@ -5,10 +5,10 @@ import React, { type ReactNode } from "react";
|
|
|
5
5
|
import { renderToString } from "react-dom/server";
|
|
6
6
|
import { compileMdx, frontmatterField } from "./mdx";
|
|
7
7
|
import { DEFAULT_FAVICON, getContentType } from "./utils";
|
|
8
|
-
import { DOCS_DIR, DIST_DIR, PROJECT_ROOT } from "./paths";
|
|
8
|
+
import { DOCS_DIR, DIST_DIR, PAGES_DIR, PROJECT_ROOT } from "./paths";
|
|
9
9
|
import { BuildPluginBuilder } from "./plugin-builder";
|
|
10
|
-
import type { PageContext } from "./plugin";
|
|
11
|
-
import type { DocuConfig, TocItem } from "./types";
|
|
10
|
+
import type { PageContext, PageType } from "./plugin";
|
|
11
|
+
import type { AssetEntry, AssetManifest, DocuConfig, TocItem } from "./types";
|
|
12
12
|
import DocsPage from "../pages/docs/[[...slug]]";
|
|
13
13
|
import NotFoundPage from "../pages/404";
|
|
14
14
|
import IndexPage from "../pages/index";
|
|
@@ -18,37 +18,49 @@ import { htmlShell as createHtmlShell, hmrScript, errorHtml } from "./html.share
|
|
|
18
18
|
|
|
19
19
|
export interface ServerState {
|
|
20
20
|
docuConfig: DocuConfig;
|
|
21
|
-
assetManifest:
|
|
21
|
+
assetManifest: AssetManifest;
|
|
22
22
|
inlineThemeCss?: string;
|
|
23
23
|
builder: BuildPluginBuilder | null;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function createHtmlResponse(
|
|
26
|
+
async function createHtmlResponse(
|
|
27
27
|
title: string,
|
|
28
28
|
description: string,
|
|
29
29
|
body: string,
|
|
30
30
|
status: number,
|
|
31
31
|
state: ServerState,
|
|
32
|
+
pageType: PageType,
|
|
33
|
+
page: Omit<PageContext, "pageType" | "assets" | "config">,
|
|
32
34
|
depth = 0
|
|
33
|
-
): Response {
|
|
35
|
+
): Promise<Response> {
|
|
34
36
|
const nonce = generateNonce();
|
|
35
37
|
const favicon = state.docuConfig.meta?.favicon || DEFAULT_FAVICON;
|
|
36
|
-
const
|
|
38
|
+
const assets: AssetEntry = state.assetManifest[pageType];
|
|
39
|
+
const context: PageContext = {
|
|
40
|
+
...page,
|
|
41
|
+
pageType,
|
|
42
|
+
assets,
|
|
43
|
+
config: state.docuConfig,
|
|
44
|
+
};
|
|
45
|
+
let html = createHtmlShell({
|
|
37
46
|
title,
|
|
38
47
|
description,
|
|
39
48
|
body,
|
|
40
49
|
favicon,
|
|
41
|
-
css:
|
|
42
|
-
js:
|
|
50
|
+
css: assets.css,
|
|
51
|
+
js: assets.js,
|
|
43
52
|
nonce,
|
|
44
53
|
extraScripts: hmrScript(nonce),
|
|
45
54
|
themeCss: state.inlineThemeCss,
|
|
55
|
+
headExtra: state.builder?.collectHead(context),
|
|
56
|
+
bodyExtra: state.builder?.collectBody(context),
|
|
46
57
|
depth,
|
|
47
58
|
// 404 pages can be requested at arbitrary depths (e.g. a noLink section
|
|
48
59
|
// path typed in the address bar) — relative asset paths would resolve
|
|
49
60
|
// against the wrong directory and break CSS/JS.
|
|
50
61
|
absoluteAssets: status === 404,
|
|
51
62
|
});
|
|
63
|
+
if (state.builder) html = await state.builder.runTransformHtmlChain(html, context);
|
|
52
64
|
/** Dev-only: serves compiledSource → MDXRemote eval path (no CSP in production). */
|
|
53
65
|
return htmlResponse(html, nonce, status, true);
|
|
54
66
|
}
|
|
@@ -127,7 +139,7 @@ async function getDocsForSlug(
|
|
|
127
139
|
let frontmatter = result.frontmatter as Record<string, unknown>;
|
|
128
140
|
if (state.builder) {
|
|
129
141
|
frontmatter = await state.builder.runTransformFrontmatterChain(frontmatter, {
|
|
130
|
-
slug
|
|
142
|
+
slug,
|
|
131
143
|
filePath: relPath,
|
|
132
144
|
content,
|
|
133
145
|
});
|
|
@@ -176,41 +188,24 @@ async function renderDocsServerPage(
|
|
|
176
188
|
// Match build.ts depth calculation: slug.split("/").length, fallback to 1 for empty
|
|
177
189
|
const depth = slug.length || 1;
|
|
178
190
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
191
|
+
return createHtmlResponse(
|
|
192
|
+
title,
|
|
193
|
+
description,
|
|
194
|
+
body,
|
|
195
|
+
200,
|
|
196
|
+
state,
|
|
197
|
+
"docs",
|
|
198
|
+
{
|
|
199
|
+
slug: slug.join("/"),
|
|
182
200
|
filePath: doc.filePath,
|
|
183
201
|
frontmatter: doc.frontmatter,
|
|
184
202
|
content: doc.resolvedContent,
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const bodyExtra = state.builder.collectBody(ctx);
|
|
189
|
-
const nonce = generateNonce();
|
|
190
|
-
const favicon = state.docuConfig.meta?.favicon || DEFAULT_FAVICON;
|
|
191
|
-
let html = createHtmlShell({
|
|
192
|
-
title,
|
|
193
|
-
description,
|
|
194
|
-
body,
|
|
195
|
-
favicon,
|
|
196
|
-
css: state.assetManifest.css,
|
|
197
|
-
js: state.assetManifest.js,
|
|
198
|
-
nonce,
|
|
199
|
-
extraScripts: hmrScript(nonce),
|
|
200
|
-
themeCss: state.inlineThemeCss,
|
|
201
|
-
headExtra,
|
|
202
|
-
bodyExtra,
|
|
203
|
-
depth,
|
|
204
|
-
});
|
|
205
|
-
html = await state.builder.runTransformHtmlChain(html, ctx);
|
|
206
|
-
/** Dev-only: serves compiledSource → MDXRemote eval path (no CSP in production). */
|
|
207
|
-
return htmlResponse(html, nonce, 200, true);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return createHtmlResponse(title, description, body, 200, state, depth);
|
|
203
|
+
},
|
|
204
|
+
depth
|
|
205
|
+
);
|
|
211
206
|
}
|
|
212
207
|
|
|
213
|
-
function renderPage(
|
|
208
|
+
async function renderPage(
|
|
214
209
|
Component: React.ComponentType<Record<string, unknown>>,
|
|
215
210
|
title: string,
|
|
216
211
|
description: string,
|
|
@@ -218,14 +213,22 @@ function renderPage(
|
|
|
218
213
|
state: ServerState,
|
|
219
214
|
props: Record<string, unknown> = {},
|
|
220
215
|
depth = 0
|
|
221
|
-
): Response {
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
216
|
+
): Promise<Response> {
|
|
217
|
+
const body = renderToString(React.createElement(Component, props));
|
|
218
|
+
return createHtmlResponse(
|
|
219
|
+
title,
|
|
220
|
+
description,
|
|
221
|
+
body,
|
|
222
|
+
status,
|
|
223
|
+
state,
|
|
224
|
+
"notFound",
|
|
225
|
+
{
|
|
226
|
+
slug: "404",
|
|
227
|
+
filePath: resolve(PAGES_DIR, "404.tsx"),
|
|
228
|
+
frontmatter: {},
|
|
229
|
+
},
|
|
230
|
+
depth
|
|
226
231
|
);
|
|
227
|
-
const body = renderToString(page);
|
|
228
|
-
return createHtmlResponse(title, description, body, status, state, depth);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
export async function handleDocsIndex(state: ServerState): Promise<Response> {
|
|
@@ -242,7 +245,7 @@ export async function handleDocsRoute(slug: string[], state: ServerState): Promi
|
|
|
242
245
|
return renderDocsServerPage(doc, slug, `/docs/${path}`, state);
|
|
243
246
|
}
|
|
244
247
|
|
|
245
|
-
export function handleIndex(state: ServerState): Response {
|
|
248
|
+
export async function handleIndex(state: ServerState): Promise<Response> {
|
|
246
249
|
const page = React.createElement(IndexPage);
|
|
247
250
|
const body = renderToString(page);
|
|
248
251
|
return createHtmlResponse(
|
|
@@ -250,11 +253,17 @@ export function handleIndex(state: ServerState): Response {
|
|
|
250
253
|
state.docuConfig.meta?.description || "",
|
|
251
254
|
body,
|
|
252
255
|
200,
|
|
253
|
-
state
|
|
256
|
+
state,
|
|
257
|
+
"home",
|
|
258
|
+
{
|
|
259
|
+
slug: "",
|
|
260
|
+
filePath: resolve(PAGES_DIR, "index.tsx"),
|
|
261
|
+
frontmatter: { ...state.docuConfig.meta } as Record<string, unknown>,
|
|
262
|
+
}
|
|
254
263
|
);
|
|
255
264
|
}
|
|
256
265
|
|
|
257
|
-
export function handleNotFound(state: ServerState, depth = 0): Response {
|
|
266
|
+
export async function handleNotFound(state: ServerState, depth = 0): Promise<Response> {
|
|
258
267
|
return renderPage(NotFoundPage, "404 - Not Found", "", 404, state, {}, depth);
|
|
259
268
|
}
|
|
260
269
|
|
|
@@ -63,6 +63,7 @@ export async function runServer(adapter: RuntimeAdapter): Promise<ServerHandle>
|
|
|
63
63
|
for (const plugin of plugins) {
|
|
64
64
|
await plugin.setup(builder);
|
|
65
65
|
}
|
|
66
|
+
await builder.runOnStart();
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
const state: ServerState = {
|
|
@@ -155,6 +156,7 @@ export async function runServer(adapter: RuntimeAdapter): Promise<ServerHandle>
|
|
|
155
156
|
const pluginResponse = await builder.runHandleRequest(req, {
|
|
156
157
|
port: handle?.port ?? PORT,
|
|
157
158
|
hostname: handle?.hostname ?? "localhost",
|
|
159
|
+
assetManifest: state.assetManifest,
|
|
158
160
|
});
|
|
159
161
|
if (pluginResponse) {
|
|
160
162
|
const securedResponse = wrapPluginResponse(pluginResponse, true);
|
|
@@ -198,7 +200,7 @@ export async function runServer(adapter: RuntimeAdapter): Promise<ServerHandle>
|
|
|
198
200
|
// Manual route matching — same routes Bun.FileSystemRouter derives
|
|
199
201
|
// from `.docu/pages/` ("/", "/docs/[[...slug]]", "/404").
|
|
200
202
|
if (pathname === "/") {
|
|
201
|
-
response = handleIndex(state);
|
|
203
|
+
response = await handleIndex(state);
|
|
202
204
|
} else if (pathname === "/docs" || pathname === "/docs/") {
|
|
203
205
|
response = await handleDocsIndex(state);
|
|
204
206
|
} else if (pathname.startsWith("/docs/")) {
|
|
@@ -206,7 +208,7 @@ export async function runServer(adapter: RuntimeAdapter): Promise<ServerHandle>
|
|
|
206
208
|
response =
|
|
207
209
|
slug.length === 0 ? await handleDocsIndex(state) : await handleDocsRoute(slug, state);
|
|
208
210
|
} else {
|
|
209
|
-
response = handleNotFound(state);
|
|
211
|
+
response = await handleNotFound(state);
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
logger.request(
|
package/.docu/node/server.ts
CHANGED
|
@@ -54,6 +54,7 @@ if (builder) {
|
|
|
54
54
|
for (const plugin of plugins) {
|
|
55
55
|
await plugin.setup(builder);
|
|
56
56
|
}
|
|
57
|
+
await builder.runOnStart();
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
const state: ServerState = {
|
|
@@ -159,6 +160,7 @@ const server = Bun.serve({
|
|
|
159
160
|
const pluginResponse = await builder.runHandleRequest(req, {
|
|
160
161
|
port: serverPort,
|
|
161
162
|
hostname: serverHostname,
|
|
163
|
+
assetManifest: state.assetManifest,
|
|
162
164
|
});
|
|
163
165
|
if (pluginResponse) {
|
|
164
166
|
const securedResponse = wrapPluginResponse(pluginResponse, true);
|
|
@@ -200,27 +202,21 @@ const server = Bun.serve({
|
|
|
200
202
|
const match = router?.match(pathname);
|
|
201
203
|
let response: Response;
|
|
202
204
|
|
|
203
|
-
|
|
204
|
-
const routeName = match.name;
|
|
205
|
+
const routeName = match?.name;
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
if (routeName === "/docs/[[...slug]]") {
|
|
208
|
+
const slugParam = match?.params?.slug;
|
|
209
|
+
const slug = slugParam ? slugParam.split("/") : [];
|
|
209
210
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} else {
|
|
213
|
-
response = await handleDocsRoute(slug, state);
|
|
214
|
-
}
|
|
215
|
-
} else if (routeName === "/404") {
|
|
216
|
-
response = handleNotFound(state);
|
|
217
|
-
} else if (routeName === "/") {
|
|
218
|
-
response = handleIndex(state);
|
|
211
|
+
if (slug.length === 0) {
|
|
212
|
+
response = await handleDocsIndex(state);
|
|
219
213
|
} else {
|
|
220
|
-
response =
|
|
214
|
+
response = await handleDocsRoute(slug, state);
|
|
221
215
|
}
|
|
216
|
+
} else if (routeName === "/") {
|
|
217
|
+
response = await handleIndex(state);
|
|
222
218
|
} else {
|
|
223
|
-
response = handleNotFound(state);
|
|
219
|
+
response = await handleNotFound(state);
|
|
224
220
|
}
|
|
225
221
|
|
|
226
222
|
logger.request(
|
package/.docu/node/types.ts
CHANGED
|
@@ -93,6 +93,17 @@ export interface DocuConfig {
|
|
|
93
93
|
plugins?: PluginEntry[];
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
export interface AssetEntry {
|
|
97
|
+
css: string;
|
|
98
|
+
js?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface AssetManifest {
|
|
102
|
+
docs: AssetEntry;
|
|
103
|
+
home: AssetEntry;
|
|
104
|
+
notFound: AssetEntry;
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
export interface BuildCacheEntry {
|
|
97
108
|
hash: string;
|
|
98
109
|
mtime: number;
|
package/.docu/pages/404.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { BackgroundBlobs, Hero } from "../components/home";
|
|
2
|
+
|
|
1
3
|
export default function NotFoundPage() {
|
|
2
4
|
return (
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
<main className="bg-base-100 relative isolate flex min-h-screen w-full items-center justify-center overflow-hidden">
|
|
6
|
+
<BackgroundBlobs />
|
|
7
|
+
<Hero
|
|
8
|
+
hero={{
|
|
9
|
+
headline: "404",
|
|
10
|
+
description: "Page not found",
|
|
11
|
+
actions: [{ text: "Go to Docs", link: "/docs/" }],
|
|
12
|
+
}}
|
|
13
|
+
/>
|
|
14
|
+
</main>
|
|
12
15
|
);
|
|
13
16
|
}
|
package/.docu/pages/index.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { loadDocuConfig } from "../node/paths";
|
|
2
2
|
import { docsHtmlHref, isExternalUrl } from "../node/utils";
|
|
3
|
-
import { Hero, Features } from "../components/home";
|
|
3
|
+
import { Hero, Features, BackgroundBlobs } from "../components/home";
|
|
4
|
+
import { ThemeToggle } from "../components/Theme";
|
|
4
5
|
import type { HomeFeature } from "../node/types";
|
|
5
6
|
|
|
6
7
|
const docuConfig = loadDocuConfig();
|
|
@@ -61,41 +62,19 @@ export default function IndexPage() {
|
|
|
61
62
|
|
|
62
63
|
return (
|
|
63
64
|
<div className="bg-base-100 relative isolate min-h-screen overflow-hidden">
|
|
64
|
-
<div className="absolute top-4 right-4 z-10"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
aria-hidden="true"
|
|
69
|
-
className="pointer-events-none absolute -top-40 left-1/2 -z-10 -translate-x-1/2 blur-3xl sm:-top-80"
|
|
70
|
-
>
|
|
71
|
-
<div
|
|
72
|
-
style={{
|
|
73
|
-
clipPath:
|
|
74
|
-
"polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)",
|
|
75
|
-
}}
|
|
76
|
-
className="from-primary to-accent h-[40rem] w-[80rem] bg-gradient-to-tr opacity-20"
|
|
77
|
-
/>
|
|
65
|
+
<div className="absolute top-4 right-4 z-10">
|
|
66
|
+
<div id="theme-toggle-island">
|
|
67
|
+
<ThemeToggle />
|
|
68
|
+
</div>
|
|
78
69
|
</div>
|
|
79
70
|
|
|
71
|
+
<BackgroundBlobs />
|
|
72
|
+
|
|
80
73
|
{/* Hero Section */}
|
|
81
74
|
<Hero hero={hero} />
|
|
82
75
|
|
|
83
76
|
{/* Features Section */}
|
|
84
77
|
<Features features={features} />
|
|
85
|
-
|
|
86
|
-
{/* Bottom gradient blob */}
|
|
87
|
-
<div
|
|
88
|
-
aria-hidden="true"
|
|
89
|
-
className="pointer-events-none absolute bottom-0 left-1/2 -z-10 translate-x-1/4 blur-3xl"
|
|
90
|
-
>
|
|
91
|
-
<div
|
|
92
|
-
style={{
|
|
93
|
-
clipPath:
|
|
94
|
-
"polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)",
|
|
95
|
-
}}
|
|
96
|
-
className="from-accent to-primary h-[30rem] w-[70rem] bg-gradient-to-tr opacity-20"
|
|
97
|
-
/>
|
|
98
|
-
</div>
|
|
99
78
|
</div>
|
|
100
79
|
);
|
|
101
80
|
}
|