meno-core 1.1.1 → 1.1.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 (32) hide show
  1. package/dist/chunks/{chunk-7ZLF4NE5.js → chunk-3JXK2QFU.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-J4IPTP5X.js → chunk-LOZL5HOF.js} +29 -3
  5. package/dist/chunks/chunk-LOZL5HOF.js.map +7 -0
  6. package/dist/lib/client/index.js +2 -2
  7. package/dist/lib/server/index.js +812 -218
  8. package/dist/lib/server/index.js.map +4 -4
  9. package/dist/lib/shared/index.js +4 -2
  10. package/dist/lib/shared/index.js.map +1 -1
  11. package/lib/client/scripts/formHandler.ts +17 -0
  12. package/lib/server/index.ts +19 -0
  13. package/lib/server/middleware/cors.test.ts +1 -1
  14. package/lib/server/middleware/cors.ts +1 -1
  15. package/lib/server/routes/api/functions.ts +2 -2
  16. package/lib/server/services/ColorService.ts +38 -7
  17. package/lib/server/services/VariableService.ts +34 -5
  18. package/lib/server/themeCssCodec.test.ts +154 -0
  19. package/lib/server/themeCssCodec.ts +488 -0
  20. package/lib/server/themeCssStore.test.ts +139 -0
  21. package/lib/server/themeCssStore.ts +210 -0
  22. package/lib/shared/nodeUtils.ts +18 -0
  23. package/lib/shared/types/colors.ts +6 -2
  24. package/lib/shared/types/variables.ts +14 -7
  25. package/lib/shared/utilityClassMapper.test.ts +10 -0
  26. package/lib/shared/utilityClassMapper.ts +9 -1
  27. package/lib/shared/validation/schemas.test.ts +78 -0
  28. package/lib/shared/validation/schemas.ts +53 -5
  29. package/package.json +1 -1
  30. package/dist/chunks/chunk-J4IPTP5X.js.map +0 -7
  31. package/dist/chunks/chunk-QWTQZHG3.js.map +0 -7
  32. /package/dist/chunks/{chunk-7ZLF4NE5.js.map → chunk-3JXK2QFU.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-7ZLF4NE5.js";
36
+ } from "../../chunks/chunk-3JXK2QFU.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-J4IPTP5X.js";
95
+ } from "../../chunks/chunk-LOZL5HOF.js";
94
96
  import {
95
97
  DEFAULT_I18N_CONFIG,
96
98
  buildLocalizedPath,
@@ -282,7 +284,7 @@ init_constants();
282
284
  // lib/server/middleware/cors.ts
283
285
  var DEFAULT_OPTIONS = {
284
286
  origin: "*",
285
- methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
287
+ methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
286
288
  allowedHeaders: ["Content-Type", "Authorization"],
287
289
  credentials: false
288
290
  };
@@ -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) {
@@ -2384,7 +2950,7 @@ async function handleFunctionsRoute(req, url) {
2384
2950
  const response = await handler(context);
2385
2951
  const headers = new Headers(response.headers);
2386
2952
  headers.set("Access-Control-Allow-Origin", "*");
2387
- headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
2953
+ headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
2388
2954
  headers.set("Access-Control-Allow-Headers", "Content-Type");
2389
2955
  return new Response(response.body, {
2390
2956
  status: response.status,
@@ -2410,7 +2976,7 @@ function handleFunctionsPreflight(req, url) {
2410
2976
  status: 204,
2411
2977
  headers: {
2412
2978
  "Access-Control-Allow-Origin": "*",
2413
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
2979
+ "Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS",
2414
2980
  "Access-Control-Allow-Headers": "Content-Type",
2415
2981
  "Access-Control-Max-Age": "86400"
2416
2982
  }
@@ -4713,7 +5279,23 @@ var formHandlerScript = `
4713
5279
  // Find all forms with fetch handler
4714
5280
  const forms = document.querySelectorAll('form[data-submit-handler="fetch"]');
4715
5281
 
5282
+ // Spam protection (server-enforced at /api/send-email): inject a hidden honeypot
5283
+ // field bots fill but humans never see, and stamp a clock-skew-free dwell time on
5284
+ // submit. Fields named with a leading "_" are control/meta and are not emailed.
5285
+ const loadedAt = Date.now();
5286
+
4716
5287
  forms.forEach(function(form) {
5288
+ if (!form.querySelector('input[name="_honey"]')) {
5289
+ const hp = document.createElement('input');
5290
+ hp.type = 'text';
5291
+ hp.name = '_honey';
5292
+ hp.tabIndex = -1;
5293
+ hp.setAttribute('autocomplete', 'off');
5294
+ hp.setAttribute('aria-hidden', 'true');
5295
+ hp.style.cssText = 'position:absolute;left:-9999px;width:1px;height:1px;opacity:0';
5296
+ form.appendChild(hp);
5297
+ }
5298
+
4717
5299
  form.addEventListener('submit', async function(e) {
4718
5300
  e.preventDefault();
4719
5301
 
@@ -4748,6 +5330,7 @@ var formHandlerScript = `
4748
5330
 
4749
5331
  try {
4750
5332
  const formData = new FormData(form);
5333
+ formData.append('_elapsed', String(Date.now() - loadedAt));
4751
5334
 
4752
5335
  const response = await fetch(action, {
4753
5336
  method: method.toUpperCase(),
@@ -8440,8 +9023,8 @@ ${plainTextErrors}`;
8440
9023
  }
8441
9024
 
8442
9025
  // lib/server/services/pageService.ts
8443
- import { existsSync as existsSync2, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
8444
- import { join as join3 } from "node:path";
9026
+ import { existsSync as existsSync5, readdirSync as readdirSync2, mkdirSync, rmdirSync } from "node:fs";
9027
+ import { join as join4 } from "node:path";
8445
9028
 
8446
9029
  // lib/server/utils/jsonLineMapper.ts
8447
9030
  function buildLineMap(jsonText) {
@@ -8853,7 +9436,7 @@ var PageService = class {
8853
9436
  */
8854
9437
  getAllFolders() {
8855
9438
  const pagesDir = this.pagesBaseDir();
8856
- if (!existsSync2(pagesDir)) {
9439
+ if (!existsSync5(pagesDir)) {
8857
9440
  return [];
8858
9441
  }
8859
9442
  const collectFolders = (dir, prefix) => {
@@ -8864,7 +9447,7 @@ var PageService = class {
8864
9447
  if (!entry.isDirectory()) continue;
8865
9448
  const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
8866
9449
  result.push(relativePath);
8867
- result.push(...collectFolders(join3(dir, entry.name), relativePath));
9450
+ result.push(...collectFolders(join4(dir, entry.name), relativePath));
8868
9451
  }
8869
9452
  return result;
8870
9453
  } catch {
@@ -8895,8 +9478,8 @@ var PageService = class {
8895
9478
  }
8896
9479
  }
8897
9480
  const pagesDir = this.pagesBaseDir();
8898
- const folderPath = join3(pagesDir, trimmed);
8899
- if (existsSync2(folderPath)) {
9481
+ const folderPath = join4(pagesDir, trimmed);
9482
+ if (existsSync5(folderPath)) {
8900
9483
  throw new Error("Folder already exists");
8901
9484
  }
8902
9485
  mkdirSync(folderPath, { recursive: true });
@@ -8917,18 +9500,18 @@ var PageService = class {
8917
9500
  const pageName = pagePath === "/" ? "index" : pagePath.substring(1);
8918
9501
  const slashIndex = pageName.lastIndexOf("/");
8919
9502
  const baseName = slashIndex >= 0 ? pageName.substring(slashIndex + 1) : pageName;
8920
- const sourceFile = join3(pagesDir, `${pageName}${ext}`);
8921
- const targetFile = newFolder ? join3(pagesDir, newFolder, `${baseName}${ext}`) : join3(pagesDir, `${baseName}${ext}`);
9503
+ const sourceFile = join4(pagesDir, `${pageName}${ext}`);
9504
+ const targetFile = newFolder ? join4(pagesDir, newFolder, `${baseName}${ext}`) : join4(pagesDir, `${baseName}${ext}`);
8922
9505
  if (!isPathWithinRoot(sourceFile, pagesDir) || !isPathWithinRoot(targetFile, pagesDir)) {
8923
9506
  throw new Error(`movePage path escapes pages dir: ${pagePath} -> ${newFolder}`);
8924
9507
  }
8925
9508
  if (newFolder) {
8926
- const targetDir = join3(pagesDir, newFolder);
8927
- if (!existsSync2(targetDir)) {
9509
+ const targetDir = join4(pagesDir, newFolder);
9510
+ if (!existsSync5(targetDir)) {
8928
9511
  mkdirSync(targetDir, { recursive: true });
8929
9512
  }
8930
9513
  }
8931
- if (!existsSync2(sourceFile)) {
9514
+ if (!existsSync5(sourceFile)) {
8932
9515
  throw new Error(`Page not found: ${pagePath}`);
8933
9516
  }
8934
9517
  await rename2(sourceFile, targetFile);
@@ -8940,7 +9523,7 @@ var PageService = class {
8940
9523
  const lineMap = buildLineMap(content);
8941
9524
  this.pageCache.set(newPath, content, lineMap);
8942
9525
  }
8943
- const sourceDir = slashIndex >= 0 ? join3(pagesDir, pageName.substring(0, slashIndex)) : null;
9526
+ const sourceDir = slashIndex >= 0 ? join4(pagesDir, pageName.substring(0, slashIndex)) : null;
8944
9527
  if (sourceDir && sourceDir !== pagesDir) {
8945
9528
  try {
8946
9529
  const remaining = readdirSync2(sourceDir);
@@ -8989,12 +9572,12 @@ var PageService = class {
8989
9572
  const { rename: rename2 } = await import("node:fs/promises");
8990
9573
  const pagesDir = this.pagesBaseDir();
8991
9574
  const ext = this.pageExt();
8992
- const sourceFile = join3(pagesDir, `${oldName}${ext}`);
8993
- const targetFile = join3(pagesDir, `${newName}${ext}`);
8994
- if (!existsSync2(sourceFile)) {
9575
+ const sourceFile = join4(pagesDir, `${oldName}${ext}`);
9576
+ const targetFile = join4(pagesDir, `${newName}${ext}`);
9577
+ if (!existsSync5(sourceFile)) {
8995
9578
  throw new Error(`Page not found: ${oldPath}`);
8996
9579
  }
8997
- if (existsSync2(targetFile)) {
9580
+ if (existsSync5(targetFile)) {
8998
9581
  throw new Error(`Page already exists: ${newPath}`);
8999
9582
  }
9000
9583
  await rename2(sourceFile, targetFile);
@@ -9044,8 +9627,8 @@ var PageService = class {
9044
9627
  };
9045
9628
 
9046
9629
  // lib/server/services/componentService.ts
9047
- import { join as join4 } from "node:path";
9048
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmdirSync as rmdirSync2 } from "node:fs";
9630
+ import { join as join5 } from "node:path";
9631
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, rmdirSync as rmdirSync2 } from "node:fs";
9049
9632
  var ComponentService = class {
9050
9633
  components = /* @__PURE__ */ new Map();
9051
9634
  componentCategories = /* @__PURE__ */ new Map();
@@ -9277,7 +9860,7 @@ var ComponentService = class {
9277
9860
  const componentsDir = this.componentsBaseDir();
9278
9861
  if (!isSafePathSegment(name)) throw new Error(`unsafe component name: ${name}`);
9279
9862
  const cat = this.resolveComponentCategory(name, category);
9280
- const dir = cat ? join4(componentsDir, cat) : componentsDir;
9863
+ const dir = cat ? join5(componentsDir, cat) : componentsDir;
9281
9864
  if (!isPathWithinRoot(dir, componentsDir)) throw new Error(`component category escapes components dir: ${cat}`);
9282
9865
  return dir;
9283
9866
  }
@@ -9308,10 +9891,10 @@ var ComponentService = class {
9308
9891
  */
9309
9892
  findComponentCategoryOnDisk(name) {
9310
9893
  const componentsDir = this.componentsBaseDir();
9311
- if (!existsSync3(componentsDir)) return void 0;
9894
+ if (!existsSync6(componentsDir)) return void 0;
9312
9895
  const ext = this.writer ? null : ".json";
9313
9896
  const existsAt = (dir) => {
9314
- if (ext) return existsSync3(join4(dir, `${name}${ext}`));
9897
+ if (ext) return existsSync6(join5(dir, `${name}${ext}`));
9315
9898
  try {
9316
9899
  return readdirSync3(dir, { withFileTypes: true }).some(
9317
9900
  (e) => e.isFile() && (e.name === `${name}.json` || e.name === `${name}.astro`)
@@ -9323,7 +9906,7 @@ var ComponentService = class {
9323
9906
  if (existsAt(componentsDir)) return void 0;
9324
9907
  try {
9325
9908
  for (const entry of readdirSync3(componentsDir, { withFileTypes: true })) {
9326
- if (entry.isDirectory() && existsAt(join4(componentsDir, entry.name))) {
9909
+ if (entry.isDirectory() && existsAt(join5(componentsDir, entry.name))) {
9327
9910
  return entry.name;
9328
9911
  }
9329
9912
  }
@@ -9350,7 +9933,7 @@ var ComponentService = class {
9350
9933
  */
9351
9934
  async getComponentJavaScript(name) {
9352
9935
  const componentDir = this.getComponentDir(name);
9353
- const jsFilePath = join4(componentDir, `${name}.js`);
9936
+ const jsFilePath = join5(componentDir, `${name}.js`);
9354
9937
  try {
9355
9938
  if (await fileExists(jsFilePath)) {
9356
9939
  return await readTextFile(jsFilePath);
@@ -9398,15 +9981,15 @@ var ComponentService = class {
9398
9981
  const dataWithJS = javascript !== void 0 ? { ...dataWithoutJS, component: { ...dataWithoutJS.component, javascript } } : dataWithoutJS;
9399
9982
  const targetCategory = this.resolveComponentCategory(name, category);
9400
9983
  const componentsDir = this.componentsBaseDir();
9401
- const componentDir = targetCategory ? join4(componentsDir, targetCategory) : componentsDir;
9984
+ const componentDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
9402
9985
  if (this.writer) {
9403
9986
  await this.writer.writeComponent(componentDir, name, dataWithJS);
9404
9987
  } else {
9405
9988
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9406
- if (targetCategory && !existsSync3(componentDir)) {
9989
+ if (targetCategory && !existsSync6(componentDir)) {
9407
9990
  mkdirSync2(componentDir, { recursive: true });
9408
9991
  }
9409
- const filePath = join4(componentDir, `${name}.json`);
9992
+ const filePath = join5(componentDir, `${name}.json`);
9410
9993
  await writeFile3(filePath, JSON.stringify(dataWithoutJS, null, 2), "utf-8");
9411
9994
  }
9412
9995
  this.components.set(name, dataWithJS);
@@ -9439,9 +10022,9 @@ var ComponentService = class {
9439
10022
  return;
9440
10023
  }
9441
10024
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9442
- const jsFilePath = join4(componentDir, `${name}.js`);
10025
+ const jsFilePath = join5(componentDir, `${name}.js`);
9443
10026
  await writeFile3(jsFilePath, javascript || "", "utf-8");
9444
- const componentPath = join4(componentDir, `${name}.json`);
10027
+ const componentPath = join5(componentDir, `${name}.json`);
9445
10028
  const componentData = await loadJSONFile(componentPath);
9446
10029
  if (componentData) {
9447
10030
  const parsed = parseJSON(componentData);
@@ -9485,9 +10068,9 @@ var ComponentService = class {
9485
10068
  return;
9486
10069
  }
9487
10070
  const writeFile3 = this.fs ? this.fs.writeFile.bind(this.fs) : (await import("node:fs/promises")).writeFile;
9488
- const cssFilePath = join4(componentDir, `${name}.css`);
10071
+ const cssFilePath = join5(componentDir, `${name}.css`);
9489
10072
  await writeFile3(cssFilePath, css || "", "utf-8");
9490
- const componentPath = join4(componentDir, `${name}.json`);
10073
+ const componentPath = join5(componentDir, `${name}.json`);
9491
10074
  const componentData = await loadJSONFile(componentPath);
9492
10075
  if (componentData) {
9493
10076
  const parsed = parseJSON(componentData);
@@ -9520,7 +10103,7 @@ var ComponentService = class {
9520
10103
  */
9521
10104
  getAllFolders() {
9522
10105
  const componentsDir = this.componentsBaseDir();
9523
- if (!existsSync3(componentsDir)) {
10106
+ if (!existsSync6(componentsDir)) {
9524
10107
  return [];
9525
10108
  }
9526
10109
  try {
@@ -9555,8 +10138,8 @@ var ComponentService = class {
9555
10138
  throw new Error("Folder name can only contain lowercase letters, numbers, dashes, and underscores");
9556
10139
  }
9557
10140
  const componentsDir = this.componentsBaseDir();
9558
- const folderPath = join4(componentsDir, folderName);
9559
- if (existsSync3(folderPath)) {
10141
+ const folderPath = join5(componentsDir, folderName);
10142
+ if (existsSync6(folderPath)) {
9560
10143
  throw new Error("Folder already exists");
9561
10144
  }
9562
10145
  mkdirSync2(folderPath, { recursive: true });
@@ -9589,20 +10172,20 @@ var ComponentService = class {
9589
10172
  return;
9590
10173
  }
9591
10174
  const componentsDir = this.componentsBaseDir();
9592
- const sourceDir = currentCategory ? join4(componentsDir, currentCategory) : componentsDir;
9593
- const targetDir = targetCategory ? join4(componentsDir, targetCategory) : componentsDir;
10175
+ const sourceDir = currentCategory ? join5(componentsDir, currentCategory) : componentsDir;
10176
+ const targetDir = targetCategory ? join5(componentsDir, targetCategory) : componentsDir;
9594
10177
  if (this.writer) {
9595
10178
  await this.writer.moveComponent(sourceDir, targetDir, name);
9596
10179
  } else {
9597
- if (targetCategory && !existsSync3(targetDir)) {
10180
+ if (targetCategory && !existsSync6(targetDir)) {
9598
10181
  mkdirSync2(targetDir, { recursive: true });
9599
10182
  }
9600
10183
  const extensions = [".json", ".js", ".css"];
9601
10184
  const { rename: rename2 } = await import("node:fs/promises");
9602
10185
  for (const ext of extensions) {
9603
- const sourcePath = join4(sourceDir, `${name}${ext}`);
9604
- const targetPath = join4(targetDir, `${name}${ext}`);
9605
- if (existsSync3(sourcePath)) {
10186
+ const sourcePath = join5(sourceDir, `${name}${ext}`);
10187
+ const targetPath = join5(targetDir, `${name}${ext}`);
10188
+ if (existsSync6(sourcePath)) {
9606
10189
  await rename2(sourcePath, targetPath);
9607
10190
  }
9608
10191
  }
@@ -9657,7 +10240,7 @@ var ComponentService = class {
9657
10240
  }
9658
10241
  const category = this.componentCategories.get(oldName);
9659
10242
  const componentsDir = this.componentsBaseDir();
9660
- const dir = category ? join4(componentsDir, category) : componentsDir;
10243
+ const dir = category ? join5(componentsDir, category) : componentsDir;
9661
10244
  if (this.writer) {
9662
10245
  if (await this.writer.componentExists(dir, trimmedNew)) {
9663
10246
  throw new Error(`Component "${trimmedNew}" already exists in components/${category ?? ""}`);
@@ -9665,15 +10248,15 @@ var ComponentService = class {
9665
10248
  await this.writer.moveComponent(dir, dir, oldName, trimmedNew);
9666
10249
  } else {
9667
10250
  for (const ext of [".json", ".js", ".css"]) {
9668
- if (existsSync3(join4(dir, `${trimmedNew}${ext}`))) {
10251
+ if (existsSync6(join5(dir, `${trimmedNew}${ext}`))) {
9669
10252
  throw new Error(`File "${trimmedNew}${ext}" already exists in components/${category ?? ""}`);
9670
10253
  }
9671
10254
  }
9672
10255
  const { rename: rename2 } = await import("node:fs/promises");
9673
10256
  for (const ext of [".json", ".js", ".css"]) {
9674
- const src = join4(dir, `${oldName}${ext}`);
9675
- const dst = join4(dir, `${trimmedNew}${ext}`);
9676
- if (existsSync3(src)) {
10257
+ const src = join5(dir, `${oldName}${ext}`);
10258
+ const dst = join5(dir, `${trimmedNew}${ext}`);
10259
+ if (existsSync6(src)) {
9677
10260
  await rename2(src, dst);
9678
10261
  }
9679
10262
  }
@@ -9691,7 +10274,7 @@ var ComponentService = class {
9691
10274
  if (!structure) continue;
9692
10275
  if (rewriteComponentRefs(structure, oldName, trimmedNew)) {
9693
10276
  const otherCategory = this.componentCategories.get(name);
9694
- const otherDir = otherCategory ? join4(componentsDir, otherCategory) : componentsDir;
10277
+ const otherDir = otherCategory ? join5(componentsDir, otherCategory) : componentsDir;
9695
10278
  const persisted = JSON.parse(JSON.stringify(otherDef));
9696
10279
  if (persisted?.component?.javascript !== void 0) {
9697
10280
  delete persisted.component.javascript;
@@ -9699,7 +10282,7 @@ var ComponentService = class {
9699
10282
  if (this.writer) {
9700
10283
  await this.writer.writeComponent(otherDir, name, persisted);
9701
10284
  } else {
9702
- await writeFile3(join4(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
10285
+ await writeFile3(join5(otherDir, `${name}.json`), JSON.stringify(persisted, null, 2), "utf-8");
9703
10286
  }
9704
10287
  componentRefs++;
9705
10288
  }
@@ -10239,9 +10822,9 @@ var CMSService = class {
10239
10822
  };
10240
10823
 
10241
10824
  // lib/server/providers/fileSystemCMSProvider.ts
10242
- import { existsSync as existsSync4, readdirSync as readdirSync4, mkdirSync as mkdirSync3 } from "node:fs";
10243
- import { join as join5 } from "node:path";
10244
- var log5 = createLogger("FileSystemCMSProvider");
10825
+ import { existsSync as existsSync7, readdirSync as readdirSync4, mkdirSync as mkdirSync3 } from "node:fs";
10826
+ import { join as join6 } from "node:path";
10827
+ var log6 = createLogger("FileSystemCMSProvider");
10245
10828
  var DRAFT_FILE_SUFFIX = `${CMS_DRAFT_SUFFIX}.json`;
10246
10829
  async function loadJSONFile2(filePath) {
10247
10830
  try {
@@ -10250,7 +10833,7 @@ async function loadJSONFile2(filePath) {
10250
10833
  }
10251
10834
  return null;
10252
10835
  } catch (error) {
10253
- log5.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
10836
+ log6.warn(`Failed to parse JSON at ${filePath}:`, error instanceof Error ? error.message : error);
10254
10837
  return null;
10255
10838
  }
10256
10839
  }
@@ -10312,14 +10895,14 @@ var FileSystemCMSProvider = class {
10312
10895
  return this.schemaCache;
10313
10896
  }
10314
10897
  const schemas = /* @__PURE__ */ new Map();
10315
- if (!existsSync4(this.templatesDir)) {
10898
+ if (!existsSync7(this.templatesDir)) {
10316
10899
  return schemas;
10317
10900
  }
10318
10901
  const files = readdirSync4(this.templatesDir);
10319
10902
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
10320
10903
  const results = await Promise.all(
10321
10904
  jsonFiles.map(async (file) => {
10322
- const filePath = join5(this.templatesDir, file);
10905
+ const filePath = join6(this.templatesDir, file);
10323
10906
  const content = await loadJSONFile2(filePath);
10324
10907
  return { filePath, content };
10325
10908
  })
@@ -10344,15 +10927,15 @@ var FileSystemCMSProvider = class {
10344
10927
  */
10345
10928
  async getItems(collection) {
10346
10929
  this.validateCollection(collection);
10347
- const collectionDir = join5(this.cmsDir, collection);
10348
- if (!existsSync4(collectionDir)) {
10930
+ const collectionDir = join6(this.cmsDir, collection);
10931
+ if (!existsSync7(collectionDir)) {
10349
10932
  return [];
10350
10933
  }
10351
10934
  const files = readdirSync4(collectionDir);
10352
10935
  const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.endsWith(DRAFT_FILE_SUFFIX));
10353
10936
  const results = await Promise.all(
10354
10937
  jsonFiles.map(async (file) => {
10355
- const filePath = join5(collectionDir, file);
10938
+ const filePath = join6(collectionDir, file);
10356
10939
  const content = await loadJSONFile2(filePath);
10357
10940
  return { file, filePath, content };
10358
10941
  })
@@ -10366,7 +10949,7 @@ var FileSystemCMSProvider = class {
10366
10949
  if (validation.valid) {
10367
10950
  items.push(validation.data);
10368
10951
  } else {
10369
- log5.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10952
+ log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10370
10953
  }
10371
10954
  }
10372
10955
  }
@@ -10385,7 +10968,7 @@ var FileSystemCMSProvider = class {
10385
10968
  async getItemByFilename(collection, filename) {
10386
10969
  this.validateCollection(collection);
10387
10970
  this.validateFilename(filename);
10388
- const filePath = join5(this.cmsDir, collection, `${filename}.json`);
10971
+ const filePath = join6(this.cmsDir, collection, `${filename}.json`);
10389
10972
  const content = await loadJSONFile2(filePath);
10390
10973
  if (!content || typeof content !== "object") {
10391
10974
  return null;
@@ -10395,7 +10978,7 @@ var FileSystemCMSProvider = class {
10395
10978
  if (validation.valid) {
10396
10979
  return validation.data;
10397
10980
  }
10398
- log5.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10981
+ log6.warn(`Invalid CMS item at ${filePath}:`, validation.errors);
10399
10982
  return null;
10400
10983
  }
10401
10984
  /**
@@ -10437,12 +11020,12 @@ var FileSystemCMSProvider = class {
10437
11020
  throw new Error("Cannot derive filename: item is missing _id, _filename, and a usable slug-field value.");
10438
11021
  }
10439
11022
  this.validateFilename(filename);
10440
- const collectionDir = join5(this.cmsDir, collection);
10441
- if (!existsSync4(collectionDir)) {
11023
+ const collectionDir = join6(this.cmsDir, collection);
11024
+ if (!existsSync7(collectionDir)) {
10442
11025
  mkdirSync3(collectionDir, { recursive: true });
10443
11026
  }
10444
11027
  const itemData = stripTransient(item);
10445
- const filePath = join5(collectionDir, `${filename}.json`);
11028
+ const filePath = join6(collectionDir, `${filename}.json`);
10446
11029
  await writeFile3(filePath, JSON.stringify(itemData, null, 2), "utf-8");
10447
11030
  }
10448
11031
  /**
@@ -10452,18 +11035,18 @@ var FileSystemCMSProvider = class {
10452
11035
  this.validateCollection(collection);
10453
11036
  this.validateFilename(filename);
10454
11037
  const { unlink } = await import("node:fs/promises");
10455
- const publishedPath = join5(this.cmsDir, collection, `${filename}.json`);
10456
- if (existsSync4(publishedPath)) {
11038
+ const publishedPath = join6(this.cmsDir, collection, `${filename}.json`);
11039
+ if (existsSync7(publishedPath)) {
10457
11040
  await unlink(publishedPath);
10458
11041
  }
10459
11042
  const draftPath = this.draftPath(collection, filename);
10460
- if (existsSync4(draftPath)) {
11043
+ if (existsSync7(draftPath)) {
10461
11044
  await unlink(draftPath);
10462
11045
  }
10463
11046
  }
10464
11047
  // ---- Draft helpers ----------------------------------------------------
10465
11048
  draftPath(collection, filename) {
10466
- return join5(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
11049
+ return join6(this.cmsDir, collection, `${filename}${DRAFT_FILE_SUFFIX}`);
10467
11050
  }
10468
11051
  /**
10469
11052
  * Get the draft version of an item, or null if no draft file exists.
@@ -10490,12 +11073,12 @@ var FileSystemCMSProvider = class {
10490
11073
  */
10491
11074
  async getAllDrafts(collection) {
10492
11075
  this.validateCollection(collection);
10493
- const collectionDir = join5(this.cmsDir, collection);
10494
- if (!existsSync4(collectionDir)) return [];
11076
+ const collectionDir = join6(this.cmsDir, collection);
11077
+ if (!existsSync7(collectionDir)) return [];
10495
11078
  const files = readdirSync4(collectionDir).filter((f) => f.endsWith(DRAFT_FILE_SUFFIX));
10496
11079
  const results = await Promise.all(
10497
11080
  files.map(async (file) => {
10498
- const filePath = join5(collectionDir, file);
11081
+ const filePath = join6(collectionDir, file);
10499
11082
  const content = await loadJSONFile2(filePath);
10500
11083
  return { file, content };
10501
11084
  })
@@ -10517,7 +11100,7 @@ var FileSystemCMSProvider = class {
10517
11100
  async hasDraft(collection, filename) {
10518
11101
  this.validateCollection(collection);
10519
11102
  this.validateFilename(filename);
10520
- return existsSync4(this.draftPath(collection, filename));
11103
+ return existsSync7(this.draftPath(collection, filename));
10521
11104
  }
10522
11105
  /**
10523
11106
  * Save the draft version of an item. Loose validation — drafts may have
@@ -10551,8 +11134,8 @@ var FileSystemCMSProvider = class {
10551
11134
  throw new Error("Cannot derive draft filename: item is missing _id, _filename, and a usable slug-field value.");
10552
11135
  }
10553
11136
  this.validateFilename(filename);
10554
- const collectionDir = join5(this.cmsDir, collection);
10555
- if (!existsSync4(collectionDir)) {
11137
+ const collectionDir = join6(this.cmsDir, collection);
11138
+ if (!existsSync7(collectionDir)) {
10556
11139
  mkdirSync3(collectionDir, { recursive: true });
10557
11140
  }
10558
11141
  const itemData = stripTransient(item);
@@ -10572,7 +11155,7 @@ var FileSystemCMSProvider = class {
10572
11155
  this.validateFilename(filename);
10573
11156
  const { unlink } = await import("node:fs/promises");
10574
11157
  const filePath = this.draftPath(collection, filename);
10575
- if (existsSync4(filePath)) {
11158
+ if (existsSync7(filePath)) {
10576
11159
  await unlink(filePath);
10577
11160
  }
10578
11161
  }
@@ -10600,14 +11183,14 @@ var FileSystemCMSProvider = class {
10600
11183
  const messages = validation.errors.map((e) => `${e.path}: ${e.message}`).join(", ");
10601
11184
  throw new Error(`Cannot publish invalid draft: ${messages}`);
10602
11185
  }
10603
- const collectionDir = join5(this.cmsDir, collection);
10604
- if (!existsSync4(collectionDir)) {
11186
+ const collectionDir = join6(this.cmsDir, collection);
11187
+ if (!existsSync7(collectionDir)) {
10605
11188
  mkdirSync3(collectionDir, { recursive: true });
10606
11189
  }
10607
11190
  const itemData = stripTransient(validation.data);
10608
- const publishedPath = join5(collectionDir, `${filename}.json`);
11191
+ const publishedPath = join6(collectionDir, `${filename}.json`);
10609
11192
  await writeFile3(publishedPath, JSON.stringify(itemData, null, 2), "utf-8");
10610
- if (existsSync4(draftFilePath)) {
11193
+ if (existsSync7(draftFilePath)) {
10611
11194
  await unlink(draftFilePath);
10612
11195
  }
10613
11196
  return normalizeItem(itemData, filename);
@@ -10628,18 +11211,18 @@ var FileSystemCMSProvider = class {
10628
11211
  );
10629
11212
  }
10630
11213
  const { writeFile: writeFile3, mkdir } = await import("node:fs/promises");
10631
- if (!existsSync4(this.templatesDir)) {
11214
+ if (!existsSync7(this.templatesDir)) {
10632
11215
  await mkdir(this.templatesDir, { recursive: true });
10633
11216
  }
10634
- const pageFilePath = join5(this.templatesDir, `${collectionId}.json`);
10635
- if (existsSync4(pageFilePath)) {
11217
+ const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
11218
+ if (existsSync7(pageFilePath)) {
10636
11219
  throw new Error(`Page file already exists: templates/${collectionId}.json`);
10637
11220
  }
10638
11221
  await writeFile3(pageFilePath, JSON.stringify(pageData, null, 2), "utf-8");
10639
11222
  const schemaSource = pageData?.meta?.cms?.source;
10640
11223
  if (schemaSource !== "sanity") {
10641
- const collectionDir = join5(this.cmsDir, collectionId);
10642
- if (!existsSync4(collectionDir)) {
11224
+ const collectionDir = join6(this.cmsDir, collectionId);
11225
+ if (!existsSync7(collectionDir)) {
10643
11226
  await mkdir(collectionDir, { recursive: true });
10644
11227
  }
10645
11228
  }
@@ -10656,8 +11239,8 @@ var FileSystemCMSProvider = class {
10656
11239
  );
10657
11240
  }
10658
11241
  const { readFile: readFile2, writeFile: writeFile3 } = await import("node:fs/promises");
10659
- const pageFilePath = join5(this.templatesDir, `${collectionId}.json`);
10660
- if (!existsSync4(pageFilePath)) {
11242
+ const pageFilePath = join6(this.templatesDir, `${collectionId}.json`);
11243
+ if (!existsSync7(pageFilePath)) {
10661
11244
  throw new Error(`Collection not found: ${collectionId}`);
10662
11245
  }
10663
11246
  const content = await readFile2(pageFilePath, "utf-8");
@@ -10783,8 +11366,8 @@ var DraftPageStore = class {
10783
11366
  };
10784
11367
 
10785
11368
  // lib/server/fileWatcher.ts
10786
- import { watch, existsSync as existsSync5, statSync, readdirSync as readdirSync5 } from "node:fs";
10787
- import { basename as basename2, dirname as dirname2, join as join6, relative } from "node:path";
11369
+ import { watch, existsSync as existsSync8, statSync, readdirSync as readdirSync5 } from "node:fs";
11370
+ import { basename as basename2, dirname as dirname2, join as join7, relative } from "node:path";
10788
11371
  function watchRecursive(root, listener) {
10789
11372
  const nested = [];
10790
11373
  const watchedDirs = /* @__PURE__ */ new Set();
@@ -10800,7 +11383,7 @@ function watchRecursive(root, listener) {
10800
11383
  attachDir(abs);
10801
11384
  try {
10802
11385
  for (const e of readdirSync5(abs, { withFileTypes: true })) {
10803
- const child = join6(abs, e.name);
11386
+ const child = join7(abs, e.name);
10804
11387
  if (e.isDirectory()) coverNewDir(child);
10805
11388
  else listener("rename", relative(root, child));
10806
11389
  }
@@ -10814,7 +11397,7 @@ function watchRecursive(root, listener) {
10814
11397
  try {
10815
11398
  w = watch(absDir, { recursive: true }, (event, filename) => {
10816
11399
  if (!filename) return;
10817
- const abs = join6(absDir, filename);
11400
+ const abs = join7(absDir, filename);
10818
11401
  listener(event, relative(root, abs));
10819
11402
  coverNewDir(abs);
10820
11403
  });
@@ -10840,19 +11423,19 @@ function watchRecursive(root, listener) {
10840
11423
  return handle;
10841
11424
  }
10842
11425
  function attachWhenDirExists(dirPath, attach, setWatcher) {
10843
- if (existsSync5(dirPath)) {
11426
+ if (existsSync8(dirPath)) {
10844
11427
  setWatcher(attach());
10845
11428
  return;
10846
11429
  }
10847
11430
  const parentDir = dirname2(dirPath);
10848
11431
  const targetName = basename2(dirPath);
10849
- if (!existsSync5(parentDir)) {
11432
+ if (!existsSync8(parentDir)) {
10850
11433
  return;
10851
11434
  }
10852
11435
  let parentWatcher = null;
10853
11436
  parentWatcher = watch(parentDir, (_event, filename) => {
10854
11437
  if (filename !== targetName) return;
10855
- if (!existsSync5(dirPath)) return;
11438
+ if (!existsSync8(dirPath)) return;
10856
11439
  parentWatcher?.close();
10857
11440
  parentWatcher = null;
10858
11441
  setWatcher(attach());
@@ -10882,7 +11465,7 @@ var FileWatcher = class {
10882
11465
  * Watches both .json and .js files to detect component definition and JavaScript changes
10883
11466
  */
10884
11467
  watchComponents(dirPath = projectPaths.components()) {
10885
- if (!existsSync5(dirPath)) {
11468
+ if (!existsSync8(dirPath)) {
10886
11469
  return;
10887
11470
  }
10888
11471
  this.componentsWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -10898,7 +11481,7 @@ var FileWatcher = class {
10898
11481
  * Start watching pages directory
10899
11482
  */
10900
11483
  watchPages(dirPath = projectPaths.pages()) {
10901
- if (!existsSync5(dirPath)) {
11484
+ if (!existsSync8(dirPath)) {
10902
11485
  return;
10903
11486
  }
10904
11487
  this.pagesWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -10938,7 +11521,7 @@ var FileWatcher = class {
10938
11521
  * Start watching colors.json file
10939
11522
  */
10940
11523
  watchColors(filePath = projectPaths.colors()) {
10941
- if (!existsSync5(filePath)) {
11524
+ if (!existsSync8(filePath)) {
10942
11525
  return;
10943
11526
  }
10944
11527
  const dirPath = getProjectRoot();
@@ -10995,7 +11578,7 @@ var FileWatcher = class {
10995
11578
  * Start watching images directory for new source images
10996
11579
  */
10997
11580
  watchImages(dirPath = projectPaths.images()) {
10998
- if (!existsSync5(dirPath)) {
11581
+ if (!existsSync8(dirPath)) {
10999
11582
  return;
11000
11583
  }
11001
11584
  this.imagesWatcher = watch(dirPath, { recursive: false }, async (event, filename) => {
@@ -11022,7 +11605,7 @@ var FileWatcher = class {
11022
11605
  * Start watching libraries directory for CSS/JS changes
11023
11606
  */
11024
11607
  watchLibraries(dirPath = projectPaths.libraries()) {
11025
- if (!existsSync5(dirPath)) {
11608
+ if (!existsSync8(dirPath)) {
11026
11609
  return;
11027
11610
  }
11028
11611
  this.librariesWatcher = watchRecursive(dirPath, async (_event, filename) => {
@@ -11046,7 +11629,7 @@ var FileWatcher = class {
11046
11629
  * early-out and the first collection's item edits wouldn't live-reload until a
11047
11630
  * dev-server restart.
11048
11631
  */
11049
- watchAstroPages(dirPath = join6(getProjectRoot(), "src", "pages")) {
11632
+ watchAstroPages(dirPath = join7(getProjectRoot(), "src", "pages")) {
11050
11633
  attachWhenDirExists(
11051
11634
  dirPath,
11052
11635
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11063,7 +11646,7 @@ var FileWatcher = class {
11063
11646
  }
11064
11647
  );
11065
11648
  }
11066
- watchAstroComponents(dirPath = join6(getProjectRoot(), "src", "components")) {
11649
+ watchAstroComponents(dirPath = join7(getProjectRoot(), "src", "components")) {
11067
11650
  attachWhenDirExists(
11068
11651
  dirPath,
11069
11652
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11076,7 +11659,7 @@ var FileWatcher = class {
11076
11659
  }
11077
11660
  );
11078
11661
  }
11079
- watchAstroContent(dirPath = join6(getProjectRoot(), "src", "content")) {
11662
+ watchAstroContent(dirPath = join7(getProjectRoot(), "src", "content")) {
11080
11663
  attachWhenDirExists(
11081
11664
  dirPath,
11082
11665
  () => watchRecursive(dirPath, async (_event, filename) => {
@@ -11279,22 +11862,22 @@ var FileWatcherService = class {
11279
11862
  };
11280
11863
 
11281
11864
  // lib/server/migrateTemplates.ts
11282
- import { existsSync as existsSync6 } from "node:fs";
11865
+ import { existsSync as existsSync9 } from "node:fs";
11283
11866
  import { rename } from "node:fs/promises";
11284
- import { join as join7 } from "node:path";
11867
+ import { join as join8 } from "node:path";
11285
11868
  async function migrateTemplatesDirectory() {
11286
- const oldDir = join7(projectPaths.pages(), "templates");
11869
+ const oldDir = join8(projectPaths.pages(), "templates");
11287
11870
  const newDir = projectPaths.templates();
11288
- if (!existsSync6(oldDir)) return;
11289
- if (existsSync6(newDir)) return;
11871
+ if (!existsSync9(oldDir)) return;
11872
+ if (existsSync9(newDir)) return;
11290
11873
  await rename(oldDir, newDir);
11291
11874
  console.log("Migrated CMS templates: pages/templates/ \u2192 templates/");
11292
11875
  }
11293
11876
 
11294
11877
  // build-astro.ts
11295
- import { existsSync as existsSync7, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
11878
+ import { existsSync as existsSync10, readdirSync as readdirSync6, mkdirSync as mkdirSync4, rmSync, statSync as statSync2, copyFileSync, writeFileSync } from "node:fs";
11296
11879
  import { writeFile as writeFile2, readFile } from "node:fs/promises";
11297
- import { join as join8 } from "node:path";
11880
+ import { join as join9 } from "node:path";
11298
11881
  import { createHash } from "node:crypto";
11299
11882
 
11300
11883
  // lib/server/astro/tailwindMapper.ts
@@ -14147,23 +14730,23 @@ function writePageScript(javascript, scriptsDir) {
14147
14730
  if (!javascript) return [];
14148
14731
  const hash = hashContent3(javascript);
14149
14732
  const scriptFile = `${hash}.js`;
14150
- if (!existsSync7(scriptsDir)) {
14733
+ if (!existsSync10(scriptsDir)) {
14151
14734
  mkdirSync4(scriptsDir, { recursive: true });
14152
14735
  }
14153
- const fullScriptPath = join8(scriptsDir, scriptFile);
14154
- if (!existsSync7(fullScriptPath)) {
14736
+ const fullScriptPath = join9(scriptsDir, scriptFile);
14737
+ if (!existsSync10(fullScriptPath)) {
14155
14738
  writeFileSync(fullScriptPath, javascript, "utf-8");
14156
14739
  }
14157
14740
  return [`/_scripts/${scriptFile}`];
14158
14741
  }
14159
14742
  function copyDirectory(src, dest, filter) {
14160
- if (!existsSync7(src)) return;
14161
- if (!existsSync7(dest)) mkdirSync4(dest, { recursive: true });
14743
+ if (!existsSync10(src)) return;
14744
+ if (!existsSync10(dest)) mkdirSync4(dest, { recursive: true });
14162
14745
  const files = readdirSync6(src);
14163
14746
  for (const file of files) {
14164
14747
  if (filter && !filter(file)) continue;
14165
- const srcPath = join8(src, file);
14166
- const destPath = join8(dest, file);
14748
+ const srcPath = join9(src, file);
14749
+ const destPath = join9(dest, file);
14167
14750
  const stat = statSync2(srcPath);
14168
14751
  if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
14169
14752
  else copyFileSync(srcPath, destPath);
@@ -14180,13 +14763,13 @@ function isCMSPage(pageData) {
14180
14763
  }
14181
14764
  function scanJSONFiles(dir, prefix = "") {
14182
14765
  const results = [];
14183
- if (!existsSync7(dir)) return results;
14766
+ if (!existsSync10(dir)) return results;
14184
14767
  const entries = readdirSync6(dir, { withFileTypes: true });
14185
14768
  for (const entry of entries) {
14186
14769
  if (entry.isFile() && entry.name.endsWith(".json")) {
14187
14770
  results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
14188
14771
  } else if (entry.isDirectory()) {
14189
- results.push(...scanJSONFiles(join8(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
14772
+ results.push(...scanJSONFiles(join9(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
14190
14773
  }
14191
14774
  }
14192
14775
  return results;
@@ -14352,23 +14935,23 @@ async function buildAstroProject(_projectRoot, outputDir) {
14352
14935
  const globalLibraries = configService.getLibraries();
14353
14936
  const componentLibraries = collectComponentLibraries(globalComponents);
14354
14937
  const imageMetadataMap = await buildImageMetadataMap();
14355
- const outDir = outputDir || join8(projectPaths.project, "astro-export");
14356
- if (existsSync7(outDir)) {
14938
+ const outDir = outputDir || join9(projectPaths.project, "astro-export");
14939
+ if (existsSync10(outDir)) {
14357
14940
  rmSync(outDir, { recursive: true, force: true });
14358
14941
  }
14359
14942
  mkdirSync4(outDir, { recursive: true });
14360
- const srcDir = join8(outDir, "src");
14361
- const pagesOutDir = join8(srcDir, "pages");
14362
- const layoutsDir = join8(srcDir, "layouts");
14363
- const stylesDir = join8(srcDir, "styles");
14364
- const componentsOutDir = join8(srcDir, "components");
14365
- const publicDir = join8(outDir, "public");
14366
- const scriptsDir = join8(publicDir, "_scripts");
14943
+ const srcDir = join9(outDir, "src");
14944
+ const pagesOutDir = join9(srcDir, "pages");
14945
+ const layoutsDir = join9(srcDir, "layouts");
14946
+ const stylesDir = join9(srcDir, "styles");
14947
+ const componentsOutDir = join9(srcDir, "components");
14948
+ const publicDir = join9(outDir, "public");
14949
+ const scriptsDir = join9(publicDir, "_scripts");
14367
14950
  for (const d of [srcDir, pagesOutDir, layoutsDir, stylesDir, componentsOutDir, publicDir]) {
14368
14951
  mkdirSync4(d, { recursive: true });
14369
14952
  }
14370
14953
  const pagesDir = projectPaths.pages();
14371
- if (!existsSync7(pagesDir)) {
14954
+ if (!existsSync10(pagesDir)) {
14372
14955
  console.error("Pages directory not found!");
14373
14956
  return { pages: 0, cmsPages: 0, collections: 0, errors: 1 };
14374
14957
  }
@@ -14381,7 +14964,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14381
14964
  for (const file of pageFiles) {
14382
14965
  const pageName = file.replace(".json", "");
14383
14966
  const basePath = mapPageNameToPath(pageName);
14384
- const pageContent = await loadJSONFile(join8(pagesDir, file));
14967
+ const pageContent = await loadJSONFile(join9(pagesDir, file));
14385
14968
  if (!pageContent) continue;
14386
14969
  try {
14387
14970
  const pageData = parseJSON(pageContent);
@@ -14440,7 +15023,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14440
15023
  for (const file of pageFiles) {
14441
15024
  const pageName = file.replace(".json", "");
14442
15025
  const basePath = mapPageNameToPath(pageName);
14443
- const pageContent = await loadJSONFile(join8(pagesDir, file));
15026
+ const pageContent = await loadJSONFile(join9(pagesDir, file));
14444
15027
  if (!pageContent) {
14445
15028
  console.warn(` Skipping ${basePath} (empty file)`);
14446
15029
  errorCount++;
@@ -14498,8 +15081,8 @@ async function buildAstroProject(_projectRoot, outputDir) {
14498
15081
  if (!css.url.startsWith("/")) continue;
14499
15082
  const shouldInline = css.inline !== false;
14500
15083
  const relPath = css.url.slice(1);
14501
- const srcPath = join8(projectPaths.project, relPath);
14502
- if (!existsSync7(srcPath)) continue;
15084
+ const srcPath = join9(projectPaths.project, relPath);
15085
+ if (!existsSync10(srcPath)) continue;
14503
15086
  if (shouldInline) {
14504
15087
  try {
14505
15088
  inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
@@ -14513,7 +15096,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14513
15096
  for (const js of buildLibraries.js || []) {
14514
15097
  if (js.url.startsWith("/")) {
14515
15098
  const relPath = js.url.slice(1);
14516
- if (existsSync7(join8(projectPaths.project, relPath))) {
15099
+ if (existsSync10(join9(projectPaths.project, relPath))) {
14517
15100
  localLibsToCopy.push(relPath);
14518
15101
  }
14519
15102
  }
@@ -14534,9 +15117,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
14534
15117
  const cmsConsumerComponents = computeCmsConsumerComponents(globalComponents);
14535
15118
  const collectionUrlExpr = /* @__PURE__ */ new Map();
14536
15119
  const mergedRichTextFields = /* @__PURE__ */ new Set();
14537
- if (existsSync7(templatesDir)) {
15120
+ if (existsSync10(templatesDir)) {
14538
15121
  for (const file of readdirSync6(templatesDir).filter((f) => f.endsWith(".json"))) {
14539
- const tc = await loadJSONFile(join8(templatesDir, file));
15122
+ const tc = await loadJSONFile(join9(templatesDir, file));
14540
15123
  if (!tc) continue;
14541
15124
  try {
14542
15125
  const pd = parseJSON(tc);
@@ -14550,10 +15133,10 @@ async function buildAstroProject(_projectRoot, outputDir) {
14550
15133
  }
14551
15134
  }
14552
15135
  }
14553
- if (existsSync7(templatesDir)) {
15136
+ if (existsSync10(templatesDir)) {
14554
15137
  const templateFiles = readdirSync6(templatesDir).filter((f) => f.endsWith(".json"));
14555
15138
  for (const file of templateFiles) {
14556
- const templateContent = await loadJSONFile(join8(templatesDir, file));
15139
+ const templateContent = await loadJSONFile(join9(templatesDir, file));
14557
15140
  if (!templateContent) continue;
14558
15141
  try {
14559
15142
  const pageData = parseJSON(templateContent);
@@ -14642,9 +15225,9 @@ async function buildAstroProject(_projectRoot, outputDir) {
14642
15225
  cmsConsumers: cmsConsumerComponents,
14643
15226
  collectionUrlExpr
14644
15227
  });
14645
- const astroFileFull = join8(pagesOutDir, astroFilePath);
15228
+ const astroFileFull = join9(pagesOutDir, astroFilePath);
14646
15229
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
14647
- if (!existsSync7(astroFileDir)) {
15230
+ if (!existsSync10(astroFileDir)) {
14648
15231
  mkdirSync4(astroFileDir, { recursive: true });
14649
15232
  }
14650
15233
  await writeFile2(astroFileFull, astroContent, "utf-8");
@@ -14676,7 +15259,7 @@ async function buildAstroProject(_projectRoot, outputDir) {
14676
15259
 
14677
15260
  ${safelistDirectives}` : `@import "tailwindcss";`;
14678
15261
  const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined].filter(Boolean).join("\n\n");
14679
- await writeFile2(join8(stylesDir, "global.css"), globalCSS, "utf-8");
15262
+ await writeFile2(join9(stylesDir, "global.css"), globalCSS, "utf-8");
14680
15263
  const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
14681
15264
  const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
14682
15265
  const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
@@ -14723,7 +15306,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14723
15306
  </body>
14724
15307
  </html>
14725
15308
  `;
14726
- await writeFile2(join8(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
15309
+ await writeFile2(join9(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
14727
15310
  const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
14728
15311
  let _componentFileCount = 0;
14729
15312
  for (const [compName, compDef] of Object.entries(emittableComponents)) {
@@ -14742,7 +15325,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14742
15325
  collectionUrlExpr
14743
15326
  }
14744
15327
  );
14745
- await writeFile2(join8(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
15328
+ await writeFile2(join9(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
14746
15329
  _componentFileCount++;
14747
15330
  } catch (error) {
14748
15331
  console.warn(
@@ -14793,9 +15376,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
14793
15376
  scriptPaths = writePageScript(result.javascript, scriptsDir);
14794
15377
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
14795
15378
  }
14796
- const astroFileFull = join8(pagesOutDir, result.astroFilePath);
15379
+ const astroFileFull = join9(pagesOutDir, result.astroFilePath);
14797
15380
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
14798
- if (!existsSync7(astroFileDir)) {
15381
+ if (!existsSync10(astroFileDir)) {
14799
15382
  mkdirSync4(astroFileDir, { recursive: true });
14800
15383
  }
14801
15384
  await writeFile2(astroFileFull, astroContent, "utf-8");
@@ -14816,31 +15399,31 @@ export const GET: APIRoute = () => {
14816
15399
  });
14817
15400
  };
14818
15401
  `;
14819
- await writeFile2(join8(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
15402
+ await writeFile2(join9(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
14820
15403
  let collectionCount = 0;
14821
15404
  if (templateSchemas.length > 0) {
14822
- const contentDir = join8(srcDir, "content");
15405
+ const contentDir = join9(srcDir, "content");
14823
15406
  mkdirSync4(contentDir, { recursive: true });
14824
15407
  const collectionDefs = [];
14825
15408
  for (const schema of templateSchemas) {
14826
- const collectionDir = join8(contentDir, schema.id);
15409
+ const collectionDir = join9(contentDir, schema.id);
14827
15410
  mkdirSync4(collectionDir, { recursive: true });
14828
15411
  const richTextFieldNames = Object.entries(schema.fields || {}).filter(([, fd]) => fd.type === "rich-text").map(([fn]) => fn);
14829
- const cmsItemsDir = join8(projectPaths.cms(), schema.id);
14830
- if (existsSync7(cmsItemsDir)) {
15412
+ const cmsItemsDir = join9(projectPaths.cms(), schema.id);
15413
+ if (existsSync10(cmsItemsDir)) {
14831
15414
  const isDevBuild = process.env.MENO_DEV_BUILD === "true";
14832
15415
  const itemFiles = readdirSync6(cmsItemsDir).filter(
14833
15416
  (f) => f.endsWith(".json") && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`))
14834
15417
  );
14835
15418
  for (const itemFile of itemFiles) {
14836
15419
  try {
14837
- const rawContent = await readFile(join8(cmsItemsDir, itemFile), "utf-8");
15420
+ const rawContent = await readFile(join9(cmsItemsDir, itemFile), "utf-8");
14838
15421
  const item = JSON.parse(rawContent);
14839
15422
  const resolved = { ...item };
14840
15423
  for (const fieldName of richTextFieldNames) {
14841
15424
  resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
14842
15425
  }
14843
- await writeFile2(join8(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
15426
+ await writeFile2(join9(collectionDir, itemFile), JSON.stringify(resolved, null, 2), "utf-8");
14844
15427
  } catch (err) {
14845
15428
  console.warn(
14846
15429
  ` Warning: could not process CMS item ${itemFile}: ${err instanceof Error ? err.message : String(err)}`
@@ -14873,29 +15456,29 @@ ${collectionDefs.join(",\n")}
14873
15456
 
14874
15457
  export { collections };
14875
15458
  `;
14876
- await writeFile2(join8(srcDir, "content.config.ts"), configContent, "utf-8");
15459
+ await writeFile2(join9(srcDir, "content.config.ts"), configContent, "utf-8");
14877
15460
  }
14878
- const imagesSrcDir = join8(projectPaths.project, "images");
14879
- if (existsSync7(imagesSrcDir)) {
14880
- copyDirectory(imagesSrcDir, join8(srcDir, "assets", "images"), shouldCopyImageForAstro);
14881
- copyDirectory(imagesSrcDir, join8(publicDir, "images"));
15461
+ const imagesSrcDir = join9(projectPaths.project, "images");
15462
+ if (existsSync10(imagesSrcDir)) {
15463
+ copyDirectory(imagesSrcDir, join9(srcDir, "assets", "images"), shouldCopyImageForAstro);
15464
+ copyDirectory(imagesSrcDir, join9(publicDir, "images"));
14882
15465
  }
14883
15466
  const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
14884
15467
  for (const dir of publicAssetDirs) {
14885
- const srcAssetDir = join8(projectPaths.project, dir);
14886
- if (existsSync7(srcAssetDir)) {
14887
- copyDirectory(srcAssetDir, join8(publicDir, dir));
15468
+ const srcAssetDir = join9(projectPaths.project, dir);
15469
+ if (existsSync10(srcAssetDir)) {
15470
+ copyDirectory(srcAssetDir, join9(publicDir, dir));
14888
15471
  }
14889
15472
  }
14890
- const librariesDir = join8(projectPaths.project, "libraries");
14891
- if (existsSync7(librariesDir)) {
14892
- copyDirectory(librariesDir, join8(publicDir, "libraries"));
15473
+ const librariesDir = join9(projectPaths.project, "libraries");
15474
+ if (existsSync10(librariesDir)) {
15475
+ copyDirectory(librariesDir, join9(publicDir, "libraries"));
14893
15476
  }
14894
15477
  for (const relPath of localLibsToCopy) {
14895
- const srcPath = join8(projectPaths.project, relPath);
14896
- const destPath = join8(publicDir, relPath);
15478
+ const srcPath = join9(projectPaths.project, relPath);
15479
+ const destPath = join9(publicDir, relPath);
14897
15480
  const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
14898
- if (destDir && !existsSync7(destDir)) mkdirSync4(destDir, { recursive: true });
15481
+ if (destDir && !existsSync10(destDir)) mkdirSync4(destDir, { recursive: true });
14899
15482
  copyFileSync(srcPath, destPath);
14900
15483
  }
14901
15484
  const packageJson = {
@@ -14918,7 +15501,7 @@ export { collections };
14918
15501
  tailwindcss: "^4.0.0"
14919
15502
  }
14920
15503
  };
14921
- await writeFile2(join8(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
15504
+ await writeFile2(join9(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
14922
15505
  const localeCodes = i18nConfig.locales.map((l) => l.code);
14923
15506
  const i18nBlock = i18nConfig.locales.length > 1 ? `
14924
15507
  i18n: {
@@ -14938,11 +15521,11 @@ export default defineConfig({${siteUrl ? `
14938
15521
  },
14939
15522
  });
14940
15523
  `;
14941
- await writeFile2(join8(outDir, "astro.config.mjs"), astroConfig, "utf-8");
15524
+ await writeFile2(join9(outDir, "astro.config.mjs"), astroConfig, "utf-8");
14942
15525
  const tsConfig = {
14943
15526
  extends: "astro/tsconfigs/strict"
14944
15527
  };
14945
- await writeFile2(join8(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
15528
+ await writeFile2(join9(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
14946
15529
  const baseNetlifyToml = `# Generated by Meno's Astro build.
14947
15530
  [build]
14948
15531
  command = "npm run build"
@@ -14952,8 +15535,8 @@ export default defineConfig({${siteUrl ? `
14952
15535
  NODE_VERSION = "22"
14953
15536
  `;
14954
15537
  const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes("404.json"));
14955
- await writeFile2(join8(outDir, "netlify.toml"), netlifyToml, "utf-8");
14956
- await writeFile2(join8(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
15538
+ await writeFile2(join9(outDir, "netlify.toml"), netlifyToml, "utf-8");
15539
+ await writeFile2(join9(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
14957
15540
  const totalPages = allResults.length;
14958
15541
  return {
14959
15542
  pages: totalPages - cmsPageCount,
@@ -15017,6 +15600,7 @@ export {
15017
15600
  getModuleDir,
15018
15601
  getPackageRoot,
15019
15602
  getProjectRoot,
15603
+ groupForSectionLabel,
15020
15604
  handleCollectionSchemaRoute,
15021
15605
  handleCollectionsRoute,
15022
15606
  handleCoreApiRoutes,
@@ -15025,11 +15609,15 @@ export {
15025
15609
  handleItemsRoute,
15026
15610
  handleRouteError,
15027
15611
  hashContent,
15612
+ inferGroup,
15028
15613
  inspect,
15029
15614
  isBun3 as isBun,
15615
+ isColorValue,
15616
+ isThemeCssProject,
15030
15617
  jsonResponse,
15031
15618
  lineMapToObject,
15032
15619
  loadProjectConfig,
15620
+ loadThemeModel,
15033
15621
  logError,
15034
15622
  logRequest,
15035
15623
  logResponseTime,
@@ -15039,19 +15627,25 @@ export {
15039
15627
  needsFormHandler,
15040
15628
  needsMenoFilter,
15041
15629
  packagePaths,
15630
+ parseThemeCss,
15042
15631
  processCMSPropsTemplate,
15043
15632
  processCMSTemplate,
15044
15633
  projectPaths,
15045
15634
  readJsonFile,
15046
15635
  readTextFile,
15636
+ regenerateThemeCss,
15047
15637
  renderPageSSR,
15048
15638
  resetFontConfig,
15049
15639
  resolvePackagePath,
15050
15640
  resolveProjectPath,
15641
+ saveColors,
15642
+ saveVariables,
15643
+ serializeThemeCss,
15051
15644
  serveFile,
15052
15645
  setProjectRoot,
15053
15646
  spawnProcess,
15054
15647
  styleToString,
15648
+ themeCssPath,
15055
15649
  validateJS,
15056
15650
  variableService,
15057
15651
  watchRecursive,