@docubook/flame 1.4.3 → 1.5.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.
Files changed (55) hide show
  1. package/.docu/lib/build.deno.js +11 -0
  2. package/.docu/lib/build.impl-ST63VRTV.js +12 -0
  3. package/.docu/lib/build.node.js +10 -0
  4. package/.docu/lib/chunk-2QHMGZIL.js +2419 -0
  5. package/.docu/lib/chunk-654THQOR.js +461 -0
  6. package/.docu/lib/chunk-C6RZ2KBH.js +79 -0
  7. package/.docu/lib/chunk-HH4YXWEF.js +300 -0
  8. package/.docu/lib/chunk-J5NMYSBJ.js +59 -0
  9. package/.docu/lib/chunk-RE4NGTMT.js +185 -0
  10. package/.docu/lib/chunk-X6GYOIYZ.js +383 -0
  11. package/.docu/lib/chunk-ZOWTASXL.js +92 -0
  12. package/.docu/lib/clean.js +32 -0
  13. package/.docu/lib/deploy.deno.js +13 -0
  14. package/.docu/lib/deploy.node.js +10 -0
  15. package/.docu/lib/preview.deno.js +10 -0
  16. package/.docu/lib/preview.node.js +10 -0
  17. package/.docu/lib/server.deno.js +11 -0
  18. package/.docu/lib/server.node.js +11 -0
  19. package/.docu/node/build-summary.ts +126 -0
  20. package/.docu/node/build.deno.ts +7 -0
  21. package/.docu/node/build.impl.ts +424 -0
  22. package/.docu/node/build.node.ts +3 -0
  23. package/.docu/node/deploy.deno.ts +11 -0
  24. package/.docu/node/deploy.node.ts +6 -0
  25. package/.docu/node/deploy.shared.ts +85 -0
  26. package/.docu/node/deploy.ts +11 -0
  27. package/.docu/node/escapeHtml.ts +18 -0
  28. package/.docu/node/git.ts +79 -0
  29. package/.docu/node/html.shared.ts +110 -0
  30. package/.docu/node/html.ts +1 -1
  31. package/.docu/node/hydrate.node.ts +287 -0
  32. package/.docu/node/hydrate.ts +16 -19
  33. package/.docu/node/mdx.ts +1 -1
  34. package/.docu/node/paths.ts +24 -0
  35. package/.docu/node/plugin-builder.ts +6 -2
  36. package/.docu/node/plugin.ts +11 -2
  37. package/.docu/node/preview.deno.ts +4 -0
  38. package/.docu/node/preview.impl.ts +96 -0
  39. package/.docu/node/preview.node.ts +4 -0
  40. package/.docu/node/security.ts +5 -0
  41. package/.docu/node/server-routes.ts +4 -4
  42. package/.docu/node/server.deno.ts +4 -0
  43. package/.docu/node/server.impl.ts +184 -0
  44. package/.docu/node/server.node.ts +4 -0
  45. package/.docu/styles/globals.css +20 -5
  46. package/README.md +57 -506
  47. package/bin/cli.js +89 -14
  48. package/bin/compile-lib.mjs +67 -0
  49. package/package.json +9 -5
  50. package/template/docs/getting-started/configuration.mdx +18 -0
  51. package/template/docs/getting-started/overview.mdx +50 -0
  52. package/template/docs/guide/deployment.mdx +27 -0
  53. package/template/docs/guide/routing.mdx +25 -0
  54. package/template/docs/index.mdx +8 -205
  55. package/template/docu.json +32 -1
