@docubook/flame 1.7.2 → 2.0.0-alpha.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/Context.tsx +1 -1
- package/.docu/components/Search.tsx +6 -6
- package/.docu/components/Sidebar.tsx +37 -8
- package/.docu/components/Theme.tsx +2 -2
- package/.docu/components/Toc.tsx +51 -5
- package/.docu/components/Typography.tsx +1 -1
- package/.docu/components/home/Hero.tsx +4 -4
- package/.docu/components/registry.ts +1 -1
- package/.docu/lib/build.deno.js +3 -3
- package/.docu/lib/{build.impl-TSIF3F7O.js → build.impl-WR24HDUT.js} +3 -3
- package/.docu/lib/build.node.js +3 -3
- package/.docu/lib/{chunk-HRO7ONJQ.js → chunk-2EYRWRDP.js} +66 -26
- package/.docu/lib/{chunk-PJIJEPNR.js → chunk-AJV2GEDF.js} +5 -4
- package/.docu/lib/{chunk-KMDGSD57.js → chunk-KEWRVASF.js} +3 -3
- package/.docu/lib/{chunk-B6LGUADD.js → chunk-QPF4DPZQ.js} +294 -177
- package/.docu/lib/chunk-UISOJ4RW.js +114 -0
- package/.docu/lib/{chunk-DITXUPUV.js → chunk-VPV7KP7K.js} +56 -9
- package/.docu/lib/{chunk-SPHVBXRR.js → chunk-X7KPVCDN.js} +6 -6
- 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/preview.deno.js +5 -3
- package/.docu/lib/preview.node.js +5 -3
- package/.docu/lib/server.deno.js +6 -4
- package/.docu/lib/server.node.js +6 -4
- package/.docu/node/build.impl.ts +72 -26
- package/.docu/node/build.ts +67 -17
- package/.docu/node/client.ts +64 -27
- package/.docu/node/deploy.shared.ts +5 -5
- package/.docu/node/deploy.ts +1 -1
- package/.docu/node/hydrate.node.ts +69 -4
- package/.docu/node/hydrate.ts +50 -1
- package/.docu/node/mdx-manifest.d.ts +5 -0
- package/.docu/node/mdx.ts +103 -17
- package/.docu/node/preview.deno.ts +1 -1
- package/.docu/node/preview.impl.ts +3 -3
- package/.docu/node/preview.node.ts +1 -1
- package/.docu/node/preview.ts +2 -2
- package/.docu/node/runtime/bun.ts +28 -0
- package/.docu/node/runtime/deno.ts +34 -0
- package/.docu/node/runtime/index.ts +4 -0
- package/.docu/node/runtime/node.ts +107 -0
- package/.docu/node/runtime/types.ts +19 -0
- package/.docu/node/search-indexer.ts +3 -2
- package/.docu/node/seo.ts +2 -2
- package/.docu/node/server-routes.ts +28 -13
- package/.docu/node/server.deno.ts +1 -1
- package/.docu/node/server.impl.ts +49 -3
- package/.docu/node/server.node.ts +1 -1
- package/.docu/node/server.ts +45 -1
- package/.docu/pages/docs/[[...slug]].tsx +13 -4
- package/.docu/pages/index.tsx +1 -1
- package/.docu/styles/globals.css +29 -20
- package/README.md +7 -48
- package/bin/cli.js +25 -7
- package/package.json +7 -6
- package/template/README.md +7 -48
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// .docu/node/runtime/deno.ts
|
|
2
|
+
var denoAdapter = {
|
|
3
|
+
name: "deno",
|
|
4
|
+
serve(fetch, options) {
|
|
5
|
+
const server = Deno.serve(
|
|
6
|
+
{
|
|
7
|
+
port: options.port,
|
|
8
|
+
hostname: options.hostname,
|
|
9
|
+
onListen: () => {
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
fetch
|
|
13
|
+
);
|
|
14
|
+
return {
|
|
15
|
+
port: server.addr.port,
|
|
16
|
+
hostname: server.addr.hostname,
|
|
17
|
+
stop: () => server.shutdown()
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// .docu/node/runtime/node.ts
|
|
23
|
+
import { createServer } from "node:http";
|
|
24
|
+
function toWebRequest(req, port, hostname) {
|
|
25
|
+
const host = req.headers.host ?? `${hostname}:${port}`;
|
|
26
|
+
const url = `http://${host}${req.url ?? "/"}`;
|
|
27
|
+
const headers = new Headers();
|
|
28
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
29
|
+
if (value === void 0) continue;
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
for (const v of value) headers.append(key, v);
|
|
32
|
+
} else {
|
|
33
|
+
headers.set(key, value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const method = req.method ?? "GET";
|
|
37
|
+
const hasBody = method !== "GET" && method !== "HEAD";
|
|
38
|
+
return new Request(url, {
|
|
39
|
+
method,
|
|
40
|
+
headers,
|
|
41
|
+
// IncomingMessage is an async iterable of Buffer chunks; Request accepts
|
|
42
|
+
// an async iterable body when half-duplex is declared.
|
|
43
|
+
body: hasBody ? req : void 0,
|
|
44
|
+
// @ts-expect-error -- required by undici for streaming request bodies
|
|
45
|
+
duplex: hasBody ? "half" : void 0
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function writeResponse(response, res) {
|
|
49
|
+
const headers = {};
|
|
50
|
+
const setCookie = response.headers.getSetCookie?.() ?? [];
|
|
51
|
+
response.headers.forEach((value, key) => {
|
|
52
|
+
if (key === "set-cookie") return;
|
|
53
|
+
headers[key] = value;
|
|
54
|
+
});
|
|
55
|
+
if (setCookie.length > 0) headers["set-cookie"] = setCookie;
|
|
56
|
+
res.writeHead(response.status, headers);
|
|
57
|
+
if (!response.body) {
|
|
58
|
+
res.end();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const reader = response.body.getReader();
|
|
62
|
+
try {
|
|
63
|
+
for (; ; ) {
|
|
64
|
+
const { done, value } = await reader.read();
|
|
65
|
+
if (done) break;
|
|
66
|
+
const ok = res.write(value);
|
|
67
|
+
if (!ok) await new Promise((resolve) => res.once("drain", resolve));
|
|
68
|
+
}
|
|
69
|
+
res.end();
|
|
70
|
+
} catch {
|
|
71
|
+
await reader.cancel().catch(() => {
|
|
72
|
+
});
|
|
73
|
+
res.destroy();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
var nodeAdapter = {
|
|
77
|
+
name: "node",
|
|
78
|
+
serve(fetch, options) {
|
|
79
|
+
const hostname = options.hostname ?? "localhost";
|
|
80
|
+
const server = createServer((req, res) => {
|
|
81
|
+
Promise.resolve().then(() => fetch(toWebRequest(req, options.port, hostname))).then((response) => writeResponse(response, res)).catch((err) => {
|
|
82
|
+
console.error(err);
|
|
83
|
+
if (!res.headersSent) {
|
|
84
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
85
|
+
}
|
|
86
|
+
res.end("Internal Server Error");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
if (options.idleTimeout !== void 0) {
|
|
90
|
+
server.timeout = options.idleTimeout * 1e3;
|
|
91
|
+
server.keepAliveTimeout = options.idleTimeout * 1e3;
|
|
92
|
+
}
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
server.once("error", reject);
|
|
95
|
+
server.listen(options.port, () => {
|
|
96
|
+
const address = server.address();
|
|
97
|
+
const port = typeof address === "object" && address ? address.port : options.port;
|
|
98
|
+
resolve({
|
|
99
|
+
port,
|
|
100
|
+
hostname,
|
|
101
|
+
stop: () => new Promise((res2, rej2) => {
|
|
102
|
+
server.closeAllConnections?.();
|
|
103
|
+
server.close((err) => err ? rej2(err) : res2());
|
|
104
|
+
})
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
denoAdapter,
|
|
113
|
+
nodeAdapter
|
|
114
|
+
};
|
|
@@ -9,12 +9,13 @@ import {
|
|
|
9
9
|
compileMdx,
|
|
10
10
|
computeInlineThemeCss,
|
|
11
11
|
errorHtml,
|
|
12
|
+
frontmatterField,
|
|
12
13
|
generateSearchIndex,
|
|
13
14
|
hmrScript,
|
|
14
15
|
htmlShell,
|
|
15
16
|
initSentry,
|
|
16
17
|
loadPlugins
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-QPF4DPZQ.js";
|
|
18
19
|
import {
|
|
19
20
|
SECURITY_HEADERS,
|
|
20
21
|
generateNonce,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
} from "./chunk-EOK6KATZ.js";
|
|
28
29
|
import {
|
|
29
30
|
logger
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-AJV2GEDF.js";
|
|
31
32
|
import {
|
|
32
33
|
DIST_DIR,
|
|
33
34
|
DOCS_DIR,
|
|
@@ -36,10 +37,12 @@ import {
|
|
|
36
37
|
} from "./chunk-4IQXHHPF.js";
|
|
37
38
|
|
|
38
39
|
// .docu/node/server.impl.ts
|
|
39
|
-
import { watch } from "node:fs";
|
|
40
|
+
import { watch, existsSync } from "node:fs";
|
|
41
|
+
import { dirname, join } from "node:path";
|
|
42
|
+
import { createRequire } from "node:module";
|
|
40
43
|
|
|
41
44
|
// .docu/node/server-routes.ts
|
|
42
|
-
import { readFile } from "node:fs/promises";
|
|
45
|
+
import { readFile, stat } from "node:fs/promises";
|
|
43
46
|
import { resolve } from "node:path";
|
|
44
47
|
import { readFileSync, statSync } from "node:fs";
|
|
45
48
|
import React from "react";
|
|
@@ -61,6 +64,7 @@ function createHtmlResponse(title, description, body, status, state, depth = 0)
|
|
|
61
64
|
});
|
|
62
65
|
return htmlResponse(html, nonce, status, true);
|
|
63
66
|
}
|
|
67
|
+
var docsCache = /* @__PURE__ */ new Map();
|
|
64
68
|
async function getDocsForSlug(slug, state) {
|
|
65
69
|
if (!isSlugSafe(slug, DOCS_DIR)) return null;
|
|
66
70
|
const paths = [
|
|
@@ -87,6 +91,11 @@ async function getDocsForSlug(slug, state) {
|
|
|
87
91
|
}
|
|
88
92
|
if (!filePath || !raw) return null;
|
|
89
93
|
const relPath = filePath.replace(PROJECT_ROOT + "/", "");
|
|
94
|
+
const mtimeMs = (await stat(filePath)).mtimeMs;
|
|
95
|
+
const cached = docsCache.get(relPath);
|
|
96
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
97
|
+
return cached.doc;
|
|
98
|
+
}
|
|
90
99
|
let content = raw;
|
|
91
100
|
if (state.builder) {
|
|
92
101
|
const transformed = await state.builder.runOnLoad(relPath, content);
|
|
@@ -105,7 +114,7 @@ async function getDocsForSlug(slug, state) {
|
|
|
105
114
|
content
|
|
106
115
|
});
|
|
107
116
|
}
|
|
108
|
-
|
|
117
|
+
const doc = {
|
|
109
118
|
content: result.content,
|
|
110
119
|
compiledSource: result.compiledSource,
|
|
111
120
|
frontmatter,
|
|
@@ -113,10 +122,12 @@ async function getDocsForSlug(slug, state) {
|
|
|
113
122
|
filePath: relPath,
|
|
114
123
|
resolvedContent: content
|
|
115
124
|
};
|
|
125
|
+
docsCache.set(relPath, { mtimeMs, doc });
|
|
126
|
+
return doc;
|
|
116
127
|
}
|
|
117
128
|
async function renderDocsServerPage(doc, slug, pathname, state) {
|
|
118
|
-
const title = (
|
|
119
|
-
const description =
|
|
129
|
+
const title = frontmatterField(doc.frontmatter, "title") || slug.join("/") || "Docs";
|
|
130
|
+
const description = frontmatterField(doc.frontmatter, "description");
|
|
120
131
|
const page = React.createElement(
|
|
121
132
|
DocsLayout,
|
|
122
133
|
{ repoUrl: state.docuConfig.repo?.url, pathname },
|
|
@@ -124,8 +135,9 @@ async function renderDocsServerPage(doc, slug, pathname, state) {
|
|
|
124
135
|
slug,
|
|
125
136
|
title,
|
|
126
137
|
description,
|
|
127
|
-
date: doc.frontmatter
|
|
128
|
-
|
|
138
|
+
date: frontmatterField(doc.frontmatter, "date") || void 0,
|
|
139
|
+
// Same root-relative SSR as build — see build.ts.
|
|
140
|
+
content: renderToString(doc.content),
|
|
129
141
|
tocs: doc.tocs,
|
|
130
142
|
filePath: doc.filePath,
|
|
131
143
|
repoUrl: state.docuConfig.repo?.url,
|
|
@@ -283,6 +295,16 @@ async function runServer(adapter) {
|
|
|
283
295
|
builder
|
|
284
296
|
};
|
|
285
297
|
const hmrClients = /* @__PURE__ */ new Set();
|
|
298
|
+
const require2 = createRequire(import.meta.url);
|
|
299
|
+
function resolveMdxContentSrc() {
|
|
300
|
+
try {
|
|
301
|
+
const pkgDir = dirname(require2.resolve("@docubook/markdown/package.json"));
|
|
302
|
+
const src = join(pkgDir, "src");
|
|
303
|
+
return existsSync(src) ? src : null;
|
|
304
|
+
} catch {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
286
308
|
let hmrTimeout = null;
|
|
287
309
|
const watcher = watch(DOCS_DIR, { recursive: true }, (_event, filename) => {
|
|
288
310
|
if (!filename || !filename.endsWith(".mdx") && !filename.endsWith(".md")) return;
|
|
@@ -297,12 +319,37 @@ async function runServer(adapter) {
|
|
|
297
319
|
}
|
|
298
320
|
}, 300);
|
|
299
321
|
});
|
|
322
|
+
let srcHmrTimeout = null;
|
|
323
|
+
const mdxContentSrc = resolveMdxContentSrc();
|
|
324
|
+
const srcWatcher = mdxContentSrc ? watch(mdxContentSrc, { recursive: true }, (_event, filename) => {
|
|
325
|
+
if (!filename || !/\.(ts|tsx|js|jsx|css)$/.test(filename)) return;
|
|
326
|
+
if (srcHmrTimeout) clearTimeout(srcHmrTimeout);
|
|
327
|
+
srcHmrTimeout = setTimeout(async () => {
|
|
328
|
+
try {
|
|
329
|
+
state.assetManifest = await buildClientBundle();
|
|
330
|
+
logger.warn("[hmr] client bundle rebuilt (component change)");
|
|
331
|
+
} catch (e) {
|
|
332
|
+
logger.warn(
|
|
333
|
+
`[hmr] bundle rebuild failed: ${e instanceof Error ? e.message : String(e)}`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
for (const client of [...hmrClients]) {
|
|
337
|
+
try {
|
|
338
|
+
client.enqueue(new TextEncoder().encode("data: reload\n\n"));
|
|
339
|
+
} catch {
|
|
340
|
+
hmrClients.delete(client);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}, 300);
|
|
344
|
+
}) : null;
|
|
300
345
|
process.on("SIGINT", () => {
|
|
301
346
|
watcher.close();
|
|
347
|
+
srcWatcher?.close();
|
|
302
348
|
process.exit(0);
|
|
303
349
|
});
|
|
304
350
|
process.on("SIGTERM", () => {
|
|
305
351
|
watcher.close();
|
|
352
|
+
srcWatcher?.close();
|
|
306
353
|
process.exit(0);
|
|
307
354
|
});
|
|
308
355
|
let handle = null;
|
|
@@ -28,7 +28,7 @@ var NGINX_CONF = `server {
|
|
|
28
28
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
|
29
29
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
30
30
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
31
|
-
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'
|
|
31
|
+
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self' data:; connect-src 'self' https:; frame-src https://www.youtube-nocookie.com; frame-ancestors 'none'" always;
|
|
32
32
|
|
|
33
33
|
location /assets/ {
|
|
34
34
|
expires 1y;
|
|
@@ -38,7 +38,7 @@ var NGINX_CONF = `server {
|
|
|
38
38
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
|
39
39
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
40
40
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
41
|
-
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'
|
|
41
|
+
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self' data:; connect-src 'self' https:; frame-src https://www.youtube-nocookie.com; frame-ancestors 'none'" always;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
location /docs/assets/ {
|
|
@@ -49,7 +49,7 @@ var NGINX_CONF = `server {
|
|
|
49
49
|
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
|
|
50
50
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
51
51
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
52
|
-
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'
|
|
52
|
+
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self' data:; connect-src 'self' https:; frame-src https://www.youtube-nocookie.com; frame-ancestors 'none'" always;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
location / {
|
|
@@ -113,7 +113,7 @@ var HEADERS_FILE = `/*
|
|
|
113
113
|
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
|
|
114
114
|
Referrer-Policy: strict-origin-when-cross-origin
|
|
115
115
|
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
|
116
|
-
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
|
|
116
|
+
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self' data:; connect-src 'self' https:; frame-src https://www.youtube-nocookie.com; frame-ancestors 'none'
|
|
117
117
|
|
|
118
118
|
/assets/*
|
|
119
119
|
Cache-Control: public, max-age=31536000, immutable
|
|
@@ -137,7 +137,7 @@ async function runBuild() {
|
|
|
137
137
|
process.env.FLAME_BUILD_SILENT = "1";
|
|
138
138
|
process.env.LOG_LEVEL = "error";
|
|
139
139
|
}
|
|
140
|
-
const { runBuildCli } = await import("./build.impl-
|
|
140
|
+
const { runBuildCli } = await import("./build.impl-WR24HDUT.js");
|
|
141
141
|
await runBuildCli();
|
|
142
142
|
}
|
|
143
143
|
async function writeDockerFiles() {
|
|
@@ -145,7 +145,7 @@ async function writeDockerFiles() {
|
|
|
145
145
|
if (!existsSync(join(dockerDir, "Dockerfile"))) {
|
|
146
146
|
await writeFile(
|
|
147
147
|
join(dockerDir, "Dockerfile"),
|
|
148
|
-
`FROM ghcr.io/docubook/flame
|
|
148
|
+
`FROM ghcr.io/docubook/flame:${FLAME_MAJOR} AS builder
|
|
149
149
|
ENV NODE_ENV=production
|
|
150
150
|
WORKDIR /app
|
|
151
151
|
COPY . .
|
package/.docu/lib/clean.js
CHANGED
package/.docu/lib/deploy.deno.js
CHANGED
package/.docu/lib/deploy.node.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runPreview
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KEWRVASF.js";
|
|
4
|
+
import {
|
|
5
|
+
denoAdapter
|
|
6
|
+
} from "./chunk-UISOJ4RW.js";
|
|
4
7
|
import "./chunk-EOK6KATZ.js";
|
|
5
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-AJV2GEDF.js";
|
|
6
9
|
import "./chunk-4IQXHHPF.js";
|
|
7
10
|
|
|
8
11
|
// .docu/node/preview.deno.ts
|
|
9
|
-
import { denoAdapter } from "@docubook/runt";
|
|
10
12
|
await runPreview(denoAdapter);
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runPreview
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KEWRVASF.js";
|
|
4
|
+
import {
|
|
5
|
+
nodeAdapter
|
|
6
|
+
} from "./chunk-UISOJ4RW.js";
|
|
4
7
|
import "./chunk-EOK6KATZ.js";
|
|
5
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-AJV2GEDF.js";
|
|
6
9
|
import "./chunk-4IQXHHPF.js";
|
|
7
10
|
|
|
8
11
|
// .docu/node/preview.node.ts
|
|
9
|
-
import { nodeAdapter } from "@docubook/runt";
|
|
10
12
|
await runPreview(nodeAdapter);
|
package/.docu/lib/server.deno.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runServer
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-VPV7KP7K.js";
|
|
4
|
+
import "./chunk-QPF4DPZQ.js";
|
|
5
|
+
import {
|
|
6
|
+
denoAdapter
|
|
7
|
+
} from "./chunk-UISOJ4RW.js";
|
|
5
8
|
import "./chunk-EOK6KATZ.js";
|
|
6
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-AJV2GEDF.js";
|
|
7
10
|
import "./chunk-4IQXHHPF.js";
|
|
8
11
|
|
|
9
12
|
// .docu/node/server.deno.ts
|
|
10
|
-
import { denoAdapter } from "@docubook/runt";
|
|
11
13
|
await runServer(denoAdapter);
|
package/.docu/lib/server.node.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runServer
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-VPV7KP7K.js";
|
|
4
|
+
import "./chunk-QPF4DPZQ.js";
|
|
5
|
+
import {
|
|
6
|
+
nodeAdapter
|
|
7
|
+
} from "./chunk-UISOJ4RW.js";
|
|
5
8
|
import "./chunk-EOK6KATZ.js";
|
|
6
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-AJV2GEDF.js";
|
|
7
10
|
import "./chunk-4IQXHHPF.js";
|
|
8
11
|
|
|
9
12
|
// .docu/node/server.node.ts
|
|
10
|
-
import { nodeAdapter } from "@docubook/runt";
|
|
11
13
|
await runServer(nodeAdapter);
|
package/.docu/node/build.impl.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { createHash } from "node:crypto";
|
|
|
12
12
|
import { join, dirname } from "node:path";
|
|
13
13
|
import React from "react";
|
|
14
14
|
import { renderToString } from "react-dom/server";
|
|
15
|
-
import { compileMdx, getGitLastModifiedBatch } from "./mdx";
|
|
15
|
+
import { compileMdx, compileMdxModule, frontmatterField, getGitLastModifiedBatch } from "./mdx";
|
|
16
16
|
import {
|
|
17
17
|
DOCS_DIR,
|
|
18
18
|
DIST_DIR,
|
|
@@ -120,8 +120,8 @@ async function renderDocsPage(
|
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const title = (
|
|
124
|
-
const description =
|
|
123
|
+
const title = frontmatterField(frontmatter, "title") || slug || "Docs";
|
|
124
|
+
const description = frontmatterField(frontmatter, "description");
|
|
125
125
|
const slugParts = slug ? slug.split("/") : [];
|
|
126
126
|
|
|
127
127
|
const page = React.createElement(
|
|
@@ -131,12 +131,15 @@ async function renderDocsPage(
|
|
|
131
131
|
slug: slugParts,
|
|
132
132
|
title,
|
|
133
133
|
description,
|
|
134
|
-
date: (frontmatter
|
|
135
|
-
content:
|
|
134
|
+
date: frontmatterField(frontmatter, "date") || undefined,
|
|
135
|
+
// Render MDX content as its own root: client hydrates the island as a
|
|
136
|
+
// separate root, so SSR must be root-relative too or useId-based ids
|
|
137
|
+
// (mdx-compiler components) mismatch during hydration.
|
|
138
|
+
content: renderToString(result.content),
|
|
136
139
|
tocs: result.tocs,
|
|
137
140
|
filePath,
|
|
138
141
|
repoUrl: docuConfig.repo?.url,
|
|
139
|
-
|
|
142
|
+
mdxSlug: slug,
|
|
140
143
|
})
|
|
141
144
|
);
|
|
142
145
|
|
|
@@ -149,11 +152,9 @@ async function renderDocsPage(
|
|
|
149
152
|
const depth = slug ? slug.split("/").length : 1;
|
|
150
153
|
const favicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
151
154
|
const seo = buildSeoMeta(docuConfig, frontmatter, slug || "");
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
*/
|
|
156
|
-
const csp = cspHeader(nonce, true);
|
|
155
|
+
// MDX content hydrates from the bundled ESM module (mdx-hydrate), not
|
|
156
|
+
// new Function — no 'unsafe-eval' needed in the CSP.
|
|
157
|
+
const csp = cspHeader(nonce);
|
|
157
158
|
let html = htmlShell({
|
|
158
159
|
title,
|
|
159
160
|
description,
|
|
@@ -217,9 +218,66 @@ export async function runBuild(): Promise<void> {
|
|
|
217
218
|
let built = 0;
|
|
218
219
|
let skipped = 0;
|
|
219
220
|
|
|
221
|
+
const pluginsConfig = docuConfig.plugins ?? [];
|
|
222
|
+
const builder = pluginsConfig.length > 0 ? new BuildPluginBuilder(docuConfig) : null;
|
|
223
|
+
if (builder) {
|
|
224
|
+
const plugins = await loadPlugins(pluginsConfig);
|
|
225
|
+
for (const plugin of plugins) {
|
|
226
|
+
await plugin.setup(builder);
|
|
227
|
+
}
|
|
228
|
+
await builder.runOnStart();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Pre-compile every page's MDX to an ESM module (program format) so the
|
|
232
|
+
// client bundle can hydrate the content island statically — no new Function.
|
|
233
|
+
// Mirrors the page loop's transform + plugin chain so SSR and client trees
|
|
234
|
+
// match. Runs for all files regardless of cache; the bundle is shared by
|
|
235
|
+
// every page, so a content change invalidates the page cache anyway.
|
|
236
|
+
const mdxSources: Record<string, string> = {};
|
|
237
|
+
const prePassTasks = mdxFiles.map(async (file) => {
|
|
238
|
+
let raw: string;
|
|
239
|
+
try {
|
|
240
|
+
raw = await readFile(file.absPath, "utf-8");
|
|
241
|
+
} catch {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
let content = raw;
|
|
245
|
+
if (builder) {
|
|
246
|
+
const relPath = file.absPath.replace(PROJECT_ROOT + "/", "");
|
|
247
|
+
const transformed = await builder.runOnLoad(relPath, content);
|
|
248
|
+
if (transformed?.contents) content = transformed.contents;
|
|
249
|
+
}
|
|
250
|
+
const remarkPlugins = builder?.collectRemarkPlugins();
|
|
251
|
+
const rehypePlugins = builder?.collectRehypePlugins();
|
|
252
|
+
mdxSources[file.path] = await compileMdxModule(content, remarkPlugins, rehypePlugins);
|
|
253
|
+
});
|
|
254
|
+
await Promise.all(prePassTasks);
|
|
255
|
+
|
|
256
|
+
// The docs root (index.mdx) renders with slug "" — mirror that key so the
|
|
257
|
+
// index page hydrates too. Its render has its own try/catch; skip on error.
|
|
258
|
+
const indexMdxPath = join(DOCS_DIR, "index.mdx");
|
|
259
|
+
if (existsSync(indexMdxPath)) {
|
|
260
|
+
try {
|
|
261
|
+
const indexRaw = await readFile(indexMdxPath, "utf-8");
|
|
262
|
+
let indexContent = indexRaw;
|
|
263
|
+
if (builder) {
|
|
264
|
+
const relPath = indexMdxPath.replace(PROJECT_ROOT + "/", "");
|
|
265
|
+
const transformed = await builder.runOnLoad(relPath, indexContent);
|
|
266
|
+
if (transformed?.contents) indexContent = transformed.contents;
|
|
267
|
+
}
|
|
268
|
+
mdxSources[""] = await compileMdxModule(
|
|
269
|
+
indexContent,
|
|
270
|
+
builder?.collectRemarkPlugins(),
|
|
271
|
+
builder?.collectRehypePlugins()
|
|
272
|
+
);
|
|
273
|
+
} catch {
|
|
274
|
+
// ignore — the index render reports its own error
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
220
278
|
logger.bundleStart();
|
|
221
279
|
let t = performance.now();
|
|
222
|
-
assetManifest = await buildClientBundle();
|
|
280
|
+
assetManifest = await buildClientBundle(mdxSources);
|
|
223
281
|
logger.bundleDone(Math.round(performance.now() - t));
|
|
224
282
|
|
|
225
283
|
inlineThemeCss = computeInlineThemeCss();
|
|
@@ -235,16 +293,6 @@ export async function runBuild(): Promise<void> {
|
|
|
235
293
|
};
|
|
236
294
|
}
|
|
237
295
|
|
|
238
|
-
const pluginsConfig = docuConfig.plugins ?? [];
|
|
239
|
-
const builder = pluginsConfig.length > 0 ? new BuildPluginBuilder(docuConfig) : null;
|
|
240
|
-
if (builder) {
|
|
241
|
-
const plugins = await loadPlugins(pluginsConfig);
|
|
242
|
-
for (const plugin of plugins) {
|
|
243
|
-
await plugin.setup(builder);
|
|
244
|
-
}
|
|
245
|
-
await builder.runOnStart();
|
|
246
|
-
}
|
|
247
|
-
|
|
248
296
|
logger.spinner.start("Building pages...");
|
|
249
297
|
t = performance.now();
|
|
250
298
|
|
|
@@ -362,8 +410,7 @@ export async function runBuild(): Promise<void> {
|
|
|
362
410
|
body: renderToString(landingPage),
|
|
363
411
|
favicon: landingFavicon,
|
|
364
412
|
seo: landingSeo,
|
|
365
|
-
|
|
366
|
-
csp: cspHeader(landingNonce, true),
|
|
413
|
+
csp: cspHeader(landingNonce),
|
|
367
414
|
css: assetManifest.css,
|
|
368
415
|
js: assetManifest.js,
|
|
369
416
|
nonce: landingNonce,
|
|
@@ -384,8 +431,7 @@ export async function runBuild(): Promise<void> {
|
|
|
384
431
|
body: renderToString(notFoundPage),
|
|
385
432
|
favicon: notFoundFavicon,
|
|
386
433
|
headExtra: ['<meta name="robots" content="noindex,follow">'],
|
|
387
|
-
|
|
388
|
-
csp: cspHeader(notFoundNonce, true),
|
|
434
|
+
csp: cspHeader(notFoundNonce),
|
|
389
435
|
css: assetManifest.css,
|
|
390
436
|
js: assetManifest.js,
|
|
391
437
|
nonce: notFoundNonce,
|