@docubook/flame 2.0.0-beta.2 → 2.0.0-beta.3

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 (39) hide show
  1. package/.docu/lib/build.deno.js +1 -1
  2. package/.docu/lib/{build.impl-BJsi28mD.js → build.impl-Bz_p421t.js} +60 -13
  3. package/.docu/lib/build.impl-Bz_p421t.js.map +1 -0
  4. package/.docu/lib/build.impl-CtPrlYAE.js +2 -0
  5. package/.docu/lib/build.node.js +1 -1
  6. package/.docu/lib/clean.js +1 -1
  7. package/.docu/lib/deploy.deno.js +1 -1
  8. package/.docu/lib/deploy.node.js +1 -1
  9. package/.docu/lib/{deploy.shared-D3UWafa6.js → deploy.shared-fk8eM-r4.js} +3 -3
  10. package/.docu/lib/{deploy.shared-D3UWafa6.js.map → deploy.shared-fk8eM-r4.js.map} +1 -1
  11. package/.docu/lib/{html.shared-DSn-7_6t.js → html.shared-FwgbE1WG.js} +242 -13
  12. package/.docu/lib/html.shared-FwgbE1WG.js.map +1 -0
  13. package/.docu/lib/{logger-CycvLCrQ.js → logger-CQyNTE6L.js} +9 -15
  14. package/.docu/lib/logger-CQyNTE6L.js.map +1 -0
  15. package/.docu/lib/{paths-BtOIPBQ9.js → paths-Bl2cdp9E.js} +27 -3
  16. package/.docu/lib/paths-Bl2cdp9E.js.map +1 -0
  17. package/.docu/lib/preview.deno.js +1 -1
  18. package/.docu/lib/{preview.impl-CXJS2tQS.js → preview.impl-CnsbLmDA.js} +3 -3
  19. package/.docu/lib/{preview.impl-CXJS2tQS.js.map → preview.impl-CnsbLmDA.js.map} +1 -1
  20. package/.docu/lib/preview.node.js +1 -1
  21. package/.docu/lib/server.deno.js +1 -1
  22. package/.docu/lib/{server.impl-CJuWimfN.js → server.impl-CXTzYqbF.js} +4 -4
  23. package/.docu/lib/{server.impl-CJuWimfN.js.map → server.impl-CXTzYqbF.js.map} +1 -1
  24. package/.docu/lib/server.node.js +1 -1
  25. package/.docu/node/build.impl.ts +76 -11
  26. package/.docu/node/build.ts +83 -9
  27. package/.docu/node/cache-key.ts +311 -0
  28. package/.docu/node/hydrate.node.ts +8 -11
  29. package/.docu/node/hydrate.ts +13 -14
  30. package/.docu/node/mdx.ts +14 -2
  31. package/.docu/node/paths.ts +27 -1
  32. package/.docu/node/types.ts +23 -5
  33. package/bin/cli.js +56 -18
  34. package/package.json +10 -16
  35. package/.docu/lib/build.impl-BJsi28mD.js.map +0 -1
  36. package/.docu/lib/build.impl-yVLaa1eQ.js +0 -2
  37. package/.docu/lib/html.shared-DSn-7_6t.js.map +0 -1
  38. package/.docu/lib/logger-CycvLCrQ.js.map +0 -1
  39. package/.docu/lib/paths-BtOIPBQ9.js.map +0 -1
@@ -1,14 +1,14 @@
1
- import { a as DOCS_DIR, c as PROJECT_ROOT, d as loadDocuConfig, l as STYLES_DIR, o as FRAMEWORK_ROOT, s as LIB_DIR, t as ASSETS_DIR, u as cleanOldBundles } from "./paths-BtOIPBQ9.js";
1
+ import { a as DOCS_DIR, c as PROJECT_ROOT, d as loadDocuConfig, f as resolveProjectFile, l as STYLES_DIR, o as FRAMEWORK_ROOT, s as LIB_DIR, t as ASSETS_DIR, u as cleanOldBundles } from "./paths-Bl2cdp9E.js";
2
2
  import { a as isExternalUrl, h as normalizeImporterPath, n as docsHtmlHref, o as scanMdxFiles, r as formatDate2, t as cn } from "./utils-DA17MyQG.js";
3
3
  import { builtinModules, createRequire } from "node:module";