@@ -0,0 +1,461 @@
1
+ import {
2
+ BuildPluginBuilder,
3
+ DocsLayout,
4
+ DocsPage,
5
+ IndexPage,
6
+ NotFoundPage,
7
+ buildClientBundle,
8
+ captureException,
9
+ compileMdx,
10
+ computeInlineThemeCss,
11
+ generateSearchIndex,
12
+ getGitLastModifiedBatch,
13
+ htmlShell,
14
+ initSentry,
15
+ loadPlugins
16
+ } from "./chunk-2QHMGZIL.js";
17
+ import {
18
+ generateNonce,
19
+ scanMdxFiles
20
+ } from "./chunk-RE4NGTMT.js";
21
+ import {
22
+ logger
23
+ } from "./chunk-HH4YXWEF.js";
24
+ import {
25
+ ASSETS_DIR,
26
+ CACHE_FILE,
27
+ DIST_DIR,
28
+ DOCS_ASSETS_DIR,
29
+ DOCS_DIR,
30
+ PROJECT_ROOT,
31
+ loadDocuConfig
32
+ } from "./chunk-J5NMYSBJ.js";
33
+
34
+ // .docu/node/build.impl.ts
35
+ import { readFile, writeFile, mkdir, readdir as readdir2, copyFile } from "node:fs/promises";
36
+ import { existsSync as existsSync2 } from "node:fs";
37
+ import { createHash } from "node:crypto";
38
+ import { join as join2, dirname } from "node:path";
39
+ import React from "react";
40
+ import { renderToString } from "react-dom/server";
41
+
42
+ // .docu/node/build-summary.ts
43
+ import { readdir, stat } from "node:fs/promises";
44
+ import { join, relative, extname } from "node:path";
45
+ import { existsSync } from "node:fs";
46
+ var MAX_FILES_SHOWN = 10;
47
+ var SEP = "\u2500".repeat(60);
48
+ function formatSize(bytes) {
49
+ if (bytes < 1024) return `${bytes} B`;
50
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
51
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
52
+ }
53
+ async function walkFiles(dir) {
54
+ const out = [];
55
+ const entries = await readdir(dir, { withFileTypes: true });
56
+ for (const entry of entries) {
57
+ const full = join(dir, entry.name);
58
+ if (entry.isDirectory()) {
59
+ out.push(...await walkFiles(full));
60
+ } else if (entry.isFile()) {
61
+ const s = await stat(full);
62
+ out.push({ path: full, size: s.size });
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ async function collectBuildOutput(distDir) {
68
+ if (!existsSync(distDir)) return null;
69
+ const all = await walkFiles(distDir);
70
+ if (all.length === 0) return null;
71
+ const files = all.map((f) => ({ path: relative(distDir, f.path), size: f.size })).sort((a, b) => b.size !== a.size ? b.size - a.size : a.path.localeCompare(b.path));
72
+ const byExt = /* @__PURE__ */ new Map();
73
+ for (const f of files) {
74
+ const ext = extname(f.path) || "(none)";
75
+ const entry = byExt.get(ext) ?? { ext, count: 0, size: 0 };
76
+ entry.count++;
77
+ entry.size += f.size;
78
+ byExt.set(ext, entry);
79
+ }
80
+ const byType = [...byExt.values()].sort(
81
+ (a, b) => b.size !== a.size ? b.size - a.size : b.count - a.count
82
+ );
83
+ return {
84
+ files,
85
+ byType,
86
+ totalFiles: files.length,
87
+ totalSize: files.reduce((sum, f) => sum + f.size, 0)
88
+ };
89
+ }
90
+ function formatBuildSummary(output) {
91
+ const lines = [];
92
+ lines.push("\u{1F4E6} Build Output Summary:");
93
+ lines.push(SEP);
94
+ const shown = output.files.slice(0, MAX_FILES_SHOWN);
95
+ const nameWidth = Math.min(Math.max(...shown.map((f) => f.path.length), 1), 50);
96
+ for (const f of shown) {
97
+ lines.push(` ${f.path.padEnd(nameWidth)} ${formatSize(f.size).padStart(10)}`);
98
+ }
99
+ const remaining = output.totalFiles - shown.length;
100
+ if (remaining > 0) {
101
+ lines.push(` ... and ${remaining} more file${remaining === 1 ? "" : "s"}`);
102
+ }
103
+ lines.push(SEP);
104
+ lines.push("\u{1F4CA} Summary by Type:");
105
+ const extWidth = Math.max(...output.byType.map((t) => t.ext.length), 1);
106
+ for (const t of output.byType) {
107
+ const plural = t.count === 1 ? "file" : "files";
108
+ lines.push(
109
+ ` ${t.ext.padEnd(extWidth)} ${String(t.count).padStart(3)} ${plural} ${formatSize(
110
+ t.size
111
+ ).padStart(10)}`
112
+ );
113
+ }
114
+ lines.push(SEP);
115
+ const totalPlural = output.totalFiles === 1 ? "file" : "files";
116
+ lines.push(
117
+ `\u{1F4C8} Total: ${output.totalFiles} ${totalPlural} ${formatSize(output.totalSize).padStart(10)}`
118
+ );
119
+ lines.push(SEP);
120
+ return lines.join("\n");
121
+ }
122
+ async function generateBuildSummary(distDir) {
123
+ const output = await collectBuildOutput(distDir);
124
+ return output ? formatBuildSummary(output) : null;
125
+ }
126
+
127
+ // .docu/node/build.impl.ts
128
+ function parseArgs() {
129
+ const args = process.argv.slice(2);
130
+ return {
131
+ force: args.includes("--force") || args.includes("-f"),
132
+ clean: args.includes("--clean") || args.includes("-c")
133
+ };
134
+ }
135
+ function hashContent(content) {
136
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
137
+ }
138
+ async function readCache() {
139
+ try {
140
+ if (existsSync2(CACHE_FILE)) {
141
+ const data = await readFile(CACHE_FILE, "utf-8");
142
+ return JSON.parse(data);
143
+ }
144
+ } catch (err) {
145
+ console.error("Failed to load build cache:", err.message);
146
+ }
147
+ return {};
148
+ }
149
+ async function writeCache(cache) {
150
+ await writeFile(CACHE_FILE, JSON.stringify(cache, null, 2));
151
+ }
152
+ function parseConcurrency() {
153
+ return Math.max(1, parseInt(process.env.BUILD_CONCURRENCY || "4", 10) || 4);
154
+ }
155
+ function shouldRebuild(path, mtime, cache) {
156
+ const cached = cache[path];
157
+ if (!cached) return "yes";
158
+ if (mtime > cached.builtAt) return "hash_check";
159
+ return "no";
160
+ }
161
+ var assetManifest = { js: "client.js", css: "client.css" };
162
+ var inlineThemeCss;
163
+ async function renderDocsPage(docuConfig, slug, rawMdx, filePath, gitDates, builder, nonce) {
164
+ let content = rawMdx;
165
+ if (builder) {
166
+ const transformed = await builder.runOnLoad(filePath, content);
167
+ if (transformed?.contents) {
168
+ content = transformed.contents;
169
+ }
170
+ }
171
+ let result;
172
+ try {
173
+ const remarkPlugins = builder?.collectRemarkPlugins();
174
+ const rehypePlugins = builder?.collectRehypePlugins();
175
+ result = await compileMdx(content, filePath, gitDates, remarkPlugins, rehypePlugins);
176
+ } catch (err) {
177
+ const msg = err instanceof Error ? err.message : "Unknown MDX error";
178
+ throw new Error(`MDX Error in: docs/${slug}.mdx
179
+ ${msg}`, { cause: err });
180
+ }
181
+ let frontmatter = result.frontmatter;
182
+ if (builder) {
183
+ frontmatter = await builder.runTransformFrontmatterChain(frontmatter, {
184
+ slug,
185
+ filePath,
186
+ content
187
+ });
188
+ }
189
+ const title = (typeof frontmatter.title === "string" ? frontmatter.title : "") || slug || "Docs";
190
+ const description = typeof frontmatter.description === "string" ? frontmatter.description : "";
191
+ const slugParts = slug ? slug.split("/") : [];
192
+ const page = React.createElement(
193
+ DocsLayout,
194
+ { repoUrl: docuConfig.repo?.url },
195
+ React.createElement(DocsPage, {
196
+ slug: slugParts,
197
+ title,
198
+ description,
199
+ date: frontmatter.date || void 0,
200
+ content: result.content,
201
+ tocs: result.tocs,
202
+ filePath,
203
+ repoUrl: docuConfig.repo?.url,
204
+ compiledSource: result.compiledSource
205
+ })
206
+ );
207
+ const body = renderToString(page);
208
+ const ctx = { slug, filePath, frontmatter, content, config: docuConfig };
209
+ const headExtra = builder?.collectHead(ctx);
210
+ const bodyExtra = builder?.collectBody(ctx);
211
+ const depth = slug ? slug.split("/").length : 1;
212
+ const favicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
213
+ let html = htmlShell({
214
+ title,
215
+ description,
216
+ body,
217
+ favicon,
218
+ css: assetManifest.css,
219
+ js: assetManifest.js,
220
+ nonce,
221
+ themeCss: inlineThemeCss,
222
+ depth,
223
+ headExtra,
224
+ bodyExtra
225
+ });
226
+ if (builder) {
227
+ html = await builder.runTransformHtmlChain(html, ctx);
228
+ }
229
+ return html;
230
+ }
231
+ async function copyDirectoryRecursive(src, dest) {
232
+ if (!existsSync2(src)) return;
233
+ await mkdir(dest, { recursive: true });
234
+ const entries = await readdir2(src, { withFileTypes: true });
235
+ for (const entry of entries) {
236
+ const srcPath = join2(src, entry.name);
237
+ const destPath = join2(dest, entry.name);
238
+ if (entry.isDirectory()) {
239
+ await copyDirectoryRecursive(srcPath, destPath);
240
+ } else {
241
+ await copyFile(srcPath, destPath);
242
+ }
243
+ }
244
+ }
245
+ async function runBuild() {
246
+ const docuConfig = loadDocuConfig();
247
+ const args = parseArgs();
248
+ logger.buildStart();
249
+ if (args.clean) {
250
+ const { rm } = await import("node:fs/promises");
251
+ try {
252
+ await rm(DIST_DIR, { recursive: true, force: true });
253
+ } catch (err) {
254
+ console.error("Failed to clean dist directory:", err.message);
255
+ }
256
+ }
257
+ await mkdir(DIST_DIR, { recursive: true });
258
+ await mkdir(ASSETS_DIR, { recursive: true });
259
+ await copyDirectoryRecursive(DOCS_ASSETS_DIR, join2(DIST_DIR, "docs", "assets"));
260
+ const mdxFiles = await scanMdxFiles(DOCS_DIR);
261
+ const cache = args.force ? {} : await readCache();
262
+ let built = 0;
263
+ let skipped = 0;
264
+ logger.bundleStart();
265
+ let t = performance.now();
266
+ assetManifest = await buildClientBundle();
267
+ logger.bundleDone(Math.round(performance.now() - t));
268
+ inlineThemeCss = computeInlineThemeCss();
269
+ const lastManifest = cache["__assets__"];
270
+ const assetsChanged = !lastManifest || lastManifest.hash !== `${assetManifest.js}:${assetManifest.css}`;
271
+ if (assetsChanged) {
272
+ cache["__assets__"] = {
273
+ hash: `${assetManifest.js}:${assetManifest.css}`,
274
+ mtime: 0,
275
+ builtAt: Date.now()
276
+ };
277
+ }
278
+ const pluginsConfig = docuConfig.plugins ?? [];
279
+ const builder = pluginsConfig.length > 0 ? new BuildPluginBuilder(docuConfig) : null;
280
+ if (builder) {
281
+ const plugins = await loadPlugins(pluginsConfig);
282
+ for (const plugin of plugins) {
283
+ await plugin.setup(builder);
284
+ }
285
+ await builder.runOnStart();
286
+ }
287
+ logger.spinner.start("Building pages...");
288
+ t = performance.now();
289
+ const allRelPaths = mdxFiles.map((f) => f.absPath.replace(PROJECT_ROOT + "/", ""));
290
+ const indexMdxFull = join2(DOCS_DIR, "index.mdx");
291
+ if (existsSync2(indexMdxFull)) {
292
+ allRelPaths.push(indexMdxFull.replace(PROJECT_ROOT + "/", ""));
293
+ }
294
+ const gitDates = await getGitLastModifiedBatch(allRelPaths);
295
+ const CONCURRENCY = parseConcurrency();
296
+ const buildTasks = [];
297
+ const errors = [];
298
+ for (const file of mdxFiles) {
299
+ const rebuildDecision = shouldRebuild(file.path, file.mtime, cache);
300
+ if (rebuildDecision === "no") {
301
+ const outputPath = join2(DIST_DIR, "docs", `${file.path}.html`);
302
+ if (existsSync2(outputPath) && !assetsChanged) {
303
+ skipped++;
304
+ continue;
305
+ }
306
+ }
307
+ let rawMdx;
308
+ try {
309
+ rawMdx = await readFile(file.absPath, "utf-8");
310
+ } catch (err) {
311
+ if (err.code !== "ENOENT") throw err;
312
+ continue;
313
+ }
314
+ if (rebuildDecision === "hash_check") {
315
+ const contentHash = hashContent(rawMdx);
316
+ const cached = cache[file.path];
317
+ if (cached && cached.hash === contentHash) {
318
+ if (!assetsChanged) {
319
+ const outputPath = join2(DIST_DIR, "docs", `${file.path}.html`);
320
+ if (existsSync2(outputPath)) {
321
+ cache[file.path] = { ...cached, mtime: file.mtime, builtAt: Date.now() };
322
+ skipped++;
323
+ continue;
324
+ }
325
+ }
326
+ }
327
+ }
328
+ const relPath = file.absPath.replace(PROJECT_ROOT + "/", "");
329
+ const capturedRawMdx = rawMdx;
330
+ const capturedFile = file;
331
+ buildTasks.push(async () => {
332
+ try {
333
+ const pageNonce = generateNonce();
334
+ const html = await renderDocsPage(
335
+ docuConfig,
336
+ capturedFile.path,
337
+ capturedRawMdx,
338
+ relPath,
339
+ gitDates,
340
+ builder,
341
+ pageNonce
342
+ );
343
+ const outputPath = join2(DIST_DIR, "docs", `${capturedFile.path}.html`);
344
+ await mkdir(dirname(outputPath), { recursive: true });
345
+ await writeFile(outputPath, html);
346
+ cache[capturedFile.path] = {
347
+ hash: hashContent(capturedRawMdx),
348
+ mtime: capturedFile.mtime,
349
+ builtAt: Date.now()
350
+ };
351
+ built++;
352
+ } catch (err) {
353
+ const msg = err instanceof Error ? err.message : String(err);
354
+ errors.push(msg);
355
+ console.error(`
356
+ \u274C ${msg}
357
+ `);
358
+ }
359
+ });
360
+ }
361
+ for (let i = 0; i < buildTasks.length; i += CONCURRENCY) {
362
+ await Promise.all(buildTasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
363
+ }
364
+ try {
365
+ const indexMdxPath = join2(DOCS_DIR, "index.mdx");
366
+ const indexRaw = await readFile(indexMdxPath, "utf-8");
367
+ const indexRelPath = indexMdxPath.replace(PROJECT_ROOT + "/", "");
368
+ const indexHtml = await renderDocsPage(
369
+ docuConfig,
370
+ "",
371
+ indexRaw,
372
+ indexRelPath,
373
+ gitDates,
374
+ builder,
375
+ generateNonce()
376
+ );
377
+ await mkdir(join2(DIST_DIR, "docs"), { recursive: true });
378
+ await writeFile(join2(DIST_DIR, "docs", "index.html"), indexHtml);
379
+ } catch (err) {
380
+ const msg = err instanceof Error ? err.message : String(err);
381
+ errors.push(`index.mdx: ${msg}`);
382
+ console.error(`
383
+ \u274C Failed to build index: ${msg}
384
+ `);
385
+ }
386
+ const landingPage = React.createElement(IndexPage);
387
+ const landingFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
388
+ const landingHtml = htmlShell({
389
+ title: docuConfig.meta?.title || "DocuBook",
390
+ description: docuConfig.meta?.description || "",
391
+ body: renderToString(landingPage),
392
+ favicon: landingFavicon,
393
+ css: assetManifest.css,
394
+ js: assetManifest.js,
395
+ nonce: generateNonce(),
396
+ themeCss: inlineThemeCss
397
+ });
398
+ await writeFile(join2(DIST_DIR, "index.html"), landingHtml);
399
+ const notFoundPage = React.createElement(
400
+ DocsLayout,
401
+ { repoUrl: docuConfig.repo?.url },
402
+ React.createElement(NotFoundPage)
403
+ );
404
+ const notFoundFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
405
+ const notFoundHtml = htmlShell({
406
+ title: "404 - Not Found",
407
+ description: "",
408
+ body: renderToString(notFoundPage),
409
+ favicon: notFoundFavicon,
410
+ css: assetManifest.css,
411
+ js: assetManifest.js,
412
+ nonce: generateNonce(),
413
+ themeCss: inlineThemeCss
414
+ });
415
+ await writeFile(join2(DIST_DIR, "404.html"), notFoundHtml);
416
+ logger.spinner.stop(
417
+ `Built ${built} pages (${skipped} cached) \x1B[90m(${Math.round(performance.now() - t)}ms)\x1B[0m`
418
+ );
419
+ if (builder) {
420
+ const pages = mdxFiles.map((f) => ({
421
+ slug: f.path,
422
+ title: f.path.split("/").pop() || f.path,
423
+ filePath: join2(DOCS_DIR, f.path),
424
+ outputPath: join2(DIST_DIR, "docs", `${f.path}.html`)
425
+ }));
426
+ await builder.runOnEnd(pages);
427
+ }
428
+ logger.indexStart();
429
+ t = performance.now();
430
+ const indexCount = await generateSearchIndex();
431
+ logger.indexDone(indexCount, Math.round(performance.now() - t));
432
+ logger.routes();
433
+ console.log("");
434
+ const buildSummary = await generateBuildSummary(DIST_DIR);
435
+ if (buildSummary) {
436
+ console.log(buildSummary);
437
+ console.log("");
438
+ }
439
+ await writeCache(cache);
440
+ if (errors.length > 0) {
441
+ console.error(`
442
+ \u274C Build completed with ${errors.length} error(s)
443
+ `);
444
+ process.exit(1);
445
+ }
446
+ }
447
+ async function runBuildCli() {
448
+ try {
449
+ await initSentry();
450
+ await runBuild();
451
+ } catch (err) {
452
+ captureException(err);
453
+ console.error("Build failed:", err);
454
+ process.exit(1);
455
+ }
456
+ }
457
+
458
+ export {
459
+ runBuild,
460
+ runBuildCli
461
+ };
@@ -0,0 +1,79 @@
1
+ import {
2
+ DIST_DIR,
3
+ PROJECT_ROOT
4
+ } from "./chunk-J5NMYSBJ.js";
5
+
6
+ // .docu/node/deploy.shared.ts
7
+ import { writeFile, mkdir } from "node:fs/promises";
8
+ import { existsSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ var WORKFLOW_DIR = join(PROJECT_ROOT, ".github/workflows");
11
+ var WORKFLOW_FILE = join(WORKFLOW_DIR, "deploy.yml");
12
+ async function runDeploy() {
13
+ console.log("\u{1F4E6} Building for production...\n");
14
+ process.env.NODE_ENV = "production";
15
+ const { runBuildCli } = await import("./build.impl-ST63VRTV.js");
16
+ await runBuildCli();
17
+ await writeFile(join(DIST_DIR, ".nojekyll"), "");
18
+ if (!existsSync(WORKFLOW_FILE)) {
19
+ await mkdir(WORKFLOW_DIR, { recursive: true });
20
+ await writeFile(WORKFLOW_FILE, GITHUB_ACTIONS_WORKFLOW);
21
+ console.log("\n\u{1F4C4} Created .github/workflows/deploy.yml");
22
+ }
23
+ console.log("\n\u2705 Ready to deploy!");
24
+ console.log(" Output: .docu/dist/");
25
+ console.log(" Push to GitHub and enable Pages (Settings \u2192 Pages \u2192 Source: GitHub Actions)");
26
+ }
27
+ var GITHUB_ACTIONS_WORKFLOW = `name: Deploy to GitHub Pages
28
+
29
+ on:
30
+ push:
31
+ branches: [main]
32
+ workflow_dispatch:
33
+
34
+ permissions:
35
+ contents: read
36
+ pages: write
37
+ id-token: write
38
+
39
+ concurrency:
40
+ group: "pages"
41
+ cancel-in-progress: false
42
+
43
+ jobs:
44
+ build:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ with:
49
+ fetch-depth: 0
50
+
51
+ - uses: actions/setup-node@v4
52
+ with:
53
+ node-version: 22
54
+
55
+ - run: npm install
56
+
57
+ - run: npm run build
58
+
59
+ - name: Add .nojekyll
60
+ run: touch .docu/dist/.nojekyll
61
+
62
+ - uses: actions/upload-pages-artifact@v3
63
+ with:
64
+ path: .docu/dist
65
+
66
+ deploy:
67
+ environment:
68
+ name: github-pages
69
+ url: \${{ steps.deployment.outputs.page_url }}
70
+ runs-on: ubuntu-latest
71
+ needs: build
72
+ steps:
73
+ - id: deployment
74
+ uses: actions/deploy-pages@v4
75
+ `;
76
+
77
+ export {
78
+ runDeploy
79
+ };