@motion-proto/live-tokens 0.16.2 → 0.17.1

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.
@@ -1,17 +1,14 @@
1
- // vite-plugin/themeFileApi.ts
2
- import fs3 from "fs";
3
- import path3 from "path";
1
+ import {
2
+ TOKENS_CSS_MIGRATIONS,
3
+ extractGlobalRootBody,
4
+ resolveDataDirs,
5
+ runTokensCssMigrations,
6
+ validateTokensCss
7
+ } from "./chunk-UBS57IYV.js";
4
8
 
5
- // src/editor/core/themes/parsers/globalRootBlock.ts
6
- function extractGlobalRootBody(source) {
7
- const re = /:global\(:root\)\s*\{([^}]*)\}/g;
8
- const bodies = [];
9
- let m;
10
- while ((m = re.exec(source)) !== null) {
11
- bodies.push(m[1]);
12
- }
13
- return bodies.join("\n");
14
- }
9
+ // vite-plugin/themeFileApi.ts
10
+ import fs2 from "fs";
11
+ import path2 from "path";
15
12
 
16
13
  // src/editor/core/storage/files/versionedFileResourceClient.ts
17
14
  function sanitizeFileName(name) {
@@ -520,63 +517,18 @@ function nextAvailableName(exists, baseName, maxAttempts = 1e3) {
520
517
  throw new Error(`Could not allocate a non-colliding name for "${baseName}"`);
521
518
  }
522
519
 
523
- // vite-plugin/files/dataPaths.ts
524
- import fs2 from "fs";
525
- import path2 from "path";
526
- var DEFAULT_DATA_DIR = "src/live-tokens/data";
527
- var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
528
- "dataDir",
529
- "themesDir",
530
- "componentConfigsDir",
531
- "manifestsDir"
532
- ]);
533
- var cached = null;
534
- function readLiveTokensConfig() {
535
- if (cached) return cached;
536
- try {
537
- const configPath = path2.resolve("live-tokens.config.json");
538
- if (!fs2.existsSync(configPath)) return cached = {};
539
- const parsed = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
540
- if (!parsed || typeof parsed !== "object") return cached = {};
541
- const unknown = Object.keys(parsed).filter(
542
- (k) => k !== "$schema" && !KNOWN_CONFIG_KEYS.has(k)
543
- );
544
- if (unknown.length > 0) {
545
- console.warn(
546
- `[live-tokens] Unknown key(s) in live-tokens.config.json: ${unknown.join(", ")}. Known keys: ${Array.from(KNOWN_CONFIG_KEYS).join(", ")}.`
547
- );
548
- }
549
- cached = parsed;
550
- return cached;
551
- } catch {
552
- return cached = {};
553
- }
554
- }
555
- function resolveDataDirs(opts = {}) {
556
- const fileConfig = readLiveTokensConfig();
557
- const dataDirRaw = opts.dataDir ?? fileConfig.dataDir ?? DEFAULT_DATA_DIR;
558
- const dataDir = path2.resolve(dataDirRaw);
559
- const sub = (name) => path2.resolve(dataDir, name);
560
- return {
561
- dataDir,
562
- themesDir: opts.themesDir ? path2.resolve(opts.themesDir) : fileConfig.themesDir ? path2.resolve(fileConfig.themesDir) : sub("themes"),
563
- componentConfigsDir: opts.componentConfigsDir ? path2.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? path2.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
564
- manifestsDir: opts.manifestsDir ? path2.resolve(opts.manifestsDir) : fileConfig.manifestsDir ? path2.resolve(fileConfig.manifestsDir) : sub("manifests")
565
- };
566
- }
567
-
568
520
  // vite-plugin/themeFileApi.ts
569
521
  import { fileURLToPath } from "url";
