meno-core 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/chunks/{chunk-NUP7H7D3.js → chunk-7ZLF4NE5.js} +2 -2
  2. package/dist/chunks/{chunk-QWTQZHG3.js → chunk-FQBIC2OB.js} +1 -1
  3. package/dist/chunks/chunk-FQBIC2OB.js.map +7 -0
  4. package/dist/chunks/{chunk-2IIQK7T3.js → chunk-J4IPTP5X.js} +393 -3
  5. package/dist/chunks/{chunk-2IIQK7T3.js.map → chunk-J4IPTP5X.js.map} +3 -3
  6. package/dist/lib/client/index.js +2 -2
  7. package/dist/lib/server/index.js +804 -218
  8. package/dist/lib/server/index.js.map +4 -4
  9. package/dist/lib/shared/index.js +6 -2
  10. package/dist/lib/shared/index.js.map +2 -2
  11. package/lib/server/index.ts +19 -0
  12. package/lib/server/services/ColorService.ts +38 -7
  13. package/lib/server/services/VariableService.ts +34 -5
  14. package/lib/server/ssr/htmlGenerator.ts +18 -2
  15. package/lib/server/ssr/ssrRenderer.test.ts +25 -0
  16. package/lib/server/ssr/ssrRenderer.ts +12 -2
  17. package/lib/server/themeCssCodec.test.ts +154 -0
  18. package/lib/server/themeCssCodec.ts +488 -0
  19. package/lib/server/themeCssStore.test.ts +139 -0
  20. package/lib/server/themeCssStore.ts +210 -0
  21. package/lib/shared/cssGeneration.test.ts +10 -0
  22. package/lib/shared/cssGeneration.ts +10 -8
  23. package/lib/shared/index.ts +6 -0
  24. package/lib/shared/interactiveStyles.test.ts +3 -1
  25. package/lib/shared/tailwindThemeScale.ts +256 -0
  26. package/lib/shared/types/colors.ts +6 -2
  27. package/lib/shared/types/variables.ts +14 -7
  28. package/lib/shared/utilityClassConfig.ts +116 -0
  29. package/lib/shared/utilityClassMapper.test.ts +148 -0
  30. package/lib/shared/utilityClassMapper.ts +33 -0
  31. package/lib/shared/utilityClassNames.ts +146 -0
  32. package/package.json +1 -1
  33. package/dist/chunks/chunk-QWTQZHG3.js.map +0 -7
  34. /package/dist/chunks/{chunk-NUP7H7D3.js.map → chunk-7ZLF4NE5.js.map} +0 -0
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  CMS_DRAFT_SUFFIX,
3
+ VARIABLE_GROUPS,
3
4
  buildSlugIndex,
4
5
  collectComponentLibraries,
5
6
  createLogger,
@@ -8,6 +9,7 @@ import {
8
9
  fontFaceCss,
9
10
  fontPreloadLinks,
10
11
  generateLibraryTags,
12
+ getDefaultScalingType,
11
13
  getLocaleLinks,
12
14
  isPathWithinRoot,
13
15
  isReservedDraftFilename,
@@ -18,7 +20,7 @@ import {
18
20
  resolveSlugToPageId,
19
21
  rewriteComponentRefs,
20
22
  translatePath
21
- } from "../../chunks/chunk-QWTQZHG3.js";
23
+ } from "../../chunks/chunk-FQBIC2OB.js";
22
24
  import {
23
25
  syncNetlifyLocale404Block
24
26
  } from "../../chunks/chunk-2AR55GYH.js";