4
4
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
5
5
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
6
- import { mkdir, readFile, stat, unlink, writeFile } from "node:fs/promises";
6
+ import { mkdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
7
7
  import { execFile } from "node:child_process";
8
8
  import { promisify } from "node:util";
9
- import { createHash } from "node:crypto";
10
9
  import { build } from "vite";
11
10
  import { generateThemeCss, presetRegistry, resolveTheme } from "@docubook/themes-colors";
11
+ import { createHash } from "node:crypto";
12
12
  import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
13
13
  import { z } from "zod";
14
14
  import { MDXRemote, createDefaultRehypePlugins, createDefaultRemarkPlugins, extractFrontmatter, extractFrontmatterWithContent, extractTocsFromRawMdx, serialize } from "@docubook/core";
@@ -464,6 +464,230 @@ var BuildPluginBuilder = class {
464
464
  else console.warn(`[plugin] ${hookName} callback returned unexpected type (got ${typeof result}), expected string or string[], skipping`);
465
465
  }
466
466
  };
467
+ /** Toolchain fingerprint: Bun version on Bun, Deno version on Deno, Node elsewhere. */
468
+ function runtimeStamp() {
469
+ const g = globalThis;
470
+ const bun = g.Bun;
471
+ if (typeof bun?.version === "string" && bun.version.length > 0) return `bun-${bun.version}`;
472
+ const deno = g.Deno;
473
+ if (typeof deno?.version?.deno === "string" && deno.version.deno.length > 0) return `deno-${deno.version.deno}`;
474
+ const proc = g.process;
475
+ if (typeof proc?.version === "string" && proc.version.length > 0) return `node-${proc.version}`;
476
+ return "node-unknown";
477
+ }
478
+ /**
479
+ * True when a CSS file can change Tailwind v4 output.
480
+ * v4 is CSS-first: `@theme`, `@source`, `@plugin`, `@custom-variant`,
481
+ * `@utility`, `@config`, `@apply`/`@variant`, and `@import "tailwindcss"`
482
+ * all live in CSS. Plain CSS without these cannot affect the CLI output,
483
+ * so it is excluded to avoid false cache busts. Broad match deliberate:
484
+ * false positive busts safe, false negative serves stale CSS.
485
+ */
486
+ function isTailwindRelevantCss(content) {
487
+ return content.includes("@theme") || content.includes("@source") || content.includes("@plugin") || content.includes("@custom-variant") || content.includes("@utility") || content.includes("@config") || content.includes("@apply") || content.includes("@variant") || content.includes("@layer") || content.includes("tailwindcss");
488
+ }
489
+ var IMPORT_RE = /@import\s+(?:url\()?["']([^"']+)["']/g;
490
+ var MAX_IMPORT_DEPTH = 10;
491
+ /** Resolve `./` + `../` imports only — bare specifiers are version-pinned deps. */
492
+ function resolveRelativeImport(spec, fromDir) {
493
+ if (!spec.startsWith(".")) return void 0;
494
+ const clean = spec.split("?")[0].split("#")[0];
495
+ if (clean.length === 0) return void 0;
496
+ return join(fromDir, clean);
497
+ }
498
+ /**
499
+ * Read a CSS file plus transitively imported relative files.
500
+ * Non-relevant files contribute "" themselves, but their imports are still
501
+ * followed (nested file may carry `@theme`). `visited` breaks import cycles.
502
+ * Missing/unreadable files resolve to "" — never throws.
503
+ */
504
+ function readCssWithImports(path, visited, depth = 0) {
505
+ if (depth > MAX_IMPORT_DEPTH || visited.has(path)) return "";
506
+ visited.add(path);
507
+ let content = "";
508
+ try {
509
+ if (!existsSync(path)) return "";
510
+ content = readFileSync(path, "utf-8");
511
+ } catch {
512
+ return "";
513
+ }
514
+ let out = isTailwindRelevantCss(content) ? content : "";
515
+ try {
516
+ const dir = join(path, "..");
517
+ for (const m of content.matchAll(IMPORT_RE)) {
518
+ const resolved = resolveRelativeImport(m[1] ?? "", dir);
519
+ if (resolved) out += readCssWithImports(resolved, visited, depth + 1);
520
+ }
521
+ } catch {}
522
+ return out;
523
+ }
524
+ function scanCssDir(dir, visited) {
525
+ let out = "";
526
+ try {
527
+ const entries = readdirSync(dir, { withFileTypes: true });
528
+ for (const e of entries) {
529
+ const full = join(dir, e.name);
530
+ if (e.isDirectory()) {
531
+ if (e.name === "assets" || e.name.startsWith(".") || e.name === "node_modules") continue;
532
+ out += scanCssDir(full, visited);
533
+ } else if (e.name.endsWith(".css")) out += readCssWithImports(full, visited);
534
+ }
535
+ } catch {}
536
+ return out;
537
+ }
538
+ function scanRootCss(root, visited) {
539
+ let out = "";
540
+ try {
541
+ const entries = readdirSync(root, { withFileTypes: true });
542
+ for (const e of entries) if (e.isFile() && e.name.endsWith(".css")) out += readCssWithImports(join(root, e.name), visited);
543
+ } catch {}
544
+ return out;
545
+ }
546
+ /** Hash @theme/@source/@plugin-bearing CSS in project docs/ + root *.css. */
547
+ function tailwindCssThemeInputs(root) {
548
+ const visited = /* @__PURE__ */ new Set();
549
+ return scanCssDir(join(root, "docs"), visited) + scanRootCss(root, visited);
550
+ }
551
+ var TAILWIND_CONFIG_FILES = [
552
+ "tailwind.config.ts",
553
+ "tailwind.config.js",
554
+ "tailwind.config.mjs",
555
+ "tailwind.config.cjs",
556
+ "tailwind.config.mts",
557
+ "tailwind.config.cts",
558
+ "postcss.config.js",
559
+ "postcss.config.mjs",
560
+ "postcss.config.cjs"
561
+ ];
562
+ /**
563
+ * JS config still affects v4 when referenced via `@config`
564
+ * (plus PostCSS pipeline config). Content hashed when present.
565
+ */
566
+ function tailwindJsConfigInputs(root) {
567
+ let out = "";
568
+ for (const name of TAILWIND_CONFIG_FILES) try {
569
+ const p = join(root, name);
570
+ if (existsSync(p)) out += readFileSync(p, "utf-8") + "\0";
571
+ } catch {}
572
+ return out;
573
+ }
574
+ function readInstalledVersion(pkg, roots) {
575
+ for (const root of roots) try {
576
+ const p = join(root, "node_modules", ...pkg.split("/"), "package.json");
577
+ if (existsSync(p)) {
578
+ const parsed = JSON.parse(readFileSync(p, "utf-8"));
579
+ if (typeof parsed.version === "string" && parsed.version.length > 0) return parsed.version;
580
+ }
581
+ } catch {}
582
+ return "";
583
+ }
584
+ /** Pin resolved CSS-affecting deps into the key (installed version wins). */
585
+ function tailwindVersionPins(root) {
586
+ const names = [
587
+ "tailwindcss",
588
+ "@tailwindcss/cli",
589
+ "@tailwindcss/typography",
590
+ "daisyui"
591
+ ];
592
+ let extra = "";
593
+ const roots = [root, FRAMEWORK_ROOT];
594
+ for (const name of names) {
595
+ const installed = readInstalledVersion(name, roots);
596
+ if (installed) extra += `${name}@${installed}\0`;
597
+ }
598
+ try {
599
+ const pkgPath = join(root, "package.json");
600
+ if (existsSync(pkgPath)) {
601
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
602
+ for (const name of names) {
603
+ const range = pkg.dependencies?.[name] ?? pkg.devDependencies?.[name] ?? "";
604
+ if (range) extra += `${name}:${range}\0`;
605
+ }
606
+ }
607
+ } catch {}
608
+ return extra;
609
+ }
610
+ /**
611
+ * Extra Tailwind inputs beyond globals.css + theme.
612
+ * v4 is CSS-first: user overrides live in `@theme`/`@source`/`@plugin`
613
+ * blocks inside CSS files under the project root (e.g. docs slash star dot css),
614
+ * plus JS config referenced via `@config` and installed plugin versions.
615
+ * Missing files resolve to "" — never throws.
616
+ */
617
+ function tailwindExtraInputs(root = resolveProjectFile()) {
618
+ return tailwindCssThemeInputs(root) + "\0" + tailwindJsConfigInputs(root) + tailwindVersionPins(root);
619
+ }
620
+ /**
621
+ * Shared Tailwind cache key: globals.css + theme + tailwind config +
622
+ * toolchain version. Used by both hydrate.ts (Bun) and hydrate.node.ts
623
+ * (Vite) so the two runtimes agree on filenames. Segments joined with NUL
624
+ * so `("ab","c")` and `("a","bc")` hash differently.
625
+ */
626
+ function computeTailwindCacheKey(globals, themeSuffix, projectRoot = resolveProjectFile()) {
627
+ const h = createHash("sha256");
628
+ h.update(globals);
629
+ h.update("\0");
630
+ h.update(themeSuffix);
631
+ h.update("\0");
632
+ h.update(tailwindExtraInputs(projectRoot));
633
+ h.update("\0");
634
+ h.update(runtimeStamp());
635
+ h.update("\0");
636
+ h.update(`v3`);
637
+ return h.digest("hex").slice(0, 16);
638
+ }
639
+ /** Read globals.css content ("" when missing). Shared by both hydrators. */
640
+ function readGlobalsCss() {
641
+ const globalsPath = join(STYLES_DIR, "globals.css");
642
+ return existsSync(globalsPath) ? readFileSync(globalsPath, "utf-8") : "";
643
+ }
644
+ /**
645
+ * Atomic file write: tmp + rename so a crash mid-write never leaves a
646
+ * half-written cache/CSS behind. Tmp name includes pid so parallel
647
+ * builds (`bun run --parallel`) do not clobber each other.
648
+ */
649
+ async function atomicWriteFile(writeFile, rename, unlink, target, data) {
650
+ const proc = globalThis.process;
651
+ const tmp = `${target}.tmp-${typeof proc?.pid === "number" ? proc.pid : Math.floor(Math.random() * 1e9)}-${Date.now()}`;
652
+ try {
653
+ await writeFile(tmp, data);
654
+ await rename(tmp, target);
655
+ } catch (err) {
656
+ try {
657
+ await unlink(tmp);
658
+ } catch {}
659
+ throw err;
660
+ }
661
+ }
662
+ /** Wire memory-pressure hook once: OS low-memory → drop parsed page maps. */
663
+ var memoryPressureHooked = false;
664
+ function hookMemoryPressure(clear) {
665
+ if (memoryPressureHooked) return;
666
+ memoryPressureHooked = true;
667
+ try {
668
+ globalThis.process?.on?.("memoryPressure", () => {
669
+ try {
670
+ clear();
671
+ } catch {}
672
+ });
673
+ } catch {}
674
+ }
675
+ /**
676
+ * Hash of compiled MDX module sources (sorted keys + content).
677
+ * Used to skip the JS bundle rebuild when no page content changed.
678
+ */
679
+ function hashMdxSources(mdxSources) {
680
+ const h = createHash("sha256");
681
+ const slugs = Object.keys(mdxSources).sort();
682
+ h.update(`v3:${runtimeStamp()}:`);
683
+ for (const slug of slugs) {
684
+ h.update(slug);
685
+ h.update("\0");
686
+ h.update(mdxSources[slug]);
687
+ h.update("\0");
688
+ }
689
+ return h.digest("hex").slice(0, 16);
690
+ }
467
691
  //#endregion
468
692
  //#region .docu/node/fs-scanner.ts
469
693
  function toTitleCase$1(str) {
@@ -652,16 +876,15 @@ function resolveTailwindBin() {
652
876
  const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin.tailwindcss;
653
877
  return join(dirname(pkgPath), binRel);
654
878
  }
655
- /** Compute a cache key from globals.css + theme config content. */
879
+ /** Compute a cache key from globals.css + theme + config + toolchain. */
656
880
  function tailwindCacheKey() {
657
- const globalsPath = join(STYLES_DIR, "globals.css");
658
- const globalsContent = existsSync(globalsPath) ? readFileSync(globalsPath, "utf-8") : "";
881
+ const globalsContent = readGlobalsCss();
659
882
  let themeSuffix = "";
660
883
  try {
661
884
  const themeColors = getThemeConfig();
662
885
  if (themeColors) themeSuffix = JSON.stringify(themeColors);
663
886
  } catch {}
664
- return createHash("sha256").update(globalsContent + themeSuffix).digest("hex").slice(0, 16);
887
+ return computeTailwindCacheKey(globalsContent, themeSuffix);
665
888
  }
666
889
  /**
667
890
  * Build Tailwind CSS with content-based caching.
@@ -697,7 +920,7 @@ async function buildTailwindCss(key) {
697
920
  throw new Error(`Tailwind CSS build failed:\n${stderr}`, { cause: err });
698
921
  }
699
922
  let cssContent = await readFile(tmpCss, "utf-8");
700
- await unlink(tmpCss);
923
+ await unlink(tmpCss).catch(() => {});
701
924
  try {
702
925
  const themeColors = getThemeConfig();
703
926
  if (themeColors) cssContent = buildThemeCss(cssContent, themeColors);
@@ -706,7 +929,7 @@ async function buildTailwindCss(key) {
706
929
  }
707
930
  const cssFile = `client-${key}.css`;
708
931
  const outPath = join(ASSETS_DIR, cssFile);
709
- if (!existsSync(outPath)) await writeFile(outPath, cssContent);
932
+ if (!existsSync(outPath)) await atomicWriteFile(writeFile, rename, unlink, outPath, cssContent);
710
933
  return {
711
934
  file: cssFile,
712
935
  content: cssContent
@@ -1053,7 +1276,7 @@ function frontmatterField(frontmatter, key) {
1053
1276
  * (defaults + .html link fixes + user plugins) and runs `serialize()`.
1054
1277
  */
1055
1278
  async function serializeWithDocPlugins(rawMdx, opts = {}, pre) {
1056
- const { strippedContent, frontmatter } = pre ?? extractFrontmatterWithContent(rawMdx, opts.frontmatterSchema);
1279
+ const { strippedContent, frontmatter } = pre ?? (opts.frontmatterSchema ? extractFrontmatterWithContent(rawMdx, opts.frontmatterSchema) : extractFrontmatterWithContent(rawMdx));
1057
1280
  const defaultRemark = createDefaultRemarkPlugins();
1058
1281
  const defaultRehype = createDefaultRehypePlugins();
1059
1282
  const finalRemark = [
@@ -1091,7 +1314,7 @@ async function serializeWithDocPlugins(rawMdx, opts = {}, pre) {
1091
1314
  */
1092
1315
  async function compileMdx(rawMdx, filePath, gitDates, remarkPlugins, rehypePlugins, frontmatterSchema, pre) {
1093
1316
  const tocs = extractTocsFromRawMdx(rawMdx);
1094
- const frontmatter = pre?.frontmatter ?? extractFrontmatterWithContent(rawMdx, frontmatterSchema).frontmatter;
1317
+ const frontmatter = pre?.frontmatter ?? (frontmatterSchema ? extractFrontmatterWithContent(rawMdx, frontmatterSchema).frontmatter : extractFrontmatterWithContent(rawMdx).frontmatter);
1095
1318
  const serialized = await serializeWithDocPlugins(rawMdx, {
1096
1319
  remarkPlugins,
1097
1320
  rehypePlugins,
@@ -1159,6 +1382,12 @@ function registerPageContent(href, raw) {
1159
1382
  function getPageContent(href) {
1160
1383
  return pageContent.get(href);
1161
1384
  }
1385
+ /** Drop derived page maps under OS memory pressure (Bun 1.4 `memoryPressure`). */
1386
+ function clearDerivedPageCaches() {
1387
+ pageContent.clear();
1388
+ pageStripped.clear();
1389
+ pageFrontmatter.clear();
1390
+ }
1162
1391
  async function compileMdxModule(rawMdx, remarkPlugins, rehypePlugins, href) {
1163
1392
  const serialized = await serializeWithDocPlugins(rawMdx, {
1164
1393
  outputFormat: "program",
@@ -2462,6 +2691,6 @@ function hmrScript(nonce) {
2462
2691
  <\/script>`;
2463
2692
  }
2464
2693
  //#endregion
2465
- export { loadPlugins as S, registerPageContent as _, IndexPage as a, computeInlineThemeCss as b, captureException as c, compileMdx as d, compileMdxModule as f, getPageStripped as g, getPageFrontmatter as h, DocsLayout as i, initSentry as l, getPageContent as m, hmrScript as n, NotFoundPage as o, frontmatterField as p, htmlShell as r, DocsPage as s, errorHtml as t, generateSearchIndex as u, getGitLastModifiedBatch as v, BuildPluginBuilder as x, buildClientBundle as y };
2694
+ export { hashMdxSources as C, loadPlugins as D, BuildPluginBuilder as E, atomicWriteFile as S, runtimeStamp as T, getPageStripped as _, IndexPage as a, buildClientBundle as b, captureException as c, clearDerivedPageCaches as d, compileMdx as f, getPageFrontmatter as g, getPageContent as h, DocsLayout as i, initSentry as l, frontmatterField as m, hmrScript as n, NotFoundPage as o, compileMdxModule as p, htmlShell as r, DocsPage as s, errorHtml as t, generateSearchIndex as u, registerPageContent as v, hookMemoryPressure as w, computeInlineThemeCss as x, getGitLastModifiedBatch as y };
2466
2695
 
2467
- //# sourceMappingURL=html.shared-DSn-7_6t.js.map
2696
+ //# sourceMappingURL=html.shared-FwgbE1WG.js.map