570
522
  var PKG_VERSION = (() => {
571
523
  try {
572
- let dir = path3.dirname(fileURLToPath(import.meta.url));
524
+ let dir = path2.dirname(fileURLToPath(import.meta.url));
573
525
  for (let i = 0; i < 4; i++) {
574
- const p = path3.join(dir, "package.json");
575
- if (fs3.existsSync(p)) {
576
- const json = JSON.parse(fs3.readFileSync(p, "utf-8"));
526
+ const p = path2.join(dir, "package.json");
527
+ if (fs2.existsSync(p)) {
528
+ const json = JSON.parse(fs2.readFileSync(p, "utf-8"));
577
529
  if (json?.name === "@motion-proto/live-tokens") return json.version ?? "";
578
530
  }
579
- const up = path3.dirname(dir);
531
+ const up = path2.dirname(dir);
580
532
  if (up === dir) break;
581
533
  dir = up;
582
534
  }
@@ -594,23 +546,23 @@ function themeFileApi(opts) {
594
546
  const THEMES_DIR = dataDirs.themesDir;
595
547
  const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
596
548
  const MANIFESTS_DIR = dataDirs.manifestsDir;
597
- const CSS_PATH = path3.resolve(opts.tokensCssPath);
598
- const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? path3.resolve(opts.tokensGeneratedCssPath) : path3.join(dataDirs.dataDir, "tokens.generated.css");
599
- const FONTS_CSS_PATH = opts.fontsCssPath ? path3.resolve(opts.fontsCssPath) : path3.join(path3.dirname(CSS_PATH), "fonts.css");
549
+ const CSS_PATH = path2.resolve(opts.tokensCssPath);
550
+ const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? path2.resolve(opts.tokensGeneratedCssPath) : path2.join(dataDirs.dataDir, "tokens.generated.css");
551
+ const FONTS_CSS_PATH = opts.fontsCssPath ? path2.resolve(opts.fontsCssPath) : path2.join(path2.dirname(CSS_PATH), "fonts.css");
600
552
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
601
- const consumerComponentDirs = opts.componentsSrcDir ? [path3.resolve(opts.componentsSrcDir)] : [path3.resolve("src/components"), path3.resolve("src/system/components")];
602
- const packageComponentsDir = path3.resolve(
603
- path3.dirname(fileURLToPath(import.meta.url)),
553
+ const consumerComponentDirs = opts.componentsSrcDir ? [path2.resolve(opts.componentsSrcDir)] : [path2.resolve("src/components"), path2.resolve("src/system/components")];
554
+ const packageComponentsDir = path2.resolve(
555
+ path2.dirname(fileURLToPath(import.meta.url)),
604
556
  "..",
605
557
  "src",
606
558
  "system",
607
559
  "components"
608
560
  );
609
561
  const COMPONENTS_SCAN_DIRS = [...consumerComponentDirs];
610
- if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && fs3.existsSync(packageComponentsDir)) {
562
+ if (!COMPONENTS_SCAN_DIRS.includes(packageComponentsDir) && fs2.existsSync(packageComponentsDir)) {
611
563
  COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
612
564
  }
613
- const LEGACY_PRESETS_DIR = path3.resolve("presets");
565
+ const LEGACY_PRESETS_DIR = path2.resolve("presets");
614
566
  const themesResource = versionedFileResourceServer({
615
567
  dir: THEMES_DIR
616
568
  });
@@ -618,7 +570,7 @@ function themeFileApi(opts) {
618
570
  function componentResource(comp) {
619
571
  let r = componentResourceCache.get(comp);
620
572
  if (!r) {
621
- r = versionedFileResourceServer({ dir: path3.join(COMPONENT_CONFIGS_DIR, comp) });
573
+ r = versionedFileResourceServer({ dir: path2.join(COMPONENT_CONFIGS_DIR, comp) });
622
574
  componentResourceCache.set(comp, r);
623
575
  }
624
576
  return r;
@@ -626,7 +578,7 @@ function themeFileApi(opts) {
626
578
  const manifestsResource = versionedFileResourceServer({ dir: MANIFESTS_DIR });
627
579
  function ensureThemesDir() {
628
580
  themesResource.ensureDir();
629
- if (!fs3.existsSync(path3.join(THEMES_DIR, "default.json"))) {
581
+ if (!fs2.existsSync(path2.join(THEMES_DIR, "default.json"))) {
630
582
  const defaultTheme = {
631
583
  name: "Default Theme",
632
584
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -634,7 +586,7 @@ function themeFileApi(opts) {
634
586
  editorConfigs: {},
635
587
  cssVariables: {}
636
588
  };
637
- fs3.writeFileSync(path3.join(THEMES_DIR, "default.json"), JSON.stringify(defaultTheme, null, 2));
589
+ fs2.writeFileSync(path2.join(THEMES_DIR, "default.json"), JSON.stringify(defaultTheme, null, 2));
638
590
  }
639
591
  themesResource.ensureMeta();
640
592
  }
@@ -699,10 +651,10 @@ function themeFileApi(opts) {
699
651
  lines.push("/* tokens.css holds developer-authored defaults; this file holds editor overrides. */");
700
652
  lines.push("");
701
653
  const productionThemeName = themesResource.getProductionName();
702
- const themePath = path3.join(THEMES_DIR, `${productionThemeName}.json`);
654
+ const themePath = path2.join(THEMES_DIR, `${productionThemeName}.json`);
703
655
  let themeVarCount = 0;
704
- if (fs3.existsSync(themePath)) {
705
- const themeData = JSON.parse(fs3.readFileSync(themePath, "utf-8"));
656
+ if (fs2.existsSync(themePath)) {
657
+ const themeData = JSON.parse(fs2.readFileSync(themePath, "utf-8"));
706
658
  const cssVars = { ...themeData.cssVariables || {} };
707
659
  Object.assign(cssVars, palettesToVars(themeData.editorConfigs ?? {}));
708
660
  const resolvedFontVars = resolveFontStacks(themeData);
@@ -721,7 +673,7 @@ function themeFileApi(opts) {
721
673
  }
722
674
  }
723
675
  let componentOverrideCount = 0;
724
- if (fs3.existsSync(COMPONENT_CONFIGS_DIR)) {
676
+ if (fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
725
677
  const blocks = [];
726
678
  for (const comp of listComponentNames()) {
727
679
  const prod = componentResource(comp).getProductionName();
@@ -755,21 +707,21 @@ function themeFileApi(opts) {
755
707
  lines.push("");
756
708
  }
757
709
  }
758
- if (!fs3.existsSync(path3.dirname(GENERATED_CSS_PATH))) {
759
- fs3.mkdirSync(path3.dirname(GENERATED_CSS_PATH), { recursive: true });
710
+ if (!fs2.existsSync(path2.dirname(GENERATED_CSS_PATH))) {
711
+ fs2.mkdirSync(path2.dirname(GENERATED_CSS_PATH), { recursive: true });
760
712
  }
761
- fs3.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
713
+ fs2.writeFileSync(GENERATED_CSS_PATH, lines.join("\n"));
762
714
  console.log(
763
- `[regenerateTokensCss] Wrote ${path3.basename(GENERATED_CSS_PATH)} (${themeVarCount} theme vars, ${componentOverrideCount} component overrides)`
715
+ `[regenerateTokensCss] Wrote ${path2.basename(GENERATED_CSS_PATH)} (${themeVarCount} theme vars, ${componentOverrideCount} component overrides)`
764
716
  );
765
717
  }
766
718
  function syncTokensToCss(_fileName) {
767
719
  regenerateTokensCss();
768
720
  }
769
721
  function syncFontsToCss(fileName) {
770
- const themePath = path3.join(THEMES_DIR, `${fileName}.json`);
771
- if (!fs3.existsSync(themePath)) return;
772
- const themeData = JSON.parse(fs3.readFileSync(themePath, "utf-8"));
722
+ const themePath = path2.join(THEMES_DIR, `${fileName}.json`);
723
+ if (!fs2.existsSync(themePath)) return;
724
+ const themeData = JSON.parse(fs2.readFileSync(themePath, "utf-8"));
773
725
  const sources = themeData.fontSources;
774
726
  if (!sources) return;
775
727
  const lines = [];
@@ -793,11 +745,11 @@ function themeFileApi(opts) {
793
745
  lines.push("");
794
746
  }
795
747
  const content = lines.join("\n");
796
- if (!fs3.existsSync(path3.dirname(FONTS_CSS_PATH))) {
797
- fs3.mkdirSync(path3.dirname(FONTS_CSS_PATH), { recursive: true });
748
+ if (!fs2.existsSync(path2.dirname(FONTS_CSS_PATH))) {
749
+ fs2.mkdirSync(path2.dirname(FONTS_CSS_PATH), { recursive: true });
798
750
  }
799
- fs3.writeFileSync(FONTS_CSS_PATH, content);
800
- console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${path3.basename(FONTS_CSS_PATH)}`);
751
+ fs2.writeFileSync(FONTS_CSS_PATH, content);
752
+ console.log(`[syncFontsToCss] Wrote ${sources.length} source(s) into ${path2.basename(FONTS_CSS_PATH)}`);
801
753
  }
802
754
  function extractAliasDeclarations(body) {
803
755
  const aliases = {};
@@ -807,11 +759,11 @@ function themeFileApi(opts) {
807
759
  return aliases;
808
760
  }
809
761
  function componentNameFromFile(filePath) {
810
- return path3.basename(filePath, ".svelte").toLowerCase();
762
+ return path2.basename(filePath, ".svelte").toLowerCase();
811
763
  }
812
764
  function isThemeAwareComponent(filePath) {
813
765
  try {
814
- const source = fs3.readFileSync(filePath, "utf-8");
766
+ const source = fs2.readFileSync(filePath, "utf-8");
815
767
  return /:global\(:root\)\s*\{/.test(source);
816
768
  } catch {
817
769
  return false;
@@ -820,10 +772,10 @@ function themeFileApi(opts) {
820
772
  function listComponentSourcePaths() {
821
773
  const byName = /* @__PURE__ */ new Map();
822
774
  for (const dir of COMPONENTS_SCAN_DIRS) {
823
- if (!fs3.existsSync(dir)) continue;
824
- for (const f of fs3.readdirSync(dir)) {
775
+ if (!fs2.existsSync(dir)) continue;
776
+ for (const f of fs2.readdirSync(dir)) {
825
777
  if (!f.endsWith(".svelte")) continue;
826
- const full = path3.join(dir, f);
778
+ const full = path2.join(dir, f);
827
779
  if (!isThemeAwareComponent(full)) continue;
828
780
  const name = componentNameFromFile(f);
829
781
  if (!byName.has(name)) byName.set(name, full);
@@ -834,26 +786,53 @@ function themeFileApi(opts) {
834
786
  function listComponentNames() {
835
787
  return listComponentSourcePaths().map(componentNameFromFile);
836
788
  }
789
+ function warnOnTokenDrift(log) {
790
+ let tokensCss = "";
791
+ try {
792
+ tokensCss = fs2.readFileSync(CSS_PATH, "utf-8");
793
+ } catch {
794
+ return;
795
+ }
796
+ let generatedCss = "";
797
+ try {
798
+ generatedCss = fs2.readFileSync(GENERATED_CSS_PATH, "utf-8");
799
+ } catch {
800
+ }
801
+ const componentSources = listComponentSourcePaths().map((p) => ({
802
+ name: componentNameFromFile(p),
803
+ source: fs2.readFileSync(p, "utf-8")
804
+ }));
805
+ const missing = validateTokensCss({ tokensCss, generatedCss, componentSources });
806
+ if (missing.length === 0) return;
807
+ const lines = missing.map(
808
+ (m) => ` ${m.token} (referenced by ${m.referencedBy.join(", ")})`
809
+ );
810
+ log(
811
+ `[live-tokens] ${missing.length} token(s) referenced by components are not defined in ${path2.relative(process.cwd(), CSS_PATH)}:
812
+ ${lines.join("\n")}
813
+ These render as blank/empty editor slots. Run \`npx live-tokens migrate\` to reconcile.`
814
+ );
815
+ }
837
816
  function generateDefaultConfig(comp, sourcePath) {
838
- if (!fs3.existsSync(sourcePath)) return;
817
+ if (!fs2.existsSync(sourcePath)) return;
839
818
  const r = componentResource(comp);
840
819
  r.ensureDir();
841
820
  const defaultPath = r.filePath("default");
842
- const sourceStat = fs3.statSync(sourcePath);
843
- if (fs3.existsSync(defaultPath)) {
844
- const defaultStat = fs3.statSync(defaultPath);
821
+ const sourceStat = fs2.statSync(sourcePath);
822
+ if (fs2.existsSync(defaultPath)) {
823
+ const defaultStat = fs2.statSync(defaultPath);
845
824
  if (defaultStat.mtimeMs >= sourceStat.mtimeMs) return;
846
825
  }
847
- const source = fs3.readFileSync(sourcePath, "utf-8");
826
+ const source = fs2.readFileSync(sourcePath, "utf-8");
848
827
  const body = extractGlobalRootBody(source);
849
828
  const aliases = extractAliasDeclarations(body);
850
829
  const now = (/* @__PURE__ */ new Date()).toISOString();
851
830
  let createdAt = now;
852
831
  let existingUpdatedAt;
853
832
  let existingAliases;
854
- if (fs3.existsSync(defaultPath)) {
833
+ if (fs2.existsSync(defaultPath)) {
855
834
  try {
856
- const existing = JSON.parse(fs3.readFileSync(defaultPath, "utf-8"));
835
+ const existing = JSON.parse(fs2.readFileSync(defaultPath, "utf-8"));
857
836
  if (existing.createdAt) createdAt = existing.createdAt;
858
837
  if (typeof existing.updatedAt === "string") existingUpdatedAt = existing.updatedAt;
859
838
  if (existing.aliases && typeof existing.aliases === "object") {
@@ -872,14 +851,14 @@ function themeFileApi(opts) {
872
851
  };
873
852
  if (aliasesUnchanged && existingUpdatedAt) {
874
853
  const t = /* @__PURE__ */ new Date();
875
- fs3.utimesSync(defaultPath, t, t);
854
+ fs2.utimesSync(defaultPath, t, t);
876
855
  return;
877
856
  }
878
- fs3.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
857
+ fs2.writeFileSync(defaultPath, JSON.stringify(defaultConfig, null, 2));
879
858
  }
880
859
  function ensureComponentConfigsDir() {
881
- if (!fs3.existsSync(COMPONENT_CONFIGS_DIR)) {
882
- fs3.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
860
+ if (!fs2.existsSync(COMPONENT_CONFIGS_DIR)) {
861
+ fs2.mkdirSync(COMPONENT_CONFIGS_DIR, { recursive: true });
883
862
  }
884
863
  for (const sourcePath of listComponentSourcePaths()) {
885
864
  const comp = componentNameFromFile(sourcePath);
@@ -890,14 +869,14 @@ function themeFileApi(opts) {
890
869
  }
891
870
  }
892
871
  function ensureManifestsDir() {
893
- if (!fs3.existsSync(MANIFESTS_DIR) && fs3.existsSync(LEGACY_PRESETS_DIR)) {
894
- fs3.renameSync(LEGACY_PRESETS_DIR, MANIFESTS_DIR);
895
- const legacyProd = path3.join(MANIFESTS_DIR, "_production.json");
896
- if (fs3.existsSync(legacyProd)) fs3.unlinkSync(legacyProd);
872
+ if (!fs2.existsSync(MANIFESTS_DIR) && fs2.existsSync(LEGACY_PRESETS_DIR)) {
873
+ fs2.renameSync(LEGACY_PRESETS_DIR, MANIFESTS_DIR);
874
+ const legacyProd = path2.join(MANIFESTS_DIR, "_production.json");
875
+ if (fs2.existsSync(legacyProd)) fs2.unlinkSync(legacyProd);
897
876
  }
898
877
  manifestsResource.ensureDir();
899
- const defaultPath = path3.join(MANIFESTS_DIR, "default.json");
900
- if (!fs3.existsSync(defaultPath)) {
878
+ const defaultPath = path2.join(MANIFESTS_DIR, "default.json");
879
+ if (!fs2.existsSync(defaultPath)) {
901
880
  const componentConfigs = {};
902
881
  for (const comp of listComponentNames()) {
903
882
  componentConfigs[comp] = componentResource(comp).getActiveName();
@@ -910,30 +889,30 @@ function themeFileApi(opts) {
910
889
  theme: themesResource.getActiveName(),
911
890
  componentConfigs
912
891
  };
913
- fs3.writeFileSync(defaultPath, JSON.stringify(defaultManifest, null, 2));
892
+ fs2.writeFileSync(defaultPath, JSON.stringify(defaultManifest, null, 2));
914
893
  }
915
- if (!fs3.existsSync(manifestsResource.activePath)) {
916
- fs3.writeFileSync(
894
+ if (!fs2.existsSync(manifestsResource.activePath)) {
895
+ fs2.writeFileSync(
917
896
  manifestsResource.activePath,
918
897
  JSON.stringify({ activeFile: "default" })
919
898
  );
920
899
  } else {
921
900
  const activeName = manifestsResource.getActiveName();
922
- if (!fs3.existsSync(manifestsResource.filePath(activeName))) {
901
+ if (!fs2.existsSync(manifestsResource.filePath(activeName))) {
923
902
  manifestsResource.setActiveName("default");
924
903
  }
925
904
  }
926
- const stragglerProd = path3.join(MANIFESTS_DIR, "_production.json");
927
- if (fs3.existsSync(stragglerProd)) fs3.unlinkSync(stragglerProd);
905
+ const stragglerProd = path2.join(MANIFESTS_DIR, "_production.json");
906
+ if (fs2.existsSync(stragglerProd)) fs2.unlinkSync(stragglerProd);
928
907
  }
929
908
  function patchActiveManifest(field, comp, fileName) {
930
909
  const activeFile = manifestsResource.getActiveName();
931
910
  if (activeFile === "default") return false;
932
911
  const manifestPath = manifestsResource.filePath(activeFile);
933
- if (!fs3.existsSync(manifestPath)) return false;
912
+ if (!fs2.existsSync(manifestPath)) return false;
934
913
  let manifest;
935
914
  try {
936
- manifest = JSON.parse(fs3.readFileSync(manifestPath, "utf-8"));
915
+ manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
937
916
  } catch {
938
917
  return false;
939
918
  }
@@ -944,7 +923,7 @@ function themeFileApi(opts) {
944
923
  manifest.componentConfigs[comp] = fileName;
945
924
  }
946
925
  manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
947
- fs3.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
926
+ fs2.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
948
927
  return true;
949
928
  }
950
929
  function formatAliasGradient(v) {
@@ -976,9 +955,9 @@ function themeFileApi(opts) {
976
955
  }
977
956
  function readComponentConfig(comp, name) {
978
957
  const filePath = componentResource(comp).filePath(name);
979
- if (!fs3.existsSync(filePath)) return null;
958
+ if (!fs2.existsSync(filePath)) return null;
980
959
  try {
981
- return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
960
+ return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
982
961
  } catch {
983
962
  return null;
984
963
  }
@@ -1004,9 +983,9 @@ function themeFileApi(opts) {
1004
983
  const MANIFEST_BY_NAME_REGEX = new RegExp(`^${escapedBase}/manifests/([a-z0-9\\-_]+)$`);
1005
984
  async function handleListThemes(_ctx) {
1006
985
  const activeFile = themesResource.getActiveName();
1007
- const files = fs3.readdirSync(THEMES_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
1008
- const filePath = path3.join(THEMES_DIR, f);
1009
- const data = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
986
+ const files = fs2.readdirSync(THEMES_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
987
+ const filePath = path2.join(THEMES_DIR, f);
988
+ const data = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1010
989
  const fileName = f.replace(".json", "");
1011
990
  return {
1012
991
  name: data.name || fileName,
@@ -1020,18 +999,18 @@ function themeFileApi(opts) {
1020
999
  async function handleGetActiveTheme({ res }) {
1021
1000
  const activeFile = themesResource.getActiveName();
1022
1001
  const filePath = themesResource.filePath(activeFile);
1023
- if (!fs3.existsSync(filePath)) {
1002
+ if (!fs2.existsSync(filePath)) {
1024
1003
  jsonResponse(res, 404, { error: "Active theme not found" });
1025
1004
  return;
1026
1005
  }
1027
- const data = normalizeTheme(JSON.parse(fs3.readFileSync(filePath, "utf-8")));
1006
+ const data = normalizeTheme(JSON.parse(fs2.readFileSync(filePath, "utf-8")));
1028
1007
  data._fileName = activeFile;
1029
1008
  jsonResponse(res, 200, data);
1030
1009
  }
1031
1010
  async function handleSetActiveTheme({ req, res }) {
1032
1011
  const body = JSON.parse(await readBody(req));
1033
1012
  const fileName = sanitizeFileName(body.name || "default");
1034
- if (!fs3.existsSync(themesResource.filePath(fileName))) {
1013
+ if (!fs2.existsSync(themesResource.filePath(fileName))) {
1035
1014
  jsonResponse(res, 404, { error: "Theme not found" });
1036
1015
  return;
1037
1016
  }
@@ -1041,11 +1020,11 @@ function themeFileApi(opts) {
1041
1020
  async function handleGetProductionTheme({ res }) {
1042
1021
  const prodFile = themesResource.getProductionName();
1043
1022
  const filePath = themesResource.filePath(prodFile);
1044
- if (!fs3.existsSync(filePath)) {
1023
+ if (!fs2.existsSync(filePath)) {
1045
1024
  jsonResponse(res, 200, { fileName: prodFile, name: prodFile, cssVariables: {} });
1046
1025
  return;
1047
1026
  }
1048
- const data = normalizeTheme(JSON.parse(fs3.readFileSync(filePath, "utf-8")));
1027
+ const data = normalizeTheme(JSON.parse(fs2.readFileSync(filePath, "utf-8")));
1049
1028
  jsonResponse(res, 200, {
1050
1029
  fileName: prodFile,
1051
1030
  name: data.name || prodFile,
@@ -1056,7 +1035,7 @@ function themeFileApi(opts) {
1056
1035
  async function handleSetProductionTheme({ req, res }) {
1057
1036
  const body = JSON.parse(await readBody(req));
1058
1037
  const fileName = sanitizeFileName(body.name || "default");
1059
- if (!fs3.existsSync(themesResource.filePath(fileName))) {
1038
+ if (!fs2.existsSync(themesResource.filePath(fileName))) {
1060
1039
  jsonResponse(res, 404, { error: "Theme not found" });
1061
1040
  return;
1062
1041
  }
@@ -1072,7 +1051,7 @@ function themeFileApi(opts) {
1072
1051
  syncFontsToCss(fileName);
1073
1052
  syncComponentsToCss();
1074
1053
  patchActiveManifest("theme", null, fileName);
1075
- const data = JSON.parse(fs3.readFileSync(themesResource.filePath(fileName), "utf-8"));
1054
+ const data = JSON.parse(fs2.readFileSync(themesResource.filePath(fileName), "utf-8"));
1076
1055
  jsonResponse(res, 200, {
1077
1056
  ok: true,
1078
1057
  fileName,
@@ -1084,11 +1063,11 @@ function themeFileApi(opts) {
1084
1063
  const [fileName] = params;
1085
1064
  const filePath = themesResource.filePath(fileName);
1086
1065
  if (req.method === "GET") {
1087
- if (!fs3.existsSync(filePath)) {
1066
+ if (!fs2.existsSync(filePath)) {
1088
1067
  jsonResponse(res, 404, { error: "Not found" });
1089
1068
  return;
1090
1069
  }
1091
- const data = normalizeTheme(JSON.parse(fs3.readFileSync(filePath, "utf-8")));
1070
+ const data = normalizeTheme(JSON.parse(fs2.readFileSync(filePath, "utf-8")));
1092
1071
  data._fileName = fileName;
1093
1072
  jsonResponse(res, 200, data);
1094
1073
  return;
@@ -1096,15 +1075,15 @@ function themeFileApi(opts) {
1096
1075
  if (req.method === "PUT") {
1097
1076
  const body = JSON.parse(await readBody(req));
1098
1077
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1099
- if (fs3.existsSync(filePath)) {
1078
+ if (fs2.existsSync(filePath)) {
1100
1079
  try {
1101
- const existing = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1080
+ const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1102
1081
  if (existing.createdAt) body.createdAt = existing.createdAt;
1103
1082
  } catch {
1104
1083
  }
1105
1084
  }
1106
1085
  if (!body.createdAt) body.createdAt = body.updatedAt;
1107
- fs3.writeFileSync(filePath, JSON.stringify(body, null, 2));
1086
+ fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
1108
1087
  if (fileName === themesResource.getProductionName()) {
1109
1088
  syncTokensToCss(fileName);
1110
1089
  syncFontsToCss(fileName);
@@ -1125,8 +1104,8 @@ function themeFileApi(opts) {
1125
1104
  });
1126
1105
  return;
1127
1106
  }
1128
- if (fs3.existsSync(filePath)) {
1129
- fs3.unlinkSync(filePath);
1107
+ if (fs2.existsSync(filePath)) {
1108
+ fs2.unlinkSync(filePath);
1130
1109
  if (themesResource.getActiveName() === fileName) {
1131
1110
  themesResource.setActiveName("default");
1132
1111
  }
@@ -1163,7 +1142,7 @@ function themeFileApi(opts) {
1163
1142
  const fileName = sanitizeFileName(body.name || "default");
1164
1143
  const r = componentResource(comp);
1165
1144
  const configPath = r.filePath(fileName);
1166
- if (!fs3.existsSync(configPath)) {
1145
+ if (!fs2.existsSync(configPath)) {
1167
1146
  jsonResponse(res, 404, { error: "Config not found" });
1168
1147
  return;
1169
1148
  }
@@ -1188,7 +1167,7 @@ function themeFileApi(opts) {
1188
1167
  const fileName = sanitizeFileName(body.name || "default");
1189
1168
  const r = componentResource(comp);
1190
1169
  const configPath = r.filePath(fileName);
1191
- if (!fs3.existsSync(configPath)) {
1170
+ if (!fs2.existsSync(configPath)) {
1192
1171
  jsonResponse(res, 404, { error: "Config not found" });
1193
1172
  return;
1194
1173
  }
@@ -1216,11 +1195,11 @@ function themeFileApi(opts) {
1216
1195
  const r = componentResource(comp);
1217
1196
  const configPath = r.filePath(name);
1218
1197
  if (req.method === "GET") {
1219
- if (!fs3.existsSync(configPath)) {
1198
+ if (!fs2.existsSync(configPath)) {
1220
1199
  jsonResponse(res, 404, { error: "Not found" });
1221
1200
  return;
1222
1201
  }
1223
- const data = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
1202
+ const data = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
1224
1203
  data._fileName = name;
1225
1204
  jsonResponse(res, 200, data);
1226
1205
  return;
@@ -1234,16 +1213,16 @@ function themeFileApi(opts) {
1234
1213
  body.component = comp;
1235
1214
  body.name = body.name || name;
1236
1215
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1237
- if (fs3.existsSync(configPath)) {
1216
+ if (fs2.existsSync(configPath)) {
1238
1217
  try {
1239
- const existing = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
1218
+ const existing = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
1240
1219
  if (existing.createdAt) body.createdAt = existing.createdAt;
1241
1220
  } catch {
1242
1221
  }
1243
1222
  }
1244
1223
  if (!body.createdAt) body.createdAt = body.updatedAt;
1245
1224
  r.ensureDir();
1246
- fs3.writeFileSync(configPath, JSON.stringify(body, null, 2));
1225
+ fs2.writeFileSync(configPath, JSON.stringify(body, null, 2));
1247
1226
  if (r.getProductionName() === name) {
1248
1227
  syncComponentsToCss();
1249
1228
  }
@@ -1255,8 +1234,8 @@ function themeFileApi(opts) {
1255
1234
  jsonResponse(res, 403, { error: "Cannot delete default config" });
1256
1235
  return;
1257
1236
  }
1258
- if (fs3.existsSync(configPath)) {
1259
- fs3.unlinkSync(configPath);
1237
+ if (fs2.existsSync(configPath)) {
1238
+ fs2.unlinkSync(configPath);
1260
1239
  if (r.getActiveName() === name) {
1261
1240
  r.setActiveName("default");
1262
1241
  }
@@ -1272,15 +1251,15 @@ function themeFileApi(opts) {
1272
1251
  async function handleListComponentConfigs({ params, res }) {
1273
1252
  const [comp] = params;
1274
1253
  const r = componentResource(comp);
1275
- if (!fs3.existsSync(r.dir)) {
1254
+ if (!fs2.existsSync(r.dir)) {
1276
1255
  jsonResponse(res, 404, { error: "Component not found" });
1277
1256
  return;
1278
1257
  }
1279
1258
  const activeFile = r.getActiveName();
1280
1259
  const productionFile = r.getProductionName();
1281
- const files = fs3.readdirSync(r.dir).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
1282
- const filePath = path3.join(r.dir, f);
1283
- const data = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1260
+ const files = fs2.readdirSync(r.dir).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
1261
+ const filePath = path2.join(r.dir, f);
1262
+ const data = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1284
1263
  const fileName = f.replace(".json", "");
1285
1264
  return {
1286
1265
  name: data.name || fileName,
@@ -1294,9 +1273,9 @@ function themeFileApi(opts) {
1294
1273
  }
1295
1274
  async function handleListManifests({ res }) {
1296
1275
  const activeFile = manifestsResource.getActiveName();
1297
- const files = fs3.readdirSync(MANIFESTS_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
1298
- const filePath = path3.join(MANIFESTS_DIR, f);
1299
- const data = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1276
+ const files = fs2.readdirSync(MANIFESTS_DIR).filter((f) => f.endsWith(".json") && !f.startsWith("_")).map((f) => {
1277
+ const filePath = path2.join(MANIFESTS_DIR, f);
1278
+ const data = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1300
1279
  const fileName = f.replace(".json", "");
1301
1280
  return {
1302
1281
  name: data.name || fileName,
@@ -1311,18 +1290,18 @@ function themeFileApi(opts) {
1311
1290
  async function handleGetActiveManifest({ res }) {
1312
1291
  const activeFile = manifestsResource.getActiveName();
1313
1292
  const filePath = manifestsResource.filePath(activeFile);
1314
- if (!fs3.existsSync(filePath)) {
1293
+ if (!fs2.existsSync(filePath)) {
1315
1294
  jsonResponse(res, 404, { error: "Active manifest not found" });
1316
1295
  return;
1317
1296
  }
1318
- const data = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1297
+ const data = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1319
1298
  data._fileName = activeFile;
1320
1299
  jsonResponse(res, 200, data);
1321
1300
  }
1322
1301
  async function handleSetActiveManifest({ req, res }) {
1323
1302
  const body = JSON.parse(await readBody(req));
1324
1303
  const fileName = sanitizeFileName(body.name || "default");
1325
- if (!fs3.existsSync(manifestsResource.filePath(fileName))) {
1304
+ if (!fs2.existsSync(manifestsResource.filePath(fileName))) {
1326
1305
  jsonResponse(res, 404, { error: "Manifest not found" });
1327
1306
  return;
1328
1307
  }
@@ -1333,11 +1312,11 @@ function themeFileApi(opts) {
1333
1312
  const [fileName] = params;
1334
1313
  const filePath = manifestsResource.filePath(fileName);
1335
1314
  if (req.method === "GET") {
1336
- if (!fs3.existsSync(filePath)) {
1315
+ if (!fs2.existsSync(filePath)) {
1337
1316
  jsonResponse(res, 404, { error: "Not found" });
1338
1317
  return;
1339
1318
  }
1340
- const data = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1319
+ const data = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1341
1320
  data._fileName = fileName;
1342
1321
  jsonResponse(res, 200, data);
1343
1322
  return;
@@ -1349,15 +1328,15 @@ function themeFileApi(opts) {
1349
1328
  }
1350
1329
  const body = JSON.parse(await readBody(req));
1351
1330
  body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1352
- if (fs3.existsSync(filePath)) {
1331
+ if (fs2.existsSync(filePath)) {
1353
1332
  try {
1354
- const existing = JSON.parse(fs3.readFileSync(filePath, "utf-8"));
1333
+ const existing = JSON.parse(fs2.readFileSync(filePath, "utf-8"));
1355
1334
  if (existing.createdAt) body.createdAt = existing.createdAt;
1356
1335
  } catch {
1357
1336
  }
1358
1337
  }
1359
1338
  if (!body.createdAt) body.createdAt = body.updatedAt;
1360
- fs3.writeFileSync(filePath, JSON.stringify(body, null, 2));
1339
+ fs2.writeFileSync(filePath, JSON.stringify(body, null, 2));
1361
1340
  jsonResponse(res, 200, { ok: true, fileName });
1362
1341
  return;
1363
1342
  }
@@ -1366,8 +1345,8 @@ function themeFileApi(opts) {
1366
1345
  jsonResponse(res, 403, { error: "Cannot delete the default manifest" });
1367
1346
  return;
1368
1347
  }
1369
- if (fs3.existsSync(filePath)) {
1370
- fs3.unlinkSync(filePath);
1348
+ if (fs2.existsSync(filePath)) {
1349
+ fs2.unlinkSync(filePath);
1371
1350
  if (manifestsResource.getActiveName() === fileName) {
1372
1351
  manifestsResource.setActiveName("default");
1373
1352
  }
@@ -1379,14 +1358,14 @@ function themeFileApi(opts) {
1379
1358
  async function handleApplyManifest({ params, res }) {
1380
1359
  const [fileName] = params;
1381
1360
  const manifestPath = manifestsResource.filePath(fileName);
1382
- if (!fs3.existsSync(manifestPath)) {
1361
+ if (!fs2.existsSync(manifestPath)) {
1383
1362
  jsonResponse(res, 404, { error: "Manifest not found" });
1384
1363
  return;
1385
1364
  }
1386
- const manifest = JSON.parse(fs3.readFileSync(manifestPath, "utf-8"));
1365
+ const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
1387
1366
  const themeName = sanitizeFileName(manifest.theme || "default");
1388
1367
  const themePath = themesResource.filePath(themeName);
1389
- if (!fs3.existsSync(themePath)) {
1368
+ if (!fs2.existsSync(themePath)) {
1390
1369
  jsonResponse(res, 422, { error: `Manifest references missing theme: ${themeName}` });
1391
1370
  return;
1392
1371
  }
@@ -1399,7 +1378,7 @@ function themeFileApi(opts) {
1399
1378
  const sanitized = sanitizeFileName(String(configFile) || "default");
1400
1379
  const r = componentResource(comp);
1401
1380
  const cfgPath = r.filePath(sanitized);
1402
- if (!fs3.existsSync(cfgPath)) {
1381
+ if (!fs2.existsSync(cfgPath)) {
1403
1382
  jsonResponse(res, 422, {
1404
1383
  error: `Manifest references missing config: ${comp}/${sanitized}`
1405
1384
  });
@@ -1411,7 +1390,7 @@ function themeFileApi(opts) {
1411
1390
  themesResource.setProductionName(themeName);
1412
1391
  syncTokensToCss(themeName);
1413
1392
  syncFontsToCss(themeName);
1414
- const themeData = normalizeTheme(JSON.parse(fs3.readFileSync(themePath, "utf-8")));
1393
+ const themeData = normalizeTheme(JSON.parse(fs2.readFileSync(themePath, "utf-8")));
1415
1394
  themeData._fileName = themeName;
1416
1395
  for (const [comp, configFile] of apply) {
1417
1396
  const r = componentResource(comp);
@@ -1438,18 +1417,18 @@ function themeFileApi(opts) {
1438
1417
  async function handleExportManifest({ params, res }) {
1439
1418
  const [fileName] = params;
1440
1419
  const manifestPath = manifestsResource.filePath(fileName);
1441
- if (!fs3.existsSync(manifestPath)) {
1420
+ if (!fs2.existsSync(manifestPath)) {
1442
1421
  jsonResponse(res, 404, { error: "Manifest not found" });
1443
1422
  return;
1444
1423
  }
1445
- const manifest = JSON.parse(fs3.readFileSync(manifestPath, "utf-8"));
1424
+ const manifest = JSON.parse(fs2.readFileSync(manifestPath, "utf-8"));
1446
1425
  const themeName = sanitizeFileName(manifest.theme || "default");
1447
1426
  const themePath = themesResource.filePath(themeName);
1448
- if (!fs3.existsSync(themePath)) {
1427
+ if (!fs2.existsSync(themePath)) {
1449
1428
  jsonResponse(res, 422, { error: `Manifest references missing theme: ${themeName}` });
1450
1429
  return;
1451
1430
  }
1452
- const theme = JSON.parse(fs3.readFileSync(themePath, "utf-8"));
1431
+ const theme = JSON.parse(fs2.readFileSync(themePath, "utf-8"));
1453
1432
  const knownComponents = new Set(listComponentNames());
1454
1433
  const componentConfigs = {};
1455
1434
  for (const [comp, configFile] of Object.entries(manifest.componentConfigs ?? {})) {
@@ -1457,13 +1436,13 @@ function themeFileApi(opts) {
1457
1436
  const sanitized = sanitizeFileName(String(configFile) || "default");
1458
1437
  if (sanitized === "default") continue;
1459
1438
  const cfgPath = componentResource(comp).filePath(sanitized);
1460
- if (!fs3.existsSync(cfgPath)) {
1439
+ if (!fs2.existsSync(cfgPath)) {
1461
1440
  jsonResponse(res, 422, {
1462
1441
  error: `Manifest references missing config: ${comp}/${sanitized}`
1463
1442
  });
1464
1443
  return;
1465
1444
  }
1466
- const cfg = JSON.parse(fs3.readFileSync(cfgPath, "utf-8"));
1445
+ const cfg = JSON.parse(fs2.readFileSync(cfgPath, "utf-8"));
1467
1446
  componentConfigs[`${comp}/${sanitized}`] = cfg;
1468
1447
  }
1469
1448
  const bundle = {
@@ -1485,7 +1464,7 @@ function themeFileApi(opts) {
1485
1464
  }
1486
1465
  function nextAvailableName2(resourceFilePath, baseName) {
1487
1466
  return nextAvailableName(
1488
- (n) => fs3.existsSync(resourceFilePath(n)),
1467
+ (n) => fs2.existsSync(resourceFilePath(n)),
1489
1468
  sanitizeFileName(baseName)
1490
1469
  );
1491
1470
  }
@@ -1527,7 +1506,7 @@ function themeFileApi(opts) {
1527
1506
  themeBody.updatedAt = now;
1528
1507
  if (!themeBody.createdAt) themeBody.createdAt = now;
1529
1508
  themesResource.ensureDir();
1530
- fs3.writeFileSync(themesResource.filePath(finalThemeName), JSON.stringify(themeBody, null, 2));
1509
+ fs2.writeFileSync(themesResource.filePath(finalThemeName), JSON.stringify(themeBody, null, 2));
1531
1510
  const knownComponents = new Set(listComponentNames());
1532
1511
  const componentRenames = {};
1533
1512
  for (const [key, cfgValue] of Object.entries(bundle.componentConfigs)) {
@@ -1549,7 +1528,7 @@ function themeFileApi(opts) {
1549
1528
  cfgBody.updatedAt = now;
1550
1529
  if (!cfgBody.createdAt) cfgBody.createdAt = now;
1551
1530
  r.ensureDir();
1552
- fs3.writeFileSync(r.filePath(finalName), JSON.stringify(cfgBody, null, 2));
1531
+ fs2.writeFileSync(r.filePath(finalName), JSON.stringify(cfgBody, null, 2));
1553
1532
  }
1554
1533
  const rewrittenManifest = {
1555
1534
  ...bundle.manifest,
@@ -1576,7 +1555,7 @@ function themeFileApi(opts) {
1576
1555
  renames[`manifest:${originalManifestName}`] = finalManifestName;
1577
1556
  }
1578
1557
  manifestsResource.ensureDir();
1579
- fs3.writeFileSync(
1558
+ fs2.writeFileSync(
1580
1559
  manifestsResource.filePath(finalManifestName),
1581
1560
  JSON.stringify(rewrittenManifest, null, 2)
1582
1561
  );
@@ -1659,13 +1638,14 @@ function themeFileApi(opts) {
1659
1638
  ensureComponentConfigsDir();
1660
1639
  ensureManifestsDir();
1661
1640
  regenerateTokensCss();
1641
+ warnOnTokenDrift((msg) => server.config.logger.warn(msg));
1662
1642
  server.middlewares.use(async (req, res, next) => {
1663
1643
  const handled = await dispatch(req, res, routes);
1664
1644
  if (!handled) next();
1665
1645
  });
1666
1646
  },
1667
1647
  handleHotUpdate(ctx) {
1668
- const normalized = path3.resolve(ctx.file);
1648
+ const normalized = path2.resolve(ctx.file);
1669
1649
  if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
1670
1650
  if (!normalized.endsWith(".svelte")) return;
1671
1651
  if (!isThemeAwareComponent(normalized)) return;
@@ -1675,5 +1655,8 @@ function themeFileApi(opts) {
1675
1655
  };
1676
1656
  }
1677
1657
  export {
1678
- themeFileApi
1658
+ TOKENS_CSS_MIGRATIONS,
1659
+ runTokensCssMigrations,
1660
+ themeFileApi,
1661
+ validateTokensCss
1679
1662
  };