@@ -31,7 +33,7 @@ import {
31
33
  processStructure,
32
34
  resolveHtmlMapping,
33
35
  skipEmptyTemplateAttributes
34
- } from "../../chunks/chunk-NUP7H7D3.js";
36
+ } from "../../chunks/chunk-7ZLF4NE5.js";
35
37
  import {
36
38
  DEFAULT_BREAKPOINTS,
37
39
  DEFAULT_FLUID_RANGE,
@@ -90,7 +92,7 @@ import {
90
92
  validateCMSDraftItem,
91
93
  validateCMSItem,
92
94
  validateComponentDefinition
93
- } from "../../chunks/chunk-2IIQK7T3.js";
95
+ } from "../../chunks/chunk-J4IPTP5X.js";
94
96
  import {
95
97
  DEFAULT_I18N_CONFIG,
96
98
  buildLocalizedPath,
@@ -457,13 +459,13 @@ async function bundleWithBun(entrypoint, opts) {
457
459
  const code = await result.outputs[0].text();
458
460
  return { code, success: true, errors: [] };
459
461
  }
460
- const errors = (result.logs || []).map((log6) => {
462
+ const errors = (result.logs || []).map((log7) => {
461
463
  const parts = [];
462
- if (log6.position?.file) parts.push(`File: ${log6.position.file}`);
463
- if (log6.position?.line) parts.push(`Line ${log6.position.line}:${log6.position.column || 0}`);
464
- if (log6.position?.lineText) parts.push(log6.position.lineText);
465
- if (log6.message) parts.push(log6.message);
466
- return parts.length > 0 ? parts.join("\n") : String(log6);
464
+ if (log7.position?.file) parts.push(`File: ${log7.position.file}`);
465
+ if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
466
+ if (log7.position?.lineText) parts.push(log7.position.lineText);
467
+ if (log7.message) parts.push(log7.message);
468
+ return parts.length > 0 ? parts.join("\n") : String(log7);
467
469
  });
468
470
  return { code: "", success: false, errors };
469
471
  } catch (err) {
@@ -471,12 +473,12 @@ async function bundleWithBun(entrypoint, opts) {
471
473
  if (opts.throw) throw err;
472
474
  const errors = [];
473
475
  if (be.logs && Array.isArray(be.logs)) {
474
- for (const log6 of be.logs) {
476
+ for (const log7 of be.logs) {
475
477
  const parts = [];
476
- if (log6.position?.line) parts.push(`Line ${log6.position.line}:${log6.position.column || 0}`);
477
- if (log6.position?.lineText) parts.push(log6.position.lineText);
478
- if (log6.message) parts.push(log6.message);
479
- errors.push(parts.length > 0 ? parts.join("\n") : String(log6));
478
+ if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
479
+ if (log7.position?.lineText) parts.push(log7.position.lineText);
480
+ if (log7.message) parts.push(log7.message);
481
+ errors.push(parts.length > 0 ? parts.join("\n") : String(log7));
480
482
  }
481
483
  } else {
482
484
  errors.push(be.message || String(err));
@@ -486,8 +488,8 @@ async function bundleWithBun(entrypoint, opts) {
486
488
  }
487
489
  async function minifyWithBun(code) {
488
490
  const { writeFile: writeFile3, rm: _rm } = await import("node:fs/promises");
489
- const { join: join9 } = await import("node:path");
490
- const tempFile = join9("/tmp", `meno-minify-${Date.now()}.js`);
491
+ const { join: join10 } = await import("node:path");
492
+ const tempFile = join10("/tmp", `meno-minify-${Date.now()}.js`);
491
493
  try {
492
494
  await writeFile3(tempFile, code, "utf-8");
493
495
  const result = await Bun.build({
@@ -506,12 +508,12 @@ async function minifyWithBun(code) {
506
508
  const { inspect: inspect2 } = await import("../../chunks/fs-G3ANWEFP.js");
507
509
  let details = "";
508
510
  if (be.logs && Array.isArray(be.logs)) {
509
- details = be.logs.map((log6) => {
511
+ details = be.logs.map((log7) => {
510
512
  const parts = [];
511
- if (log6.position?.line) parts.push(`Line ${log6.position.line}:${log6.position.column || 0}`);
512
- if (log6.position?.lineText) parts.push(log6.position.lineText);
513
- if (log6.message) parts.push(log6.message);
514
- return parts.length > 0 ? parts.join("\n") : String(log6);
513
+ if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
514
+ if (log7.position?.lineText) parts.push(log7.position.lineText);
515
+ if (log7.message) parts.push(log7.message);
516
+ return parts.length > 0 ? parts.join("\n") : String(log7);
515
517
  }).join("\n\n");
516
518
  }
517
519
  if (!details) {
@@ -524,16 +526,16 @@ async function minifyWithBun(code) {
524
526
  return { code: "", success: false, errors: [details] };
525
527
  } finally {
526
528
  try {
527
- const { rm } = await import("node:fs/promises");
528
- await rm(tempFile, { force: true });
529
+ const { rm: rm2 } = await import("node:fs/promises");
530
+ await rm2(tempFile, { force: true });
529
531
  } catch {
530
532
  }
531
533
  }
532
534
  }
533
535
  async function validateWithBun(code) {
534
- const { writeFile: writeFile3, rm } = await import("node:fs/promises");
535
- const { join: join9 } = await import("node:path");
536
- const tempFile = join9("/tmp", `meno-validate-${Date.now()}-${Math.random().toString(36).slice(2)}.js`);
536
+ const { writeFile: writeFile3, rm: rm2 } = await import("node:fs/promises");
537
+ const { join: join10 } = await import("node:path");
538
+ const tempFile = join10("/tmp", `meno-validate-${Date.now()}-${Math.random().toString(36).slice(2)}.js`);
537
539
  try {
538
540
  await writeFile3(tempFile, code, "utf-8");
539
541
  await Bun.build({
@@ -547,12 +549,12 @@ async function validateWithBun(code) {
547
549
  const { inspect: inspect2 } = await import("../../chunks/fs-G3ANWEFP.js");
548
550
  let details = "";
549
551
  if (be.logs && Array.isArray(be.logs)) {
550
- details = be.logs.map((log6) => {
552
+ details = be.logs.map((log7) => {
551
553
  const parts = [];
552
- if (log6.position?.line) parts.push(`Line ${log6.position.line}:${log6.position.column || 0}`);
553
- if (log6.position?.lineText) parts.push(log6.position.lineText);
554
- if (log6.message) parts.push(log6.message);
555
- return parts.length > 0 ? parts.join("\n") : String(log6);
554
+ if (log7.position?.line) parts.push(`Line ${log7.position.line}:${log7.position.column || 0}`);
555
+ if (log7.position?.lineText) parts.push(log7.position.lineText);
556
+ if (log7.message) parts.push(log7.message);
557
+ return parts.length > 0 ? parts.join("\n") : String(log7);
556
558
  }).join("\n\n");
557
559
  }
558
560
  if (!details) {
@@ -565,7 +567,7 @@ async function validateWithBun(code) {
565
567
  return details || "Unknown JavaScript error";
566
568
  } finally {
567
569
  try {
568
- await rm(tempFile, { force: true });
570
+ await rm2(tempFile, { force: true });
569
571
  } catch {
570
572
  }
571
573
  }
@@ -1690,6 +1692,9 @@ async function handleComponentsConfigRoute() {
1690
1692
  }
1691
1693
  }
1692
1694
 
1695
+ // lib/server/services/ColorService.ts
1696
+ import { existsSync as existsSync3 } from "node:fs";
1697
+
1693
1698
  // lib/server/services/CachedConfigLoader.ts
1694
1699
  var CachedConfigLoader = class {
1695
1700
  config = null;
@@ -1730,8 +1735,511 @@ var CachedConfigLoader = class {
1730
1735
  }
1731
1736
  };
1732
1737
 
1738
+ // lib/server/themeCssStore.ts
1739
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
1740
+ import { rm } from "node:fs/promises";
1741
+ import { join as join2 } from "node:path";
1742
+
1743
+ // lib/server/themeCssCodec.ts
1744
+ var COLORS_LABEL = "Colors";
1745
+ var OTHER_LABEL = "Other";
1746
+ var HEADER_BANNER = `/*
1747
+ * Meno design tokens \u2014 theme.css is the source of truth for this project's colors and
1748
+ * variables. Edit values here, or use the Studio color/variable panels. Variables are
1749
+ * grouped by the comment sections below; the @media regions are regenerated on save
1750
+ * (responsive scaling is configured in project.config.json).
1751
+ */`;
1752
+ var AUTO_BANNER = "/* === Responsive scaling \u2014 auto-generated from project.config.json; regenerated on save === */";
1753
+ var OVERRIDES_BANNER = "/* === Responsive overrides \u2014 per-variable; preserved across regen === */";
1754
+ function sectionLabelForGroup(group) {
1755
+ if (!group || group === "other") return OTHER_LABEL;
1756
+ return VARIABLE_GROUPS.find((g) => g.value === group)?.label ?? OTHER_LABEL;
1757
+ }
1758
+ var LABEL_TO_GROUP = new Map(VARIABLE_GROUPS.map((g) => [g.label.toLowerCase(), g.value]));
1759
+ function groupForSectionLabel(label) {
1760
+ return LABEL_TO_GROUP.get(label.trim().toLowerCase()) ?? null;
1761
+ }
1762
+ function isColorValue(value) {
1763
+ const v = value.trim().toLowerCase();
1764
+ if (/^#[0-9a-f]{3,8}$/.test(v)) return true;
1765
+ if (/^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\(/.test(v)) return true;
1766
+ if (v === "transparent" || v === "currentcolor") return true;
1767
+ return false;
1768
+ }
1769
+ function inferGroup(cssVar, value) {
1770
+ const v = value.trim().toLowerCase();
1771
+ if (/^\d+(\.\d+)?m?s$/.test(v)) return "duration";
1772
+ if (/^(normal|bold|lighter|bolder)$/.test(v)) return "font-weight";
1773
+ if (/^\d+$/.test(v)) {
1774
+ const n = Number(v);
1775
+ if (n >= 100 && n <= 900 && n % 100 === 0) return "font-weight";
1776
+ }
1777
+ if (/^\d*\.\d+$/.test(v) || /^[1-9](\.\d+)?$/.test(v)) return "line-height";
1778
+ const name = cssVar.replace(/^--/, "").toLowerCase();
1779
+ for (const g of VARIABLE_GROUPS) {
1780
+ if (g.value !== "other" && name.includes(g.value)) return g.value;
1781
+ }
1782
+ return "other";
1783
+ }
1784
+ function groupVariables(variables) {
1785
+ const buckets = /* @__PURE__ */ new Map();
1786
+ for (const v of variables) {
1787
+ const label = sectionLabelForGroup(v.group);
1788
+ (buckets.get(label) ?? buckets.set(label, []).get(label)).push(v);
1789
+ }
1790
+ const ordered = [];
1791
+ for (const g of VARIABLE_GROUPS) {
1792
+ if (g.value === "other") continue;
1793
+ const vars = buckets.get(g.label);
1794
+ if (vars?.length) {
1795
+ ordered.push({ label: g.label, vars });
1796
+ buckets.delete(g.label);
1797
+ }
1798
+ }
1799
+ for (const [label, vars] of buckets) if (vars.length) ordered.push({ label, vars });
1800
+ return ordered;
1801
+ }
1802
+ function buildAutoMediaBlocks(scalable, cfg) {
1803
+ const { breakpoints, responsiveScales } = cfg;
1804
+ const baseRef = responsiveScales.baseReference || 16;
1805
+ const sorted = Object.entries(breakpoints).sort((a, b) => b[1].breakpoint - a[1].breakpoint);
1806
+ const blocks = [];
1807
+ for (const [bpName, bp] of sorted) {
1808
+ const lines = [];
1809
+ for (const v of scalable) {
1810
+ if (v.scales?.[bpName] !== void 0) continue;
1811
+ const categoryScales = responsiveScales[v.type];
1812
+ const scale = categoryScales?.[bpName];
1813
+ if (scale == null) continue;
1814
+ const scaled = scalePropertyValue(v.value, baseRef, scale);
1815
+ if (scaled !== null && scaled !== v.value) lines.push(` ${v.cssVar}: ${scaled};`);
1816
+ }
1817
+ if (lines.length) blocks.push(`@media (max-width: ${bp.breakpoint}px) {
1818
+ :root {
1819
+ ${lines.join("\n")}
1820
+ }
1821
+ }`);
1822
+ }
1823
+ return blocks.join("\n\n");
1824
+ }
1825
+ function buildOverrideMediaBlocks(variables, breakpoints) {
1826
+ const sorted = Object.entries(breakpoints).sort((a, b) => b[1].breakpoint - a[1].breakpoint);
1827
+ const blocks = [];
1828
+ for (const [bpName, bp] of sorted) {
1829
+ const lines = [];
1830
+ for (const v of variables) {
1831
+ const override = v.scales?.[bpName];
1832
+ if (override !== void 0 && override !== v.value) lines.push(` ${v.cssVar}: ${override};`);
1833
+ }
1834
+ if (lines.length) blocks.push(`@media (max-width: ${bp.breakpoint}px) {
1835
+ :root {
1836
+ ${lines.join("\n")}
1837
+ }
1838
+ }`);
1839
+ }
1840
+ return blocks.join("\n\n");
1841
+ }
1842
+ function serializeThemeCss(model, scaleConfig2) {
1843
+ const { themes, variables, raw = [] } = model;
1844
+ const palette = themes?.palette;
1845
+ const defaultName = themes?.default ?? "default";
1846
+ const defaultTheme = themes?.themes?.[defaultName];
1847
+ const sections = [];
1848
+ const colorEntries = Object.entries(defaultTheme?.colors ?? {});
1849
+ if (colorEntries.length) {
1850
+ sections.push(
1851
+ [
1852
+ ` /* ${COLORS_LABEL}: ${defaultName} */`,
1853
+ ...colorEntries.map(([k, val]) => ` --${k}: ${resolvePaletteColor(val, palette)};`)
1854
+ ].join("\n")
1855
+ );
1856
+ }
1857
+ for (const { label, vars } of groupVariables(variables)) {
1858
+ sections.push([` /* ${label} */`, ...vars.map((v) => ` ${v.cssVar}: ${v.value};`)].join("\n"));
1859
+ }
1860
+ const blocks = [HEADER_BANNER];
1861
+ blocks.push(sections.length ? `:root {
1862
+ ${sections.join("\n\n")}
1863
+ }` : ":root {}");
1864
+ for (const [name, theme] of Object.entries(themes?.themes ?? {})) {
1865
+ if (name === defaultName) continue;
1866
+ const lines = Object.entries(theme.colors ?? {}).map(
1867
+ ([k, val]) => ` --${k}: ${resolvePaletteColor(val, palette)};`
1868
+ );
1869
+ if (lines.length) blocks.push(`[theme="${name}"] {
1870
+ ${lines.join("\n")}
1871
+ }`);
1872
+ }
1873
+ if (scaleConfig2.responsiveScales?.enabled) {
1874
+ const auto = buildAutoMediaBlocks(
1875
+ variables.filter((v) => v.type && v.type !== "none"),
1876
+ scaleConfig2
1877
+ );
1878
+ if (auto) blocks.push(AUTO_BANNER, auto);
1879
+ }
1880
+ const overrides = buildOverrideMediaBlocks(variables, scaleConfig2.breakpoints);
1881
+ if (overrides) blocks.push(OVERRIDES_BANNER, overrides);
1882
+ for (const r of raw) {
1883
+ const t = r.trim();
1884
+ if (t) blocks.push(t);
1885
+ }
1886
+ return `${blocks.join("\n\n")}
1887
+ `;
1888
+ }
1889
+ function skipString(s, i) {
1890
+ const q = s[i];
1891
+ i++;
1892
+ while (i < s.length) {
1893
+ if (s[i] === "\\") {
1894
+ i += 2;
1895
+ continue;
1896
+ }
1897
+ if (s[i] === q) return i + 1;
1898
+ i++;
1899
+ }
1900
+ return i;
1901
+ }
1902
+ function readBlock(s, open) {
1903
+ let i = open + 1;
1904
+ let depth = 1;
1905
+ const bodyStart = i;
1906
+ while (i < s.length && depth > 0) {
1907
+ if (s[i] === "/" && s[i + 1] === "*") {
1908
+ const e = s.indexOf("*/", i + 2);
1909
+ i = e === -1 ? s.length : e + 2;
1910
+ continue;
1911
+ }
1912
+ if (s[i] === '"' || s[i] === "'") {
1913
+ i = skipString(s, i);
1914
+ continue;
1915
+ }
1916
+ if (s[i] === "{") depth++;
1917
+ else if (s[i] === "}") {
1918
+ depth--;
1919
+ if (depth === 0) break;
1920
+ }
1921
+ i++;
1922
+ }
1923
+ return { body: s.slice(bodyStart, i), end: i < s.length ? i + 1 : s.length };
1924
+ }
1925
+ function scanTopLevel(css) {
1926
+ const nodes = [];
1927
+ let i = 0;
1928
+ while (i < css.length) {
1929
+ while (i < css.length && /\s/.test(css[i])) i++;
1930
+ if (i >= css.length) break;
1931
+ if (css[i] === "/" && css[i + 1] === "*") {
1932
+ const e = css.indexOf("*/", i + 2);
1933
+ const stop = e === -1 ? css.length : e + 2;
1934
+ const text = css.slice(i, stop);
1935
+ nodes.push({ kind: "comment", text, raw: text });
1936
+ i = stop;
1937
+ continue;
1938
+ }
1939
+ const start = i;
1940
+ while (i < css.length) {
1941
+ const c = css[i];
1942
+ if (c === "/" && css[i + 1] === "*") {
1943
+ const e = css.indexOf("*/", i + 2);
1944
+ i = e === -1 ? css.length : e + 2;
1945
+ continue;
1946
+ }
1947
+ if (c === '"' || c === "'") {
1948
+ i = skipString(css, i);
1949
+ continue;
1950
+ }
1951
+ if (c === "{" || c === ";") break;
1952
+ i++;
1953
+ }
1954
+ if (i < css.length && css[i] === "{") {
1955
+ const prelude = css.slice(start, i).trim();
1956
+ const { body, end } = readBlock(css, i);
1957
+ nodes.push({ kind: "block", prelude, body, raw: css.slice(start, end) });
1958
+ i = end;
1959
+ } else {
1960
+ const stop = i < css.length ? i + 1 : css.length;
1961
+ const raw = css.slice(start, stop).trim();
1962
+ if (raw) nodes.push({ kind: "statement", raw });
1963
+ i = stop;
1964
+ }
1965
+ }
1966
+ return nodes;
1967
+ }
1968
+ function scanDeclarations(body) {
1969
+ const items = [];
1970
+ let i = 0;
1971
+ while (i < body.length) {
1972
+ while (i < body.length && /\s/.test(body[i])) i++;
1973
+ if (i >= body.length) break;
1974
+ if (body[i] === "/" && body[i + 1] === "*") {
1975
+ const e = body.indexOf("*/", i + 2);
1976
+ const stop = e === -1 ? body.length : e + 2;
1977
+ items.push({ kind: "comment", text: body.slice(i, stop) });
1978
+ i = stop;
1979
+ continue;
1980
+ }
1981
+ const start = i;
1982
+ while (i < body.length) {
1983
+ const c = body[i];
1984
+ if (c === "/" && body[i + 1] === "*") {
1985
+ const e = body.indexOf("*/", i + 2);
1986
+ i = e === -1 ? body.length : e + 2;
1987
+ continue;
1988
+ }
1989
+ if (c === '"' || c === "'") {
1990
+ i = skipString(body, i);
1991
+ continue;
1992
+ }
1993
+ if (c === ";") break;
1994
+ i++;
1995
+ }
1996
+ const text = body.slice(start, i).trim();
1997
+ i = i < body.length ? i + 1 : body.length;
1998
+ const colon = text.indexOf(":");
1999
+ if (colon > 0) {
2000
+ items.push({ kind: "decl", prop: text.slice(0, colon).trim(), value: text.slice(colon + 1).trim() });
2001
+ }
2002
+ }
2003
+ return items;
2004
+ }
2005
+ function commentInner(text) {
2006
+ return text.replace(/^\/\*+/, "").replace(/\*+\/$/, "").trim();
2007
+ }
2008
+ function isHeaderBanner(text) {
2009
+ const t = commentInner(text);
2010
+ return /meno design tokens/i.test(t) || /AUTO-GENERATED by meno-astro/i.test(t);
2011
+ }
2012
+ function prettifyName(name) {
2013
+ return name.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (c) => c.toUpperCase());
2014
+ }
2015
+ function maxWidthPx(prelude) {
2016
+ const m = prelude.match(/max-width:\s*(\d+)px/i);
2017
+ return m ? Number(m[1]) : null;
2018
+ }
2019
+ function bpNameForPx(px, breakpoints) {
2020
+ for (const [name, entry] of Object.entries(breakpoints)) if (entry.breakpoint === px) return name;
2021
+ return null;
2022
+ }
2023
+ function parseThemeCss(css, breakpoints) {
2024
+ const themesMap = {};
2025
+ const variables = [];
2026
+ const varByCssVar = /* @__PURE__ */ new Map();
2027
+ const raw = [];
2028
+ let defaultName = null;
2029
+ let region = null;
2030
+ for (const node of scanTopLevel(css)) {
2031
+ if (node.kind === "comment") {
2032
+ if (isHeaderBanner(node.text)) continue;
2033
+ const inner = commentInner(node.text);
2034
+ if (/responsive overrides/i.test(inner)) {
2035
+ region = "overrides";
2036
+ continue;
2037
+ }
2038
+ if (/responsive scaling|auto-generated from project\.config/i.test(inner)) {
2039
+ region = "auto";
2040
+ continue;
2041
+ }
2042
+ raw.push(node.raw);
2043
+ continue;
2044
+ }
2045
+ if (node.kind === "statement") {
2046
+ raw.push(node.raw);
2047
+ continue;
2048
+ }
2049
+ const sel = node.prelude;
2050
+ if (sel === ":root") {
2051
+ let section = null;
2052
+ for (const it of scanDeclarations(node.body)) {
2053
+ if (it.kind === "comment") {
2054
+ const inner = commentInner(it.text);
2055
+ if (/^colors\b/i.test(inner)) {
2056
+ section = "colors";
2057
+ const dn = inner.match(/^colors\s*:\s*([\w-]+)/i);
2058
+ if (dn) defaultName = dn[1];
2059
+ } else {
2060
+ const g = groupForSectionLabel(inner);
2061
+ if (g) section = g;
2062
+ }
2063
+ continue;
2064
+ }
2065
+ if (!it.prop.startsWith("--")) continue;
2066
+ const name = it.prop.slice(2);
2067
+ if (section === "colors" || section === null && isColorValue(it.value)) {
2068
+ const dn = defaultName ??= "default";
2069
+ (themesMap[dn] ??= { colors: {} }).colors[name] = it.value;
2070
+ } else {
2071
+ const group = section ?? inferGroup(it.prop, it.value);
2072
+ const v = { cssVar: it.prop, value: it.value, type: getDefaultScalingType(group), group };
2073
+ variables.push(v);
2074
+ varByCssVar.set(it.prop, v);
2075
+ }
2076
+ }
2077
+ continue;
2078
+ }
2079
+ const themeMatch = sel.match(/^\[theme=["']?([^"'\]]+)["']?\]$/);
2080
+ if (themeMatch) {
2081
+ const theme = themesMap[themeMatch[1]] ??= { colors: {} };
2082
+ for (const it of scanDeclarations(node.body)) {
2083
+ if (it.kind === "decl" && it.prop.startsWith("--")) theme.colors[it.prop.slice(2)] = it.value;
2084
+ }
2085
+ continue;
2086
+ }
2087
+ if (/^@media\b/i.test(sel)) {
2088
+ const px = maxWidthPx(sel);
2089
+ if (region === "auto") continue;
2090
+ const bpName = px != null && breakpoints ? bpNameForPx(px, breakpoints) : null;
2091
+ if (!bpName) {
2092
+ raw.push(node.raw);
2093
+ continue;
2094
+ }
2095
+ for (const inner of scanTopLevel(node.body)) {
2096
+ if (inner.kind !== "block" || inner.prelude !== ":root") continue;
2097
+ for (const it of scanDeclarations(inner.body)) {
2098
+ if (it.kind !== "decl" || !it.prop.startsWith("--")) continue;
2099
+ const v = varByCssVar.get(it.prop);
2100
+ if (v) (v.scales ??= {})[bpName] = it.value;
2101
+ }
2102
+ }
2103
+ continue;
2104
+ }
2105
+ raw.push(node.raw);
2106
+ }
2107
+ if (!defaultName) defaultName = Object.keys(themesMap)[0] ?? "default";
2108
+ (themesMap[defaultName] ??= { colors: {} }).label ??= prettifyName(defaultName);
2109
+ for (const [name, t] of Object.entries(themesMap)) t.label ??= prettifyName(name);
2110
+ return { themes: { default: defaultName, themes: themesMap }, variables, raw };
2111
+ }
2112
+
2113
+ // lib/server/themeCssStore.ts
2114
+ var log2 = createLogger("themeCssStore");
2115
+ function themeCssPath(root = getProjectRoot()) {
2116
+ return join2(root, "src", "styles", "theme.css");
2117
+ }
2118
+ function isThemeCssProject(root = getProjectRoot()) {
2119
+ if (existsSync2(themeCssPath(root))) return true;
2120
+ if (existsSync2(join2(root, "src", "pages"))) return true;
2121
+ try {
2122
+ const cfg = JSON.parse(readFileSync(join2(root, "project.config.json"), "utf8"));
2123
+ if (cfg.format === "astro") return true;
2124
+ } catch {
2125
+ }
2126
+ return false;
2127
+ }
2128
+ var writeChain = Promise.resolve();
2129
+ function enqueue(fn) {
2130
+ const run = writeChain.then(fn, fn);
2131
+ writeChain = run.then(
2132
+ () => void 0,
2133
+ () => void 0
2134
+ );
2135
+ return run;
2136
+ }
2137
+ async function readJsonSafe(path3) {
2138
+ try {
2139
+ return JSON.parse(await readTextFile(path3));
2140
+ } catch {
2141
+ return null;
2142
+ }
2143
+ }
2144
+ function scaleConfig() {
2145
+ return { breakpoints: configService.getBreakpoints(), responsiveScales: configService.getResponsiveScales() };
2146
+ }
2147
+ function emptyModel() {
2148
+ return { themes: { default: "default", themes: { default: { colors: {} } } }, variables: [], raw: [] };
2149
+ }
2150
+ async function readModel(root) {
2151
+ const path3 = themeCssPath(root);
2152
+ if (!await fileExists(path3)) return emptyModel();
2153
+ return parseThemeCss(await readTextFile(path3), configService.getBreakpoints());
2154
+ }
2155
+ async function writeModel(root, model) {
2156
+ const css = serializeThemeCss(model, scaleConfig());
2157
+ await ensureDir(join2(root, "src", "styles"));
2158
+ await writeFile(themeCssPath(root), css);
2159
+ }
2160
+ function hasColors(themes) {
2161
+ return Object.values(themes.themes ?? {}).some((t) => Object.keys(t.colors ?? {}).length > 0);
2162
+ }
2163
+ function mergeThemes(current, incoming) {
2164
+ if (!incoming?.themes) return current;
2165
+ if (!hasColors(current)) return incoming;
2166
+ const out = { default: current.default, palette: current.palette, themes: { ...current.themes } };
2167
+ for (const [name, theme] of Object.entries(incoming.themes)) {
2168
+ const existing = out.themes[name];
2169
+ out.themes[name] = existing ? { ...existing, colors: { ...theme.colors, ...existing.colors } } : theme;
2170
+ }
2171
+ return out;
2172
+ }
2173
+ function mergeVariables(current, incoming) {
2174
+ if (!incoming?.length) return current;
2175
+ const seen = new Set(current.map((v) => v.cssVar));
2176
+ return [...current, ...incoming.filter((v) => !seen.has(v.cssVar))];
2177
+ }
2178
+ var AUTHORED_MARKER = "Meno design tokens";
2179
+ async function migrateIfNeeded(root) {
2180
+ const colorsJson = join2(root, "colors.json");
2181
+ const variablesJson = join2(root, "variables.json");
2182
+ const hasColorsJson = existsSync2(colorsJson);
2183
+ const hasVarsJson = existsSync2(variablesJson);
2184
+ if (!hasColorsJson && !hasVarsJson) return;
2185
+ try {
2186
+ const jsonColors = hasColorsJson ? await readJsonSafe(colorsJson) : null;
2187
+ const jsonVars = hasVarsJson ? await readJsonSafe(variablesJson) : null;
2188
+ let current = emptyModel();
2189
+ let authored = false;
2190
+ if (await fileExists(themeCssPath(root))) {
2191
+ const text = await readTextFile(themeCssPath(root));
2192
+ authored = text.includes(AUTHORED_MARKER);
2193
+ current = parseThemeCss(text, configService.getBreakpoints());
2194
+ }
2195
+ const base = authored ? current : emptyModel();
2196
+ const merged = {
2197
+ themes: mergeThemes(base.themes, jsonColors?.themes ? jsonColors : null),
2198
+ variables: mergeVariables(base.variables, jsonVars?.variables),
2199
+ raw: current.raw
2200
+ };
2201
+ await writeModel(root, merged);
2202
+ await rm(colorsJson, { force: true });
2203
+ await rm(variablesJson, { force: true });
2204
+ log2.info("Folded colors.json / variables.json into src/styles/theme.css");
2205
+ } catch (err) {
2206
+ log2.warn("theme.css migration failed; keeping JSON files:", err);
2207
+ }
2208
+ }
2209
+ async function loadThemeModel(root = getProjectRoot()) {
2210
+ await configService.load();
2211
+ return enqueue(async () => {
2212
+ await migrateIfNeeded(root);
2213
+ return readModel(root);
2214
+ });
2215
+ }
2216
+ async function saveColors(themes, root = getProjectRoot()) {
2217
+ await configService.load();
2218
+ return enqueue(async () => {
2219
+ await migrateIfNeeded(root);
2220
+ const current = await readModel(root);
2221
+ await writeModel(root, { themes, variables: current.variables, raw: current.raw });
2222
+ });
2223
+ }
2224
+ async function saveVariables(variables, root = getProjectRoot()) {
2225
+ await configService.load();
2226
+ return enqueue(async () => {
2227
+ await migrateIfNeeded(root);
2228
+ const current = await readModel(root);
2229
+ await writeModel(root, { themes: current.themes, variables, raw: current.raw });
2230
+ });
2231
+ }
2232
+ async function regenerateThemeCss(root = getProjectRoot()) {
2233
+ await configService.load();
2234
+ return enqueue(async () => {
2235
+ await migrateIfNeeded(root);
2236
+ if (!await fileExists(themeCssPath(root))) return;
2237
+ await writeModel(root, await readModel(root));
2238
+ });
2239
+ }
2240
+
1733
2241
  // lib/server/services/ColorService.ts
1734
- var log2 = createLogger("ColorService");
2242
+ var log3 = createLogger("ColorService");
1735
2243
  var ColorService = class extends CachedConfigLoader {
1736
2244
  /**
1737
2245
  * Load theme configuration from colors.json
@@ -1740,9 +2248,19 @@ var ColorService = class extends CachedConfigLoader {
1740
2248
  return this.load();
1741
2249
  }
1742
2250
  /**
1743
- * Perform the actual loading from file
2251
+ * Perform the actual loading from file.
2252
+ * Astro projects read colors from `src/styles/theme.css` (the token source of truth);
2253
+ * legacy JSON projects read `colors.json`.
1744
2254
  */
1745
2255
  async performLoad() {
2256
+ if (isThemeCssProject()) {
2257
+ try {
2258
+ return (await loadThemeModel()).themes;
2259
+ } catch (error) {
2260
+ log3.warn("Failed to load colors from theme.css:", error);
2261
+ return this.getDefaultThemeConfig();
2262
+ }
2263
+ }
1746
2264
  try {
1747
2265
  const content = await loadJSONFile(projectPaths.colors());
1748
2266
  if (content) {
@@ -1752,7 +2270,7 @@ var ColorService = class extends CachedConfigLoader {
1752
2270
  }
1753
2271
  }
1754
2272
  } catch (error) {
1755
- log2.warn("Failed to load colors.json:", error);
2273
+ log3.warn("Failed to load colors.json:", error);
1756
2274
  }
1757
2275
  return this.getDefaultThemeConfig();
1758
2276
  }
@@ -1832,6 +2350,23 @@ var ColorService = class extends CachedConfigLoader {
1832
2350
  * Distinguishes between missing file, invalid JSON, and valid config
1833
2351
  */
1834
2352
  async getConfigWithStatus() {
2353
+ if (isThemeCssProject()) {
2354
+ const filePath2 = themeCssPath();
2355
+ if (!existsSync3(filePath2)) {
2356
+ return { status: "missing", config: this.getMinimalConfig(), filePath: filePath2 };
2357
+ }
2358
+ try {
2359
+ const model = await loadThemeModel();
2360
+ return { status: "valid", config: model.themes, filePath: filePath2 };
2361
+ } catch (error) {
2362
+ return {
2363
+ status: "invalid",
2364
+ config: this.getMinimalConfig(),
2365
+ error: error instanceof Error ? error.message : "Parse error",
2366
+ filePath: filePath2
2367
+ };
2368
+ }
2369
+ }
1835
2370
  const filePath = projectPaths.colors();
1836
2371
  try {
1837
2372
  const content = await loadJSONFile(filePath);
@@ -1882,7 +2417,7 @@ var ColorService = class extends CachedConfigLoader {
1882
2417
  const config = await this.loadThemeConfig();
1883
2418
  return Object.entries(config.themes).map(([name, theme]) => ({
1884
2419
  name,
1885
- label: theme.label
2420
+ label: theme.label ?? name
1886
2421
  }));
1887
2422
  }
1888
2423
  /**
@@ -1916,12 +2451,15 @@ var ColorService = class extends CachedConfigLoader {
1916
2451
  return this.loadThemeConfig();
1917
2452
  }
1918
2453
  /**
1919
- * Save theme configuration to colors.json
2454
+ * Save theme configuration. Astro projects write the colors half of
2455
+ * `src/styles/theme.css` (preserving variables); legacy JSON projects write `colors.json`.
1920
2456
  */
1921
2457
  async saveThemeConfig(config) {
1922
- const colorsPath = projectPaths.colors();
1923
- const content = JSON.stringify(config, null, 2);
1924
- await writeFile(colorsPath, content);
2458
+ if (isThemeCssProject()) {
2459
+ await saveColors(config);
2460
+ } else {
2461
+ await writeFile(projectPaths.colors(), JSON.stringify(config, null, 2));
2462
+ }
1925
2463
  this.setCache(config);
1926
2464
  }
1927
2465
  };
@@ -1948,7 +2486,8 @@ async function handleColorsStatusRoute() {
1948
2486
  }
1949
2487
 
1950
2488
  // lib/server/services/VariableService.ts
1951
- var log3 = createLogger("VariableService");
2489
+ import { existsSync as existsSync4 } from "node:fs";
2490
+ var log4 = createLogger("VariableService");
1952
2491
  var VariableService = class extends CachedConfigLoader {
1953
2492
  /**
1954
2493
  * Load variables configuration from variables.json
@@ -1957,6 +2496,14 @@ var VariableService = class extends CachedConfigLoader {
1957
2496
  return this.load();
1958
2497
  }
1959
2498
  async performLoad() {
2499
+ if (isThemeCssProject()) {
2500
+ try {
2501
+ return { variables: (await loadThemeModel()).variables };
2502
+ } catch (error) {
2503
+ log4.warn("Failed to load variables from theme.css:", error);
2504
+ return this.getDefaultConfig();
2505
+ }
2506
+ }
1960
2507
  try {
1961
2508
  const content = await loadJSONFile(projectPaths.variables());
1962
2509
  if (content) {
@@ -1966,7 +2513,7 @@ var VariableService = class extends CachedConfigLoader {
1966
2513
  }
1967
2514
  }
1968
2515
  } catch (error) {
1969
- log3.warn("Failed to load variables.json:", error);
2516
+ log4.warn("Failed to load variables.json:", error);
1970
2517
  }
1971
2518
  return this.getDefaultConfig();
1972
2519
  }
@@ -1979,7 +2526,7 @@ var VariableService = class extends CachedConfigLoader {
1979
2526
  migrateConfig(config) {
1980
2527
  for (const variable of config.variables) {
1981
2528
  if (variable.group === "spacing") {
1982
- const lower = `${variable.cssVar} ${variable.name}`.toLowerCase();
2529
+ const lower = `${variable.cssVar} ${variable.name ?? ""}`.toLowerCase();
1983
2530
  if (lower.includes("margin")) {
1984
2531
  variable.group = "margin";
1985
2532
  } else if (lower.includes("gap")) {
@@ -1995,6 +2542,22 @@ var VariableService = class extends CachedConfigLoader {
1995
2542
  * Get config with status info (for editor UI)
1996
2543
  */
1997
2544
  async getConfigWithStatus() {
2545
+ if (isThemeCssProject()) {
2546
+ const filePath2 = themeCssPath();
2547
+ if (!existsSync4(filePath2)) {
2548
+ return { status: "missing", config: this.getDefaultConfig(), filePath: filePath2 };
2549
+ }
2550
+ try {
2551
+ return { status: "valid", config: { variables: (await loadThemeModel()).variables }, filePath: filePath2 };
2552
+ } catch (error) {
2553
+ return {
2554
+ status: "invalid",
2555
+ config: this.getDefaultConfig(),
2556
+ error: error instanceof Error ? error.message : "Parse error",
2557
+ filePath: filePath2
2558
+ };
2559
+ }
2560
+ }
1998
2561
  const filePath = projectPaths.variables();
1999
2562
  try {
2000
2563
  const content = await loadJSONFile(filePath);
@@ -2021,12 +2584,15 @@ var VariableService = class extends CachedConfigLoader {
2021
2584
  }
2022
2585
  }
2023
2586
  /**
2024
- * Save variables configuration to variables.json
2587
+ * Save variables configuration. Astro projects write the variables half of
2588
+ * `src/styles/theme.css` (preserving colors); legacy JSON projects write `variables.json`.
2025
2589
  */
2026
2590
  async saveConfig(config) {
2027
- const variablesPath = projectPaths.variables();
2028
- const content = JSON.stringify(config, null, 2);
2029
- await writeFile(variablesPath, content);
2591
+ if (isThemeCssProject()) {
2592
+ await saveVariables(config.variables);
2593
+ } else {
2594
+ await writeFile(projectPaths.variables(), JSON.stringify(config, null, 2));
2595
+ }
2030
2596
  this.setCache(config);
2031
2597
  }
2032
2598
  };
@@ -2142,7 +2708,7 @@ async function handleVariablesCSSRoute() {
2142
2708
  }
2143
2709
 
2144
2710
  // lib/server/services/EnumService.ts
2145
- var log4 = createLogger("EnumService");
2711
+ var log5 = createLogger("EnumService");
2146
2712
  var EnumService = class extends CachedConfigLoader {
2147
2713
  /**
2148
2714
  * Load enums configuration from enums.json
@@ -2162,7 +2728,7 @@ var EnumService = class extends CachedConfigLoader {
2162
2728
  return this.validateEnums(data);
2163
2729
  }
2164
2730
  } catch (error) {
2165
- log4.warn("Failed to parse enums.json:", error);
2731
+ log5.warn("Failed to parse enums.json:", error);
2166
2732
  }
2167
2733
  }
2168
2734
  if (configContent) {
@@ -4237,7 +4803,8 @@ async function renderNode(node, ctx) {
4237
4803
  const nodeAttributesWithoutClass = { ...nodeAttributes };
4238
4804
  delete nodeAttributesWithoutClass.className;
4239
4805
  delete nodeAttributesWithoutClass.class;
4240
- const allClassNames = [elementClass, attrClassName, ...utilityClasses].filter(Boolean);
4806
+ const instanceClassName = typeof nodeProps.class === "string" ? nodeProps.class : "";
4807
+ const allClassNames = [elementClass, attrClassName, ...utilityClasses, instanceClassName].filter(Boolean);
4241
4808
  const mergedClassName = allClassNames.length > 0 ? allClassNames.join(" ") : "";
4242
4809
  const propsWithStyleAndAttrs = {
4243
4810
  ...nodeProps,
@@ -5043,17 +5610,25 @@ ${escapedJavaScript}
5043
5610
  const themeConfig = await colorService.loadThemeConfig();
5044
5611
  const themeColorVariablesCSS = generateThemeColorVariablesCSS(themeConfig);
5045
5612
  const componentCSS = rendered.componentCSS || "";
5046
- const usedUtilityClasses = extractUtilityClassesFromHTML(rendered.html);
5047
5613
  const breakpointConfig = await loadBreakpointConfig();
5048
5614
  const responsiveScalesConfig = configService.getResponsiveScales();
5049
5615
  const variablesConfig = await variableService.loadConfig();
5050
5616
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
5051
5617
  const remConversionConfig = configService.getRemConversion();
5618
+ const knownTokens = /* @__PURE__ */ new Set();
5619
+ for (const theme of Object.values(themeConfig.themes)) {
5620
+ for (const name of Object.keys(theme.colors)) knownTokens.add(name);
5621
+ }
5622
+ for (const variable of variablesConfig.variables) {
5623
+ if (variable.cssVar) knownTokens.add(variable.cssVar.replace(/^--/, ""));
5624
+ }
5625
+ const usedUtilityClasses = extractUtilityClassesFromHTML(rendered.html, knownTokens);
5052
5626
  const utilityCSS = generateUtilityCSS(
5053
5627
  usedUtilityClasses,
5054
5628
  breakpointConfig,
5055
5629
  responsiveScalesConfig,
5056
- remConversionConfig
5630
+ remConversionConfig,
5631
+ knownTokens
5057
5632
  );
5058
5633
  const interactiveCSS = rendered.interactiveStylesMap.size > 0 ? generateAllInteractiveCSS(
5059
5634
  rendered.interactiveStylesMap,
@@ -8431,8 +9006,8 @@ ${plainTextErrors}`;
8431
9006
  }
8432
9007
 
8433
9008
  // lib/server/services/pageService.ts
8434
- import { existsSync as existsSync2, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
8435
- import { join as join3 } from "node:path";
9009
+ import { existsSync as existsSync5, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
9010
+ import { join as join4 } from "node:path";
8436
9011
 
8437
9012
  // lib/server/utils/jsonLineMapper.ts
8438
9013
  function buildLineMap(jsonText) {
@@ -8844,7 +9419,7 @@ var PageService = class {
8844
9419
  */
8845
9420
  getAllFolders() {
8846
9421
  const pagesDir = this.pagesBaseDir();
8847
- if (!existsSync2(pagesDir)) {
9422
+ if (!existsSync5(pagesDir)) {
8848
9423
  return [];
8849
9424
  }
8850
9425
  const collectFolders = (dir, prefix) => {
@@ -8855,7 +9430,7 @@ var PageService = class {
8855
9430
  if (!entry.isDirectory()) continue;
8856
9431
  const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
8857
9432
  result.push(relativePath);
8858
- result.push(...collectFolders(join3(dir, entry.name), relativePath));
9433
+ result.push(...collectFolders(join4(dir, entry.name), relativePath));
8859
9434
  }
8860
9435
  return result;
8861
9436
  } catch {
@@ -8886,8 +9461,8 @@ var PageService = class {
8886
9461
  }
8887
9462
  }
8888
9463
  const pagesDir = this.pagesBaseDir();
8889
- const folderPath = join3(pagesDir, trimmed);
8890
- if (existsSync2(folderPath)) {
9464
+ const folderPath = join4(pagesDir, trimmed);
9465
+ if (existsSync5(folderPath)) {
8891
9466
  throw new Error("Folder already exists");
8892
9467
  }
8893
9468
  mkdirSync(folderPath, { recursive: true });
@@ -8908,18 +9483,18 @@ var PageService = class {
8908
9483
  const pageName = pagePath === "/" ? "index" : pagePath.substring(1);
8909
9484
  const slashIndex = pageName.lastIndexOf("/");
8910
9485
  const baseName = slashIndex >= 0 ? pageName.substring(slashIndex + 1) : pageName;
8911
- const sourceFile = join3(pagesDir, `${pageName}${ext}`);
8912
- const targetFile = newFolder ? join3(pagesDir, newFolder, `${baseName}${ext}`) : join3(pagesDir, `${baseName}${ext}`);
9486
+ const sourceFile = join4(pagesDir, `${pageName}${ext}`);
9487
+ const targetFile = newFolder ? join4(pagesDir, newFolder, `${baseName}${ext}`) : join4(pagesDir, `${baseName}${ext}`);
8913
9488
  if (!isPathWithinRoot(sourceFile, pagesDir) || !isPathWithinRoot(targetFile, pagesDir)) {
8914
9489
  throw new Error(`movePage path escapes pages dir: ${pagePath} -> ${newFolder}`);
8915
9490
  }
8916
9491
  if (newFolder) {
8917
- const targetDir = join3(pagesDir, newFolder);
8918
- if (!existsSync2(targetDir)) {
9492
+ const targetDir = join4(pagesDir, newFolder);
9493
+ if (!existsSync5(targetDir)) {
8919
9494
  mkdirSync(targetDir, { recursive: true });
8920
9495
  }
8921
9496
  }
8922
- if (!existsSync2(sourceFile)) {
9497
+ if (!existsSync5(sourceFile)) {
8923
9498
  throw new Error(`Page not found: ${pagePath}`);
8924
9499
  }
8925
9500
  await rename2(sourceFile, targetFile);
@@ -8931,7 +9506,7 @@ var PageService = class {
8931
9506
  const lineMap = buildLineMap(content);
8932
9507
  this.pageCache.set(newPath, content, lineMap);
8933
9508
  }
8934
- const sourceDir = slashIndex >= 0 ? join3(pagesDir, pageName.substring(0, slashIndex)) : null;
9509
+ const sourceDir = slashIndex >= 0 ? join4(pagesDir, pageName.substring(0, slashIndex)) : null;
8935
9510
  if (sourceDir && sourceDir !== pagesDir) {
8936
9511
  try {
8937
9512
  const remaining = readdirSync2(sourceDir);
@@ -8980,12 +9555,12 @@ var PageService = class {
8980
9555
  const { rename: rename2 } = await import("node:fs/promises");
8981
9556
  const pagesDir = this.pagesBaseDir();
8982
9557
  const ext = this.pageExt();
8983
- const sourceFile = join3(pagesDir, `${oldName}${ext}`);
8984
- const targetFile = join3(pagesDir, `${newName}${ext}`);
8985
- if (!existsSync2(sourceFile)) {
9558
+ const sourceFile = join4(pagesDir, `${oldName}${ext}`);
9559
+ const targetFile = join4(pagesDir, `${newName}${ext}`);
9560
+ if (!existsSync5(sourceFile)) {
8986
9561
  throw new Error(`Page not found: ${oldPath}`);
8987
9562
  }
8988
- if (existsSync2(targetFile)) {
9563
+ if (existsSync5(targetFile)) {
8989
9564
  throw new Error(`Page already exists: ${newPath}`);
8990
9565
  }
8991
9566
  await rename2(sourceFile, targetFile);
@@ -9035,8 +9610,8 @@ var PageService = class {
9035
9610
  };
9036
9611
 
9037
9612
  // lib/server/services/componentService.ts
9038
- import { join as join4 } from "node:path";
9039
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmdirSync as rmdirSync2 } from "node:fs";
9613
+ import { join as join5 } from "node:path";
9614
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmdirSync as rmdirSync2 } from "node:fs";
9040
9615
  var ComponentService = class {
9041
9616
  components = /* @__PURE__ */ new Map();
9042
9617
  componentCategories = /* @__PURE__ */ new Map();
@@ -9268,7 +9843,7 @@ var ComponentService = class {
9268
9843
  const componentsDir = this.componentsBaseDir();
9269
9844
  if (!isSafePathSegment(name)) throw new Error(`unsafe component name: ${name}`);
9270
9845
  const cat = this.resolveComponentCategory(name, category);
9271
- const dir = cat ? join4(componentsDir, cat) : componentsDir;
9846
+ const dir = cat ? join5(componentsDir, cat) : componentsDir;
9272
9847
  if (!isPathWithinRoot(dir, componentsDir)) throw new Error(`component category escapes components dir: ${cat}`);
9273
9848
  return dir;
9274
9849
  }
@@ -9299,10 +9874,10 @@ var ComponentService = class {
9299
9874
  */
9300
9875
  findComponentCategoryOnDisk(name) {
9301
9876
  const componentsDir = this.componentsBaseDir();
9302
- if (!existsSync3(componentsDir)) return void 0;
9877
+ if (!existsSync6(componentsDir)) return void 0;
9303
9878
  const ext = this.writer ? null : ".json";
9304
9879
  const existsAt = (dir) => {
9305
- if (ext) return existsSync3(join4(dir, `${name}${ext}`));
9880
+ if (ext) return existsSync6(join5(dir, `${name}${ext}`));
9306
9881
  try {
9307
9882
  return readdirSync3(dir, { withFileTypes: true }).some(
9308
9883
  (e) => e.isFile() && (e.name === `${name}.json` || e.name === `${name}.astro`)
@@ -9314,7 +9889,7 @@ var ComponentService = class {
9314
9889
  if (existsAt(componentsDir)) return void 0;
9315
9890
  try {
9316
9891
  for (const entry of readdirSync3(componentsDir, { withFileTypes: true })) {
9317
- if (entry.isDirectory() && existsAt(join4(componentsDir, entry.name))) {
9892
+ if (entry.isDirectory() && existsAt(join5(componentsDir, entry.name))) {
9318
9893
  return entry.name;
9319
9894
  }
9320
9895
  }
@@ -9341,7 +9916,7 @@ var ComponentService = class {
9341
9916
  */
9342
9917
  async getComponentJavaScript(name) {
9343
9918
  const componentDir = this.getComponentDir(name);
9344
- const jsFilePath = join4(componentDir, `${name}.js`);
9919
+ const jsFilePath = join5(componentDir, `${name}.js`);
9345
9920
  try {
9346
9921
  if (await fileExists(jsFilePath)) {
9347
9922
  return await readTextFile(jsFilePath);
@@ -9389,15 +9964,15 @@ var ComponentService = class {
9389
9964
  const dataWithJS = javascript !== void 0 ? { ...dataWithoutJS, component: { ...dataWithoutJS.component, javascript } } : dataWithoutJS;
9390
9965
  const targetCategory = this.resolveComponentCategory(name, category);
9391
9966
  const componentsDir = this.componentsBaseDir();
9392
- const componentDir = targetCategory ? join4(componentsDir, targetCategory) : componentsDir;
9967
+ const componentDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
9393
9968
  if (this.writer) {
9394
9969
  await this.writer.writeComponent(componentDir, name, dataWithJS);
9395
9970
  } else {
9396
9971
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9397
- if (targetCategory && !existsSync3(componentDir)) {
9972
+ if (targetCategory && !existsSync6(componentDir)) {
9398
9973
  mkdirSync2(componentDir, { recursive: true });
9399
9974
  }
9400
- const filePath = join4(componentDir, `${name}.json`);
9975
+ const filePath = join5(componentDir, `${name}.json`);
9401
9976
  await writeFile3(filePath, JSON.stringify(dataWithoutJS, null, 2), "utf-8");
9402
9977
  }
9403
9978
  this.components.set(name, dataWithJS);
@@ -9430,9 +10005,9 @@ var ComponentService = class {
9430
10005
  return;
9431
10006
  }
9432
10007
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9433
- const jsFilePath = join4(componentDir, `${name}.js`);
10008
+ const jsFilePath = join5(componentDir, `${name}.js`);
9434
10009
  await writeFile3(jsFilePath, javascript || "", "utf-8");
9435
- const componentPath = join4(componentDir, `${name}.json`);
10010
+ const componentPath = join5(componentDir, `${name}.json`);
9436
10011
  const componentData = await loadJSONFile(componentPath);
9437
10012
  if (componentData) {
9438
10013
  const parsed = parseJSON(componentData);
@@ -9476,9 +10051,9 @@ var ComponentService = class {
9476
10051
  return;
9477
10052
  }
9478
10053
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9479
- const cssFilePath = join4(componentDir, `${name}.css`);
10054
+ const cssFilePath = join5(componentDir, `${name}.css`);
9480
10055
  await writeFile3(cssFilePath, css || "", "utf-8");
9481
- const componentPath = join4(componentDir, `${name}.json`);
10056
+ const componentPath = join5(componentDir, `${name}.json`);
9482
10057
  const componentData = await loadJSONFile(componentPath);
9483
10058
  if (componentData) {
9484
10059
  const parsed = parseJSON(componentData);
@@ -9511,7 +10086,7 @@ var ComponentService = class {
9511
10086
  */
9512
10087
  getAllFolders() {
9513
10088
  const componentsDir = this.componentsBaseDir();
9514
- if (!existsSync3(componentsDir)) {
10089
+ if (!existsSync6(componentsDir)) {
9515
10090
  return [];
9516
10091
  }
9517
10092
  try {
@@ -9546,8 +10121,8 @@ var ComponentService = class {
9546
10121
  throw new Error("Folder name can only contain lowercase letters, numbers, dashes, and underscores");
9547
10122
  }
9548
10123
  const componentsDir = this.componentsBaseDir();
9549
- const folderPath = join4(componentsDir, folderName);
9550
- if (existsSync3(folderPath)) {
10124
+ const folderPath = join5(componentsDir, folderName);
10125
+ if (existsSync6(folderPath)) {
9551
10126
  throw new Error("Folder already exists");
9552
10127
  }
9553
10128
  mkdirSync2(folderPath, { recursive: true });
@@ -9580,20 +10155,20 @@ var ComponentService = class {
9580
10155
  return;
9581
10156
  }
9582
10157
  const componentsDir = this.componentsBaseDir();
9583
- const sourceDir = currentCategory ? join4(componentsDir, currentCategory) : componentsDir;
9584
- const targetDir = targetCategory ? join4(componentsDir, targetCategory) : componentsDir;
10158
+ const sourceDir = currentCategory ? join5(componentsDir, currentCategory) : componentsDir;
10159
+ const targetDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
9585
10160
  if (this.writer) {
9586
10161
  await this.writer.moveComponent(sourceDir, targetDir, name);
9587
10162
  } else {
9588
- if (targetCategory && !existsSync3(targetDir)) {
10163
+ if (targetCategory && !existsSync6(targetDir)) {
9589
10164
  mkdirSync2(targetDir, { recursive: true });
9590
10165
  }
9591
10166
  const extensions = [".json", ".js", ".css"];
9592
10167
  const { rename: rename2 } = await import("node:fs/promises");
9593
10168
  for (const ext of extensions) {
9594
- const sourcePath = join4(sourceDir, `${name}${ext}`);
9595
- const targetPath = join4(targetDir, `${name}${ext}`);
9596
- if (existsSync3(sourcePath)) {
10169
+ const sourcePath = join5(sourceDir, `${name}${ext}`);
10170
+ const targetPath = join5(targetDir, `${name}${ext}`);
10171
+ if (existsSync6(sourcePath)) {
9597
10172
  await rename2(sourcePath, targetPath);
9598
10173
  }
9599
10174
  }
@@ -9648,7 +10223,7 @@ var ComponentService = class {
9648
10223
  }
9649
10224
  const category = this.componentCategories.get(oldName);
9650
10225
  const componentsDir = this.componentsBaseDir();
9651
- const dir = category ? join4(componentsDir, category) : componentsDir;
10226
+ const dir = category ? join5(componentsDir, category) : componentsDir;
9652
10227
  if (this.writer) {
9653
10228
  if (await this.writer.componentExists(dir, trimmedNew)) {
9654
10229
  throw new Error(`Component "${trimmedNew}" already exists in components/${category ?? ""}`);
@@ -9656,15 +10231,15 @@ var ComponentService = class {
9656
10231
  await this.writer.moveComponent(dir, dir, oldName, trimmedNew);
9657
10232
  } else {
9658
10233
  for (const ext of [".json", ".js", ".css"]) {
9659
- if (existsSync3(join4(dir, `${trimmedNew}${ext}`))) {
10234
+ if (existsSync6(join5(dir, `${trimmedNew}${ext}`))) {
9660
10235
  throw new Error(`File "${trimmedNew}${ext}" already exists in components/${category ?? ""}`);
9661
10236
  }
9662
10237
  }
9663
10238
  const { rename: rename2 } = await import("node:fs/promises");
9664
10239
  for (const ext of [".json", ".js", ".css"]) {
9665
- const src = join4(dir, `${oldName}${ext}`);
9666
- const dst = join4(dir, `${trimmedNew}${ext}`);
9667
- if (existsSync3(src)) {
10240
+ const src = join5(dir, `${oldName}${ext}`);
10241
+ const dst = join5(dir, `${trimmedNew}${ext}`);
10242
+ if (existsSync6(src)) {
9668
10243
  await rename2(src, dst);
9669
10244
  }
9670
10245
  }
@@ -9682,7 +10257,7 @@ var ComponentService = class {
9682
10257
  if (!structure) continue;
9683
10258
  if (rewriteComponentRefs(structure, oldName, trimmedNew)) {
9684
10259
  const otherCategory = this.componentCategories.get(name);
9685
- const otherDir = otherCategory ? join4(componentsDir, otherCategory) : componentsDir;
10260
+ const otherDir = otherCategory ? join5(componentsDir, otherCategory) : componentsDir;
9686
10261
  const persisted = JSON.parse(JSON.stringify(otherDef));
9687
10262
  if (persisted?.component?.javascript !== void 0) {
9688
10263
  delete persisted.component.javascript;
@@ -9690,7 +10265,7 @@ var ComponentService = class {
9690
10265
  if (this.writer) {
9691
10266
  await this.writer.writeComponent(otherDir, name, persisted);
9692
10267
  } else {
9693
- await writeFile3(join4(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
10268
+ await writeFile3(join5(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
9694
10269
  }
9695
10270
  componentRefs++;
9696
10271
  }
@@ -10230,9 +10805,9 @@ var CMSService = class {
10230
10805
  };
10231
10806
 
10232
10807
  // lib/server/providers/fileSystemCMSProvider.ts
10233
- import { existsSync as existsSync4, readdirSync as readdirSync4, mkdirSync as mkdirSync3 } from "node:fs";
10234
- import { join as join5 } from "node:path";
10235
- var log5 = createLogger("FileSystemCMSProvider");
10808
+ import { existsSync as existsSync7, readdirSync as readdirSync4, mkdirSync as mkdirSync3 } from "node:fs";
10809
+ import { join as join6 } from "node:path";
10810
+ var log6 = createLogger("FileSystemCMSProvider");
10236
10811
  var DRAFT_FILE_SUFFIX = `${CMS_DRAFT_SUFFIX}.json`;
10237
10812
  async function loadJSONFile2(filePath) {
10238
10813
  try {
@@ -10241,7 +10816,7 @@ async function loadJSONFile2(filePath) {
10241
10816
  }
10242
10817
  return null;
10243
10818
  } catch (error) {
10244
- log5.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
10819
+ log6.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
10245
10820
  return null;
10246
10821
  }
10247
10822
  }
@@ -10303,14 +10878,14 @@ var FileSystemCMSProvider = class {
10303
10878
  return this.schemaCache;
10304
10879
  }
10305
10880
  const schemas = /* @__PURE__ */ new Map();
10306
- if (!existsSync4(this.templatesDir)) {
10881
+ if (!existsSync7(this.templatesDir)) {
10307
10882
  return schemas;
10308
10883
  }
10309
10884
  const files = readdirSync4(this.templatesDir);
10310
10885
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
10311
10886
  const results = await Promise.all(
10312
10887
  jsonFiles.map(async (file) => {
10313
- const filePath = join5(this.templatesDir, file);
10888
+ const filePath = join6(this.templatesDir, file);
10314
10889
  const content = await loadJSONFile2(filePath);
10315
10890
  return { filePath, content };
10316
10891
  })
@@ -10335,15 +10910,15 @@ var FileSystemCMSProvider = class {
10335
10910
  */
10336
10911
  async getItems(collection) {
10337
10912
  this.validateCollection(collection);
10338
- const collectionDir = join5(this.cmsDir, collection);
10339
- if (!existsSync4(collectionDir)) {
10913
+ const collectionDir = join6(this.cmsDir, collection);
10914
+ if (!existsSync7(collectionDir)) {
10340
10915
  return [];
10341
10916
  }
10342
10917
  const files = readdirSync4(collectionDir);
10343
10918
  const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.endsWith(DRAFT_FILE_SUFFIX));
10344
10919
  const results = await Promise.all(
10345
10920
  jsonFiles.map(async (file) => {
10346
- const filePath = join5(collectionDir, file);
10921
+ const filePath = join6(collectionDir, file);
10347
10922
  const content = await loadJSONFile2(filePath);
10348
10923
  return { file, filePath, content };
10349
10924
  })
@@ -10357,7 +10932,7 @@ var FileSystemCMSProvider = class {
10357
10932
  if (validation.valid) {
10358
10933
  items.push(validation.data);
10359
10934
  } else {
10360
- log5.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10935
+ log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10361
10936
  }
10362
10937
  }
10363
10938
  }
@@ -10376,7 +10951,7 @@ var FileSystemCMSProvider = class {
10376
10951
  async getItemByFilename(collection, filename) {
10377
10952
  this.validateCollection(collection);
10378
10953
  this.validateFilename(filename);
10379
- const filePath = join5(this.cmsDir, collection, `${filename}.json`);
10954
+ const filePath = join6(this.cmsDir, collection, `${filename}.json`);
10380
10955
  const content = await loadJSONFile2(filePath);
10381
10956
  if (!content || typeof content !== "object") {
10382
10957
  return null;
@@ -10386,7 +10961,7 @@ var FileSystemCMSProvider = class {
10386
10961
  if (validation.valid) {
10387
10962
  return validation.data;
10388
10963
  }
10389
- log5.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10964
+ log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10390
10965
  return null;
10391
10966
  }
10392
10967
  /**
@@ -10428,12 +11003,12 @@ var FileSystemCMSProvider = class {
10428
11003
  throw new Error("Cannot derive filename: item is missing _id, _filename, and a usable slug-field value.");
10429
11004
  }
10430
11005
  this.validateFilename(filename);
10431
- const collectionDir = join5(this.cmsDir, collection);
10432
- if (!existsSync4(collectionDir)) {
11006
+ const collectionDir = join6(this.cmsDir, collection);
11007
+ if (!existsSync7(collectionDir)) {
10433
11008
  mkdirSync3(collectionDir, { recursive: true });
10434
11009
  }
10435
11010
  const itemData = stripTransient(item);
10436
- const filePath = join5(collectionDir, `${filename}.json`);
11011
+ const filePath = join6(collectionDir, `${filename}.json`);
10437
11012
  await writeFile3(filePath, JSON.stringify(itemData, null, 2), "utf-8");
10438
11013
  }
10439
11014
  /**
@@ -10443,18 +11018,18 @@ var FileSystemCMSProvider = class {
10443
11018
  this.validateCollection(collection);
10444
11019
  this.validateFilename(filename);
10445
11020
  const { unlink } = await import("node:fs/promises");
10446
- const publishedPath = join5(this.cmsDir, collection, `${filename}.json`);
10447
- if (existsSync4(publishedPath)) {
11021
+ const publishedPath = join6(this.cmsDir, collection, `${filename}.json`);
11022
+ if (existsSync7(publishedPath)) {
10448
11023
  await unlink(publishedPath);
10449
11024
  }
10450
11025
  const draftPath = this.draftPath(collection, filename);
10451
- if (existsSync4(draftPath)) {
11026
+ if (existsSync7(draftPath)) {
10452
11027
  await unlink(draftPath);
10453
11028
  }
10454
11029
  }
10455
11030
  // ---- Draft helpers ----------------------------------------------------
10456
11031
  draftPath(collection, filename) {
10457
- return join5(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
11032
+ return join6(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
10458
11033
  }
10459
11034
  /**
10460
11035
  * Get the draft version of an item, or null if no draft file exists.
@@ -10481,12 +11056,12 @@ var FileSystemCMSProvider = class {
10481
11056
  */
10482
11057
  async getAllDrafts(collection) {
10483
11058
  this.validateCollection(collection);
10484
- const collectionDir = join5(this.cmsDir, collection);
10485
- if (!existsSync4(collectionDir)) return [];
11059
+ const collectionDir = join6(this.cmsDir, collection);
11060
+ if (!existsSync7(collectionDir)) return [];
10486
11061
  const files = readdirSync4(collectionDir).filter((f) => f.endsWith(DRAFT_FILE_SUFFIX));
10487
11062
  const results = await Promise.all(
10488
11063
  files.map(async (file) => {
10489
- const filePath = join5(collectionDir, file);
11064
+ const filePath = join6(collectionDir, file);
10490
11065
  const content = await loadJSONFile2(filePath);
10491
11066
  return { file, content };
10492
11067
  })
@@ -10508,7 +11083,7 @@ var FileSystemCMSProvider = class {
10508
11083
  async hasDraft(collection, filename) {
10509
11084
  this.validateCollection(collection);
10510
11085
  this.validateFilename(filename);
10511
- return existsSync4(this.draftPath(collection, filename));
11086
+ return existsSync7(this.draftPath(collection, filename));
10512
11087
  }
10513
11088
  /**
10514
11089
  * Save the draft version of an item. Loose validation — drafts may have
@@ -10542,8 +11117,8 @@ var FileSystemCMSProvider = class {
10542
11117
  throw new Error("Cannot derive draft filename: item is missing _id, _filename, and a usable slug-field value.");
10543
11118
  }
10544
11119
  this.validateFilename(filename);
10545
- const collectionDir = join5(this.cmsDir, collection);
10546
- if (!existsSync4(collectionDir)) {
11120
+ const collectionDir = join6(this.cmsDir, collection);
11121
+ if (!existsSync7(collectionDir)) {
10547
11122
  mkdirSync3(collectionDir, { recursive: true });
10548
11123
  }
10549
11124
  const itemData = stripTransient(item);
@@ -10563,7 +11138,7 @@ var FileSystemCMSProvider = class {
10563
11138
  this.validateFilename(filename);
10564
11139
  const { unlink } = await import("node:fs/promises");
10565
11140
  const filePath = this.draftPath(collection, filename);
10566
- if (existsSync4(filePath)) {
11141
+ if (existsSync7(filePath)) {
10567
11142
  await unlink(filePath);
10568
11143
  }
10569
11144
  }
@@ -10591,14 +11166,14 @@ var FileSystemCMSProvider = class {
10591
11166
  const messages = validation.errors.map((e) => `${e.path}: ${e.message}`).join(", ");
10592
11167
  throw new Error(`Cannot publish invalid draft: ${messages}`);
10593
11168
  }
10594
- const collectionDir = join5(this.cmsDir, collection);
10595
- if (!existsSync4(collectionDir)) {
11169
+ const collectionDir = join6(this.cmsDir, collection);
11170
+ if (!existsSync7(collectionDir)) {
10596
11171
  mkdirSync3(collectionDir, { recursive: true });
10597
11172
  }
10598
11173
  const itemData = stripTransient(validation.data);
10599
- const publishedPath = join5(collectionDir, `${filename}.json`);
11174
+ const publishedPath = join6(collectionDir, `${filename}.json`);
10600
11175
  await writeFile3(publishedPath, JSON.stringify(itemData, null, 2), "utf-8");
10601
- if (existsSync4(draftFilePath)) {
11176
+ if (existsSync7(draftFilePath)) {
10602
11177
  await unlink(draftFilePath);
10603
11178
  }
10604
11179
  return normalizeItem(itemData, filename);
@@ -10619,18 +11194,18 @@ var FileSystemCMSProvider = class {
10619
11194
  );
10620
11195
  }
10621
11196
  const { writeFile: writeFile3, mkdir } = await import("node:fs/promises");
10622
- if (!existsSync4(this.templatesDir)) {
11197
+ if (!existsSync7(this.templatesDir)) {
10623
11198
  await mkdir(this.templatesDir, { recursive: true });
10624
11199
  }
10625
- const pageFilePath = join5(this.templatesDir, `${collectionId}.json`);
10626
- if (existsSync4(pageFilePath)) {
11200
+ const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
11201
+ if (existsSync7(pageFilePath)) {
10627
11202
  throw new Error(`Page file already exists: templates/${collectionId}.json`);
10628
11203
  }
10629
11204
  await writeFile3(pageFilePath, JSON.stringify(pageData, null, 2), "utf-8");
10630
11205
  const schemaSource = pageData?.meta?.cms?.source;
10631
11206
  if (schemaSource !== "sanity") {
10632
- const collectionDir = join5(this.cmsDir, collectionId);
10633
- if (!existsSync4(collectionDir)) {
11207
+ const collectionDir = join6(this.cmsDir, collectionId);
11208
+ if (!existsSync7(collectionDir)) {
10634
11209
  await mkdir(collectionDir, { recursive: true });
10635
11210
  }
10636
11211
  }
@@ -10647,8 +11222,8 @@ var FileSystemCMSProvider = class {
10647
11222
  );
10648
11223
  }
10649
11224
  const { readFile: readFile2, writeFile: writeFile3 } = await import("node:fs/promises");
10650
- const pageFilePath = join5(this.templatesDir, `${collectionId}.json`);
10651
- if (!existsSync4(pageFilePath)) {
11225
+ const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
11226
+ if (!existsSync7(pageFilePath)) {
10652
11227
  throw new Error(`Collection not found: ${collectionId}`);
10653
11228
  }
10654
11229
  const content = await readFile2(pageFilePath, "utf-8");
@@ -10774,8 +11349,8 @@ var DraftPageStore = class {
10774
11349
  };
10775
11350
 
10776
11351
  // lib/server/fileWatcher.ts
10777
- import { watch, existsSync as existsSync5, statSync, readdirSync as readdirSync5 } from "node:fs";
10778
- import { basename as basename2, dirname as dirname2, join as join6, relative } from "node:path";
11352
+ import { watch, existsSync as existsSync8, statSync, readdirSync as readdirSync5 } from "node:fs";
11353
+ import { basename as basename2, dirname as dirname2, join as join7, relative } from "node:path";
10779
11354
  function watchRecursive(root, listener) {
10780
11355
  const nested = [];
10781
11356
  const watchedDirs = /* @__PURE__ */ new Set();
@@ -10791,7 +11366,7 @@ function watchRecursive(root, listener) {
10791
11366
  attachDir(abs);
10792
11367
  try {
10793
11368
  for (const e of readdirSync5(abs, { withFileTypes: true })) {
10794
- const child = join6(abs, e.name);
11369
+ const child = join7(abs, e.name);
10795
11370
  if (e.isDirectory()) coverNewDir(child);
10796
11371
  else listener("rename", relative(root, child));
10797
11372
  }
@@ -10805,7 +11380,7 @@ function watchRecursive(root, listener) {
10805
11380
  try {
10806
11381
  w = watch(absDir, { recursive: true }, (event, filename) => {
10807
11382
  if (!filename) return;
10808
- const abs = join6(absDir, filename);
11383
+ const abs = join7(absDir, filename);
10809
11384
  listener(event, relative(root, abs));
10810
11385
  coverNewDir(abs);
10811
11386
  });
@@ -10831,19 +11406,19 @@ function watchRecursive(root, listener) {
10831
11406
  return handle;
10832
11407
  }
10833
11408
  function attachWhenDirExists(dirPath, attach, setWatcher) {
10834
- if (existsSync5(dirPath)) {
11409
+ if (existsSync8(dirPath)) {
10835
11410
  setWatcher(attach());
10836
11411
  return;
10837
11412
  }
10838
11413
  const parentDir = dirname2(dirPath);
10839
11414
  const targetName = basename2(dirPath);
10840
- if (!existsSync5(parentDir)) {
11415
+ if (!existsSync8(parentDir)) {
10841
11416
  return;
10842
11417
  }
10843
11418
  let parentWatcher = null;
10844
11419
  parentWatcher = watch(parentDir, (_event, filename) => {
10845
11420
  if (filename !== targetName) return;
10846
- if (!existsSync5(dirPath)) return;
11421
+ if (!existsSync8(dirPath)) return;
10847
11422
  parentWatcher?.close();
10848
11423
  parentWatcher = null;
10849
11424
  setWatcher(attach());
@@ -10873,7 +11448,7 @@ var FileWatcher = class {
10873
11448
  * Watches both .json and .js files to detect component definition and JavaScript changes
10874
11449
  */
10875
11450
  watchComponents(dirPath = projectPaths.components()) {
10876
- if (!existsSync5(dirPath)) {
11451
+ if (!existsSync8(dirPath)) {
10877
11452
  return;
10878
11453
  }
10879
11454
  this.componentsWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -10889,7 +11464,7 @@ var FileWatcher = class {
10889
11464
  * Start watching pages directory
10890
11465
  */
10891
11466
  watchPages(dirPath = projectPaths.pages()) {
10892
- if (!existsSync5(dirPath)) {
11467
+ if (!existsSync8(dirPath)) {
10893
11468
  return;
10894
11469
  }
10895
11470
  this.pagesWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -10929,7 +11504,7 @@ var FileWatcher = class {
10929
11504
  * Start watching colors.json file
10930
11505
  */
10931
11506
  watchColors(filePath = projectPaths.colors()) {
10932
- if (!existsSync5(filePath)) {
11507
+ if (!existsSync8(filePath)) {
10933
11508
  return;
10934
11509
  }
10935
11510
  const dirPath = getProjectRoot();
@@ -10986,7 +11561,7 @@ var FileWatcher = class {
10986
11561
  * Start watching images directory for new source images
10987
11562
  */
10988
11563
  watchImages(dirPath = projectPaths.images()) {
10989
- if (!existsSync5(dirPath)) {
11564
+ if (!existsSync8(dirPath)) {
10990
11565
  return;
10991
11566
  }
10992
11567
  this.imagesWatcher = watch(dirPath, { recursive: false }, async (event, filename) => {
@@ -11013,7 +11588,7 @@ var FileWatcher = class {
11013
11588
  * Start watching libraries directory for CSS/JS changes
11014
11589
  */
11015
11590
  watchLibraries(dirPath = projectPaths.libraries()) {
11016
- if (!existsSync5(dirPath)) {
11591
+ if (!existsSync8(dirPath)) {
11017
11592
  return;
11018
11593
  }
11019
11594
  this.librariesWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -11037,7 +11612,7 @@ var FileWatcher = class {
11037
11612
  * early-out and the first collection's item edits wouldn't live-reload until a
11038
11613
  * dev-server restart.
11039
11614
  */
11040
- watchAstroPages(dirPath = join6(getProjectRoot(), "src", "pages")) {
11615
+ watchAstroPages(dirPath = join7(getProjectRoot(), "src", "pages")) {
11041
11616
  attachWhenDirExists(
11042
11617
  dirPath,
11043
11618
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11054,7 +11629,7 @@ var FileWatcher = class {
11054
11629
  }
11055
11630
  );
11056
11631
  }
11057
- watchAstroComponents(dirPath = join6(getProjectRoot(), "src", "components")) {
11632
+ watchAstroComponents(dirPath = join7(getProjectRoot(), "src", "components")) {
11058
11633
  attachWhenDirExists(
11059
11634
  dirPath,
11060
11635
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11067,7 +11642,7 @@ var FileWatcher = class {
11067
11642
  }
11068
11643
  );
11069
11644
  }
11070
- watchAstroContent(dirPath = join6(getProjectRoot(), "src", "content")) {
11645
+ watchAstroContent(dirPath = join7(getProjectRoot(), "src", "content")) {
11071
11646
  attachWhenDirExists(
11072
11647
  dirPath,
11073
11648
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11270,22 +11845,22 @@ var FileWatcherService = class {
11270
11845
  };
11271
11846
 
11272
11847
  // lib/server/migrateTemplates.ts
11273
- import { existsSync as existsSync6 } from "node:fs";
11848
+ import { existsSync as existsSync9 } from "node:fs";
11274
11849
  import { rename } from "node:fs/promises";
11275
- import { join as join7 } from "node:path";
11850
+ import { join as join8 } from "node:path";
11276
11851
  async function migrateTemplatesDirectory() {
11277
- const oldDir = join7(projectPaths.pages(), "templates");
11852
+ const oldDir = join8(projectPaths.pages(), "templates");
11278
11853
  const newDir = projectPaths.templates();
11279
- if (!existsSync6(oldDir)) return;
11280
- if (existsSync6(newDir)) return;
11854
+ if (!existsSync9(oldDir)) return;
11855
+ if (existsSync9(newDir)) return;
11281
11856
  await rename(oldDir, newDir);
11282
11857
  console.log("Migrated CMS templates: pages/templates/ \u2192 templates/");
11283
11858
  }
11284
11859
 
11285
11860
  // build-astro.ts
11286
- import { existsSync as existsSync7, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
11861
+ import { existsSync as existsSync10, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
11287
11862
  import { writeFile as writeFile2, readFile } from "node:fs/promises";
11288
- import { join as join8 } from "node:path";
11863
+ import { join as join9 } from "node:path";
11289
11864
  import { createHash } from "node:crypto";
11290
11865
 
11291
11866
  // lib/server/astro/tailwindMapper.ts
@@ -14138,23 +14713,23 @@ function writePageScript(javascript, scriptsDir) {
14138
14713
  if (!javascript) return [];
14139
14714
  const hash = hashContent3(javascript);
14140
14715
  const scriptFile = `${hash}.js`;
14141
- if (!existsSync7(scriptsDir)) {
14716
+ if (!existsSync10(scriptsDir)) {
14142
14717
  mkdirSync4(scriptsDir, { recursive: true });
14143
14718
  }
14144
- const fullScriptPath = join8(scriptsDir, scriptFile);
14145
- if (!existsSync7(fullScriptPath)) {
14719
+ const fullScriptPath = join9(scriptsDir, scriptFile);
14720
+ if (!existsSync10(fullScriptPath)) {
14146
14721
  writeFileSync(fullScriptPath, javascript, "utf-8");
14147
14722
  }
14148
14723
  return [`/_scripts/${scriptFile}`];
14149
14724
  }
14150
14725
  function copyDirectory(src, dest, filter) {
14151
- if (!existsSync7(src)) return;
14152
- if (!existsSync7(dest)) mkdirSync4(dest, { recursive: true });
14726
+ if (!existsSync10(src)) return;
14727
+ if (!existsSync10(dest)) mkdirSync4(dest, { recursive: true });
14153
14728
  const files = readdirSync6(src);
14154
14729
  for (const file of files) {
14155
14730
  if (filter && !filter(file)) continue;
14156
- const srcPath = join8(src, file);
14157
- const destPath = join8(dest, file);
14731
+ const srcPath = join9(src, file);
14732
+ const destPath = join9(dest, file);
14158
14733
  const stat = statSync2(srcPath);
14159
14734
  if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
14160
14735
  else copyFileSync(srcPath, destPath);
@@ -14171,13 +14746,13 @@ function isCMSPage(pageData) {
14171
14746
  }
14172
14747
  function scanJSONFiles(dir, prefix = "") {
14173
14748
  const results = [];
14174
- if (!existsSync7(dir)) return results;
14749
+ if (!existsSync10(dir)) return results;
14175
14750
  const entries = readdirSync6(dir, { withFileTypes: true });
14176
14751
  for (const entry of entries) {
14177
14752
  if (entry.isFile() && entry.name.endsWith(".json")) {
14178
14753
  results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
14179
14754
  } else if (entry.isDirectory()) {
14180
- results.push(...scanJSONFiles(join8(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
14755
+ results.push(...scanJSONFiles(join9(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
14181
14756
  }
14182
14757
  }
14183
14758
  return results;
@@ -14343,23 +14918,23 @@ async function buildAstroProject(_projectRoot, outputDir) {
14343
14918
  const globalLibraries = configService.getLibraries();
14344
14919
  const componentLibraries = collectComponentLibraries(globalComponents);
14345
14920
  const imageMetadataMap = await buildImageMetadataMap();
14346
- const outDir = outputDir || join8(projectPaths.project, "astro-export");
14347
- if (existsSync7(outDir)) {
14921
+ const outDir = outputDir || join9(projectPaths.project, "astro-export");
14922
+ if (existsSync10(outDir)) {
14348
14923
  rmSync(outDir, { recursive: true, force: true });
14349
14924
  }
14350
14925
  mkdirSync4(outDir, { recursive: true });
14351
- const srcDir = join8(outDir, "src");
14352
- const pagesOutDir = join8(srcDir, "pages");
14353
- const layoutsDir = join8(srcDir, "layouts");
14354
- const stylesDir = join8(srcDir, "styles");
14355
- const componentsOutDir = join8(srcDir, "components");
14356
- const publicDir = join8(outDir, "public");
14357
- const scriptsDir = join8(publicDir, "_scripts");
14926
+ const srcDir = join9(outDir, "src");
14927
+ const pagesOutDir = join9(srcDir, "pages");
14928
+ const layoutsDir = join9(srcDir, "layouts");
14929
+ const stylesDir = join9(srcDir, "styles");
14930
+ const componentsOutDir = join9(srcDir, "components");
14931
+ const publicDir = join9(outDir, "public");
14932
+ const scriptsDir = join9(publicDir, "_scripts");
14358
14933
  for (const d of [srcDir, pagesOutDir, layoutsDir, stylesDir, componentsOutDir, publicDir]) {
14359
14934
  mkdirSync4(d, { recursive: true });
14360
14935
  }
14361
14936
  const pagesDir = projectPaths.pages();
14362
- if (!existsSync7(pagesDir)) {
14937
+ if (!existsSync10(pagesDir)) {
14363
14938
  console.error("Pages directory not found!");
14364
14939
  return { pages: 0, cmsPages: 0, collections: 0, errors: 1 };
14365
14940
  }
@@ -14372,7 +14947,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14372
14947
  for (const file of pageFiles) {
14373
14948
  const pageName = file.replace(".json", "");
14374
14949
  const basePath = mapPageNameToPath(pageName);
14375
- const pageContent = await loadJSONFile(join8(pagesDir, file));
14950
+ const pageContent = await loadJSONFile(join9(pagesDir, file));
14376
14951
  if (!pageContent) continue;
14377
14952
  try {
14378
14953
  const pageData = parseJSON(pageContent);
@@ -14431,7 +15006,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14431
15006
  for (const file of pageFiles) {
14432
15007
  const pageName = file.replace(".json", "");
14433
15008
  const basePath = mapPageNameToPath(pageName);
14434
- const pageContent = await loadJSONFile(join8(pagesDir, file));
15009
+ const pageContent = await loadJSONFile(join9(pagesDir, file));
14435
15010
  if (!pageContent) {
14436
15011
  console.warn(` Skipping ${basePath} (empty file)`);
14437
15012
  errorCount++;
@@ -14489,8 +15064,8 @@ async function buildAstroProject(_projectRoot, outputDir) {
14489
15064
  if (!css.url.startsWith("/")) continue;
14490
15065
  const shouldInline = css.inline !== false;
14491
15066
  const relPath = css.url.slice(1);
14492
- const srcPath = join8(projectPaths.project, relPath);
14493
- if (!existsSync7(srcPath)) continue;
15067
+ const srcPath = join9(projectPaths.project, relPath);
15068
+ if (!existsSync10(srcPath)) continue;
14494
15069
  if (shouldInline) {
14495
15070
  try {
14496
15071
  inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
@@ -14504,7 +15079,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14504
15079
  for (const js of buildLibraries.js || []) {
14505
15080
  if (js.url.startsWith("/")) {
14506
15081
  const relPath = js.url.slice(1);
14507
- if (existsSync7(join8(projectPaths.project, relPath))) {
15082
+ if (existsSync10(join9(projectPaths.project, relPath))) {
14508
15083
  localLibsToCopy.push(relPath);
14509
15084
  }
14510
15085
  }
@@ -14525,9 +15100,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
14525
15100
  const cmsConsumerComponents = computeCmsConsumerComponents(globalComponents);
14526
15101
  const collectionUrlExpr = /* @__PURE__ */ new Map();
14527
15102
  const mergedRichTextFields = /* @__PURE__ */ new Set();
14528
- if (existsSync7(templatesDir)) {
15103
+ if (existsSync10(templatesDir)) {
14529
15104
  for (const file of readdirSync6(templatesDir).filter((f) => f.endsWith(".json"))) {
14530
- const tc = await loadJSONFile(join8(templatesDir, file));
15105
+ const tc = await loadJSONFile(join9(templatesDir, file));
14531
15106
  if (!tc) continue;
14532
15107
  try {
14533
15108
  const pd = parseJSON(tc);
@@ -14541,10 +15116,10 @@ async function buildAstroProject(_projectRoot, outputDir) {
14541
15116
  }
14542
15117
  }
14543
15118
  }
14544
- if (existsSync7(templatesDir)) {
15119
+ if (existsSync10(templatesDir)) {
14545
15120
  const templateFiles = readdirSync6(templatesDir).filter((f) => f.endsWith(".json"));
14546
15121
  for (const file of templateFiles) {
14547
- const templateContent = await loadJSONFile(join8(templatesDir, file));
15122
+ const templateContent = await loadJSONFile(join9(templatesDir, file));
14548
15123
  if (!templateContent) continue;
14549
15124
  try {
14550
15125
  const pageData = parseJSON(templateContent);
@@ -14633,9 +15208,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
14633
15208
  cmsConsumers: cmsConsumerComponents,
14634
15209
  collectionUrlExpr
14635
15210
  });
14636
- const astroFileFull = join8(pagesOutDir, astroFilePath);
15211
+ const astroFileFull = join9(pagesOutDir, astroFilePath);
14637
15212
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
14638
- if (!existsSync7(astroFileDir)) {
15213
+ if (!existsSync10(astroFileDir)) {
14639
15214
  mkdirSync4(astroFileDir, { recursive: true });
14640
15215
  }
14641
15216
  await writeFile2(astroFileFull, astroContent, "utf-8");
@@ -14667,7 +15242,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14667
15242
 
14668
15243
  ${safelistDirectives}` : `@import "tailwindcss";`;
14669
15244
  const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined].filter(Boolean).join("\n\n");
14670
- await writeFile2(join8(stylesDir, "global.css"), globalCSS, "utf-8");
15245
+ await writeFile2(join9(stylesDir, "global.css"), globalCSS, "utf-8");
14671
15246
  const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
14672
15247
  const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
14673
15248
  const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
@@ -14714,7 +15289,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14714
15289
  </body>
14715
15290
  </html>
14716
15291
  `;
14717
- await writeFile2(join8(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
15292
+ await writeFile2(join9(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
14718
15293
  const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
14719
15294
  let _componentFileCount = 0;
14720
15295
  for (const [compName, compDef] of Object.entries(emittableComponents)) {
@@ -14733,7 +15308,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14733
15308
  collectionUrlExpr
14734
15309
  }
14735
15310
  );
14736
- await writeFile2(join8(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
15311
+ await writeFile2(join9(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
14737
15312
  _componentFileCount++;
14738
15313
  } catch (error) {
14739
15314
  console.warn(
@@ -14784,9 +15359,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14784
15359
  scriptPaths = writePageScript(result.javascript, scriptsDir);
14785
15360
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
14786
15361
  }
14787
- const astroFileFull = join8(pagesOutDir, result.astroFilePath);
15362
+ const astroFileFull = join9(pagesOutDir, result.astroFilePath);
14788
15363
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
14789
- if (!existsSync7(astroFileDir)) {
15364
+ if (!existsSync10(astroFileDir)) {
14790
15365
  mkdirSync4(astroFileDir, { recursive: true });
14791
15366
  }
14792
15367
  await writeFile2(astroFileFull, astroContent, "utf-8");
@@ -14807,31 +15382,31 @@ export const GET: APIRoute = () => {
14807
15382
  });
14808
15383
  };
14809
15384
  `;
14810
- await writeFile2(join8(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
15385
+ await writeFile2(join9(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
14811
15386
  let collectionCount = 0;
14812
15387
  if (templateSchemas.length > 0) {
14813
- const contentDir = join8(srcDir, "content");
15388
+ const contentDir = join9(srcDir, "content");
14814
15389
  mkdirSync4(contentDir, { recursive: true });
14815
15390
  const collectionDefs = [];
14816
15391
  for (const schema of templateSchemas) {
14817
- const collectionDir = join8(contentDir, schema.id);
15392
+ const collectionDir = join9(contentDir, schema.id);
14818
15393
  mkdirSync4(collectionDir, { recursive: true });
14819
15394
  const richTextFieldNames = Object.entries(schema.fields || {}).filter(([, fd]) => fd.type === "rich-text").map(([fn]) => fn);
14820
- const cmsItemsDir = join8(projectPaths.cms(), schema.id);
14821
- if (existsSync7(cmsItemsDir)) {
15395
+ const cmsItemsDir = join9(projectPaths.cms(), schema.id);
15396
+ if (existsSync10(cmsItemsDir)) {
14822
15397
  const isDevBuild = process.env.MENO_DEV_BUILD === "true";
14823
15398
  const itemFiles = readdirSync6(cmsItemsDir).filter(
14824
15399
  (f) => f.endsWith(".json") && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`))
14825
15400
  );
14826
15401
  for (const itemFile of itemFiles) {
14827
15402
  try {
14828
- const rawContent = await readFile(join8(cmsItemsDir, itemFile), "utf-8");
15403
+ const rawContent = await readFile(join9(cmsItemsDir, itemFile), "utf-8");
14829
15404
  const item = JSON.parse(rawContent);
14830
15405
  const resolved = { ...item };
14831
15406
  for (const fieldName of richTextFieldNames) {
14832
15407
  resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
14833
15408
  }
14834
- await writeFile2(join8(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
15409
+ await writeFile2(join9(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
14835
15410
  } catch (err) {
14836
15411
  console.warn(
14837
15412
  ` Warning: could not process CMS item ${itemFile}: ${err instanceof Error ? err.message : String(err)}`
@@ -14864,29 +15439,29 @@ ${collectionDefs.join(",\n")}
14864
15439
 
14865
15440
  export { collections };
14866
15441
  `;
14867
- await writeFile2(join8(srcDir, "content.config.ts"), configContent, "utf-8");
15442
+ await writeFile2(join9(srcDir, "content.config.ts"), configContent, "utf-8");
14868
15443
  }
14869
- const imagesSrcDir = join8(projectPaths.project, "images");
14870
- if (existsSync7(imagesSrcDir)) {
14871
- copyDirectory(imagesSrcDir, join8(srcDir, "assets", "images"), shouldCopyImageForAstro);
14872
- copyDirectory(imagesSrcDir, join8(publicDir, "images"));
15444
+ const imagesSrcDir = join9(projectPaths.project, "images");
15445
+ if (existsSync10(imagesSrcDir)) {
15446
+ copyDirectory(imagesSrcDir, join9(srcDir, "assets", "images"), shouldCopyImageForAstro);
15447
+ copyDirectory(imagesSrcDir, join9(publicDir, "images"));
14873
15448
  }
14874
15449
  const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
14875
15450
  for (const dir of publicAssetDirs) {
14876
- const srcAssetDir = join8(projectPaths.project, dir);
14877
- if (existsSync7(srcAssetDir)) {
14878
- copyDirectory(srcAssetDir, join8(publicDir, dir));
15451
+ const srcAssetDir = join9(projectPaths.project, dir);
15452
+ if (existsSync10(srcAssetDir)) {
15453
+ copyDirectory(srcAssetDir, join9(publicDir, dir));
14879
15454
  }
14880
15455
  }
14881
- const librariesDir = join8(projectPaths.project, "libraries");
14882
- if (existsSync7(librariesDir)) {
14883
- copyDirectory(librariesDir, join8(publicDir, "libraries"));
15456
+ const librariesDir = join9(projectPaths.project, "libraries");
15457
+ if (existsSync10(librariesDir)) {
15458
+ copyDirectory(librariesDir, join9(publicDir, "libraries"));
14884
15459
  }
14885
15460
  for (const relPath of localLibsToCopy) {
14886
- const srcPath = join8(projectPaths.project, relPath);
14887
- const destPath = join8(publicDir, relPath);
15461
+ const srcPath = join9(projectPaths.project, relPath);
15462
+ const destPath = join9(publicDir, relPath);
14888
15463
  const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
14889
- if (destDir && !existsSync7(destDir)) mkdirSync4(destDir, { recursive: true });
15464
+ if (destDir && !existsSync10(destDir)) mkdirSync4(destDir, { recursive: true });
14890
15465
  copyFileSync(srcPath, destPath);
14891
15466
  }
14892
15467
  const packageJson = {
@@ -14909,7 +15484,7 @@ export { collections };
14909
15484
  tailwindcss: "^4.0.0"
14910
15485
  }
14911
15486
  };
14912
- await writeFile2(join8(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
15487
+ await writeFile2(join9(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
14913
15488
  const localeCodes = i18nConfig.locales.map((l) => l.code);
14914
15489
  const i18nBlock = i18nConfig.locales.length > 1 ? `
14915
15490
  i18n: {
@@ -14929,11 +15504,11 @@ export default defineConfig({${siteUrl ? `
14929
15504
  },
14930
15505
  });
14931
15506
  `;
14932
- await writeFile2(join8(outDir, "astro.config.mjs"), astroConfig, "utf-8");
15507
+ await writeFile2(join9(outDir, "astro.config.mjs"), astroConfig, "utf-8");
14933
15508
  const tsConfig = {
14934
15509
  extends: "astro/tsconfigs/strict"
14935
15510
  };
14936
- await writeFile2(join8(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
15511
+ await writeFile2(join9(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
14937
15512
  const baseNetlifyToml = `# Generated by Meno's Astro build.
14938
15513
  [build]
14939
15514
  command = "npm run build"
@@ -14943,8 +15518,8 @@ export default defineConfig({${siteUrl ? `
14943
15518
  NODE_VERSION = "22"
14944
15519
  `;
14945
15520
  const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes("404.json"));
14946
- await writeFile2(join8(outDir, "netlify.toml"), netlifyToml, "utf-8");
14947
- await writeFile2(join8(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
15521
+ await writeFile2(join9(outDir, "netlify.toml"), netlifyToml, "utf-8");
15522
+ await writeFile2(join9(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
14948
15523
  const totalPages = allResults.length;
14949
15524
  return {
14950
15525
  pages: totalPages - cmsPageCount,
@@ -15008,6 +15583,7 @@ export {
15008
15583
  getModuleDir,
15009
15584
  getPackageRoot,
15010
15585
  getProjectRoot,
15586
+ groupForSectionLabel,
15011
15587
  handleCollectionSchemaRoute,
15012
15588
  handleCollectionsRoute,
15013
15589
  handleCoreApiRoutes,
@@ -15016,11 +15592,15 @@ export {
15016
15592
  handleItemsRoute,
15017
15593
  handleRouteError,
15018
15594
  hashContent,
15595
+ inferGroup,
15019
15596
  inspect,
15020
15597
  isBun3 as isBun,
15598
+ isColorValue,
15599
+ isThemeCssProject,
15021
15600
  jsonResponse,
15022
15601
  lineMapToObject,
15023
15602
  loadProjectConfig,
15603
+ loadThemeModel,
15024
15604
  logError,
15025
15605
  logRequest,
15026
15606
  logResponseTime,
@@ -15030,19 +15610,25 @@ export {
15030
15610
  needsFormHandler,
15031
15611
  needsMenoFilter,
15032
15612
  packagePaths,
15613
+ parseThemeCss,
15033
15614
  processCMSPropsTemplate,
15034
15615
  processCMSTemplate,
15035
15616
  projectPaths,
15036
15617
  readJsonFile,
15037
15618
  readTextFile,
15619
+ regenerateThemeCss,
15038
15620
  renderPageSSR,
15039
15621
  resetFontConfig,
15040
15622
  resolvePackagePath,
15041
15623
  resolveProjectPath,
15624
+ saveColors,
15625
+ saveVariables,
15626
+ serializeThemeCss,
15042
15627
  serveFile,
15043
15628
  setProjectRoot,
15044
15629
  spawnProcess,
15045
15630
  styleToString,
15631
+ themeCssPath,
15046
15632
  validateJS,
15047
15633
  variableService,
15048
15634
  watchRecursive,