@getvitops/vite 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,82 @@
1
1
  # @getvitops/vite
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - Updated dependencies
9
+ - Updated dependencies [c949cae]
10
+ - Updated dependencies
11
+ - Updated dependencies
12
+ - Updated dependencies
13
+ - @getvitops/generator@0.9.0
14
+ - @getvitops/utils@0.9.0
15
+
16
+ ## 0.8.0
17
+
18
+ ### Minor Changes
19
+
20
+ - **New: `<wc-theme-editor>`, a live theme editor you can ship with your site.**
21
+
22
+ Tune the whole design system in the browser — palette, semantic roles, type roles, spacing, layout,
23
+ pattern geometry, radii, shadows — with no rebuild. Edits are layered as `:root` custom-property
24
+ overrides, persist to localStorage, and export as CSS or as a `design-system.json` patch. It follows
25
+ your site's colour scheme and drives the same `data-theme` + storage key as `<color-scheme-toggle>`,
26
+ so the two no longer fight.
27
+
28
+ It ships as a **separate, opt-in bundle** (`@getvitops/core/editor`, ~13 kB, no Lit) and is never
29
+ registered in `elements.js`: a page that doesn't ask for it pays nothing.
30
+
31
+ ```js
32
+ // astro.config.mjs
33
+ getvitops({
34
+ css: { input: 'design-system.json', format: 'css', out: 'src/styles' },
35
+ editor: true,
36
+ });
37
+ ```
38
+
39
+ ```html
40
+ <!-- anywhere in your layout -->
41
+ <wc-theme-editor></wc-theme-editor>
42
+ ```
43
+
44
+ `editor: true` copies `editor.js` into `public/vitops/`, loads it from `<Head />`, and mirrors
45
+ `design-manifest.json` to `/vitops/design-manifest.json` (override with the `manifest` attribute).
46
+ Outside Astro, load the bundle yourself and point `manifest` at the file.
47
+
48
+ **Save straight back to your config, in dev.** `@getvitops/vite` now serves a dev-only
49
+ `/__vitops/design-system` endpoint: the editor POSTs its patch, the plugin deep-merges it into your
50
+ `design-system.json`, validates the _merged_ result, writes it back preserving the file's formatting,
51
+ then regenerates and reloads. The endpoint exists only under `vite dev` — on a static deploy the
52
+ editor detects its absence and hides the button, while everything else still works.
53
+
54
+ **Added:** `colors.roleTokens` in `design-manifest.json` — the functional token set (bg / border /
55
+ solid / on-solid / text / emphasis stops) precomputed per hue, in `default` and `surface` variants for
56
+ both appearances. Re-pointing a role at another hue needs these: `solid` is chosen by scanning the hue
57
+ and `on-solid` is a computed contrast value, so neither is derivable by a browser client.
58
+
59
+ **Removed:** the dead `interaction` block from `design-manifest.json` — a hardcoded
60
+ `{duration, easing}` literal with no schema key, no reverse-index entry, and no corresponding CSS
61
+ variable. Nothing could have consumed it meaningfully. The real animation knobs are
62
+ `--animation-duration-*` / `--custom-ease-*`.
63
+
64
+ **Fixed:** a `[popover]` reset in `popover.css` was stripping the background, padding and border from
65
+ any pattern used as a popover. It is imported after `drawer.css`, so at equal specificity it beat
66
+ `.drawer` — and `dialog` (0-0-1) too — leaving a `.drawer[popover]` transparent and unpadded despite
67
+ drawer.css documenting popover as supported. The reset now sits in `:where()` at zero specificity, so
68
+ it still overrides the UA stylesheet but any pattern class takes its surface back. Open/closed
69
+ behaviour is unchanged.
70
+
71
+ **Added:** `input[type="range"]` and `input[type="color"]` now have baseline styling in `forms.css`
72
+ (accent colour from `--ui-primary-solid`; the colour swatch picks up the control border and radius).
73
+
74
+ ### Patch Changes
75
+
76
+ - Updated dependencies
77
+ - @getvitops/generator@0.8.0
78
+ - @getvitops/utils@0.8.0
79
+
3
80
  ## 0.7.0
4
81
 
5
82
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -25,6 +25,13 @@ interface VitopsPluginOptions {
25
25
  out?: string;
26
26
  /** Also generate a favicon set on build from this source image. */
27
27
  favicon?: VitopsFaviconOptions;
28
+ /**
29
+ * Directory to mirror `design-manifest.json` into as `vitops/design-manifest.json`
30
+ * — the URL `<wc-theme-editor>` fetches by default. Set by the Astro integration's
31
+ * `editor` option. Copied inside the generate pass rather than by the caller, so
32
+ * it can't race the first generation and can't go stale on regeneration.
33
+ */
34
+ editorManifestDir?: string;
28
35
  }
29
36
  declare function vitops(options?: VitopsPluginOptions): Plugin;
30
37
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;UAeiB,oBAAA;;EAEf,MAAA;EAFmC;EAInC,YAAA;EAJmC;EAMnC,GAAA;EAFA;EAIA,IAAA;EAAA;EAEA,UAAA;EAEA;EAAA,eAAA;AAAA;AAAA,UAGe,mBAAA;EAAmB;EAElC,KAAA;EAM8B;EAJ9B,MAAA,GAAS,MAAA;EAAT;EAEA,GAAA;EAAA;EAEA,OAAA,GAAU,oBAAoB;AAAA;AAAA,iBAGR,MAAA,CAAO,OAAA,GAAS,mBAAA,GAA2B,MAAM"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;UAqEiB,oBAAA;;EAEf,MAAA;EAFmC;EAInC,YAAA;EAJmC;EAMnC,GAAA;EAFA;EAIA,IAAA;EAAA;EAEA,UAAA;EAEA;EAAA,eAAA;AAAA;AAAA,UAGe,mBAAA;EAAmB;EAElC,KAAA;EAM8B;EAJ9B,MAAA,GAAS,MAAA;EAAT;EAEA,GAAA;EAAA;EAEA,OAAA,GAAU,oBAAoB;EAApB;;;AAOO;AAClB;;EADC,iBAAA;AAAA;AAAA,iBAGsB,MAAA,CAAO,OAAA,GAAS,mBAAA,GAA2B,MAAM"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { resolve } from "node:path";
2
- import { generate } from "@getvitops/generator";
1
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { generate, validate } from "@getvitops/generator";
3
4
  import { generateFavicons, writeFaviconManifest } from "@getvitops/utils";
4
5
 
5
6
  //#region src/index.ts
@@ -13,6 +14,52 @@ import { generateFavicons, writeFaviconManifest } from "@getvitops/utils";
13
14
  *
14
15
  * Thin wrapper over @getvitops/generator — the same generator the CLI uses.
15
16
  */
17
+ /** Endpoint `<wc-theme-editor>` probes for, and POSTs its patch to. */
18
+ const EDITOR_ENDPOINT = "/__vitops/design-system";
19
+ /**
20
+ * Recursively merge a patch into a config. Plain objects merge key-wise;
21
+ * everything else (scalars, and arrays — a token list is replaced, not appended)
22
+ * is overwritten by the patch.
23
+ */
24
+ function deepMerge(base, patch) {
25
+ const isPlain = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
26
+ if (!isPlain(base) || !isPlain(patch)) return patch;
27
+ const out = { ...base };
28
+ for (const [k, v] of Object.entries(patch)) out[k] = deepMerge(base[k], v);
29
+ return out;
30
+ }
31
+ /** Printed width the config is formatted to — matches the repo formatter's default. */
32
+ const PRINT_WIDTH = 100;
33
+ /**
34
+ * Serialize a config the way a formatter would: 2-space indent, but arrays of
35
+ * scalars kept on one line when they fit.
36
+ *
37
+ * `JSON.stringify(v, null, 2)` explodes every array onto its own lines, so writing
38
+ * back a two-key patch reflowed ~300 lines of `design-system.json` — a diff nobody
39
+ * can review, for a change of two values. Matching the prevailing style keeps the
40
+ * write surgical, which is the whole point of saving to source rather than copying
41
+ * a patch by hand.
42
+ */
43
+ function formatConfig(value, col = 0, indent = 0) {
44
+ const pad = " ".repeat(indent);
45
+ if (Array.isArray(value)) {
46
+ if (!value.length) return "[]";
47
+ if (value.every((v) => v === null || typeof v !== "object")) {
48
+ const inline = `[${value.map((v) => JSON.stringify(v)).join(", ")}]`;
49
+ if (col + inline.length <= PRINT_WIDTH) return inline;
50
+ }
51
+ return `[\n${value.map((v) => `${pad} ${formatConfig(v, indent + 2, indent + 2)}`).join(",\n")}\n${pad}]`;
52
+ }
53
+ if (value !== null && typeof value === "object") {
54
+ const entries = Object.entries(value);
55
+ if (!entries.length) return "{}";
56
+ return `{\n${entries.map(([k, v]) => {
57
+ const head = `${pad} ${JSON.stringify(k)}: `;
58
+ return head + formatConfig(v, head.length, indent + 2);
59
+ }).join(",\n")}\n${pad}}`;
60
+ }
61
+ return JSON.stringify(value) ?? "null";
62
+ }
16
63
  function vitops(options = {}) {
17
64
  const format = options.format ?? "tailwind";
18
65
  const outDir = options.out ?? "src/styles";
@@ -24,6 +71,14 @@ function vitops(options = {}) {
24
71
  format,
25
72
  outDir
26
73
  });
74
+ if (options.editorManifestDir) {
75
+ const src = resolve(root, outDir, "design-manifest.json");
76
+ if (existsSync(src)) {
77
+ const dest = resolve(root, options.editorManifestDir, "vitops");
78
+ mkdirSync(dest, { recursive: true });
79
+ copyFileSync(src, join(dest, "design-manifest.json"));
80
+ }
81
+ }
27
82
  if (options.favicon) {
28
83
  const faviconOut = resolve(root, options.favicon.out ?? "public");
29
84
  await generateFavicons({
@@ -58,6 +113,41 @@ function vitops(options = {}) {
58
113
  await run();
59
114
  server.ws.send({ type: "full-reload" });
60
115
  });
116
+ server.middlewares.use(EDITOR_ENDPOINT, (req, res, next) => {
117
+ const json = (status, body) => {
118
+ res.statusCode = status;
119
+ res.setHeader("content-type", "application/json");
120
+ res.end(JSON.stringify(body));
121
+ };
122
+ if (req.method === "GET") try {
123
+ return json(200, {
124
+ writable: true,
125
+ path: input,
126
+ config: JSON.parse(readFileSync(input, "utf8"))
127
+ });
128
+ } catch (err) {
129
+ return json(500, { error: err.message });
130
+ }
131
+ if (req.method !== "POST") return next();
132
+ const chunks = [];
133
+ req.on("data", (c) => chunks.push(c));
134
+ req.on("end", () => {
135
+ try {
136
+ const { patch } = JSON.parse(Buffer.concat(chunks).toString("utf8"));
137
+ if (patch == null || typeof patch !== "object") return json(400, { errors: ["body must be { patch: object }"] });
138
+ const merged = deepMerge(JSON.parse(readFileSync(input, "utf8")), patch);
139
+ const result = validate(merged);
140
+ if (!result.ok) return json(400, { errors: result.errors.map((e) => `${e.path.join(".") || "(root)"}: ${e.message}`) });
141
+ writeFileSync(input, `${formatConfig(merged)}\n`);
142
+ return json(200, {
143
+ ok: true,
144
+ warnings: result.warnings
145
+ });
146
+ } catch (err) {
147
+ return json(400, { errors: [err.message] });
148
+ }
149
+ });
150
+ });
61
151
  }
62
152
  };
63
153
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @getvitops/vite — a Vite plugin that generates Vitops design-system output from a\n * `design-system.json` during a Vite/Astro (EmDash) build, and hot-regenerates when\n * the config changes in dev.\n *\n * import vitops from '@getvitops/vite';\n * export default { plugins: [vitops({ input: 'design-system.json', format: 'tailwind', out: 'src/styles' })] };\n *\n * Thin wrapper over @getvitops/generator — the same generator the CLI uses.\n */\nimport { resolve } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generate, type Format } from '@getvitops/generator';\nimport { generateFavicons, writeFaviconManifest } from '@getvitops/utils';\n\nexport interface VitopsFaviconOptions {\n /** Source SVG or PNG. */\n source: string;\n /** Optional simplified source for the 16px icon. */\n lowResSource?: string;\n /** Directory to write the favicon set into. Default: 'public'. */\n out?: string;\n /** App name — when set (with `themeColor`), also emit `site.webmanifest`. */\n name?: string;\n /** PWA theme color (also drives `<meta name=\"theme-color\">`). */\n themeColor?: string;\n /** PWA background color. */\n backgroundColor?: string;\n}\n\nexport interface VitopsPluginOptions {\n /** Path to the design-system.json. Default: 'design-system.json'. */\n input?: string;\n /** Output target. Default: 'tailwind' (the EmDash/Astro case). */\n format?: Format;\n /** Directory to write generated output into. Default: 'src/styles'. */\n out?: string;\n /** Also generate a favicon set on build from this source image. */\n favicon?: VitopsFaviconOptions;\n}\n\nexport default function vitops(options: VitopsPluginOptions = {}): Plugin {\n const format: Format = options.format ?? 'tailwind';\n const outDir = options.out ?? 'src/styles';\n let input = resolve(options.input ?? 'design-system.json');\n let root = '';\n\n const run = async () => {\n await generate({ input, format, outDir });\n if (options.favicon) {\n const faviconOut = resolve(root, options.favicon.out ?? 'public');\n await generateFavicons({\n source: resolve(root, options.favicon.source),\n outputDir: faviconOut,\n ...(options.favicon.lowResSource\n ? { lowResSource: resolve(root, options.favicon.lowResSource) }\n : {}),\n });\n if (options.favicon.name && options.favicon.themeColor) {\n await writeFaviconManifest(faviconOut, {\n name: options.favicon.name,\n themeColor: options.favicon.themeColor,\n ...(options.favicon.backgroundColor\n ? { backgroundColor: options.favicon.backgroundColor }\n : {}),\n });\n }\n }\n };\n\n return {\n name: '@getvitops/vite',\n // Resolve paths against Vite's project root once it's known.\n configResolved(config) {\n root = config.root;\n input = resolve(config.root, options.input ?? 'design-system.json');\n },\n async buildStart() {\n this.addWatchFile(input);\n await run();\n },\n async watchChange(id) {\n if (resolve(id) === input) await run();\n },\n configureServer(server) {\n server.watcher.add(input);\n server.watcher.on('change', async (file) => {\n if (resolve(file) !== input) return;\n await run();\n server.ws.send({ type: 'full-reload' });\n });\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAyCA,SAAwB,OAAO,UAA+B,CAAC,GAAW;CACxE,MAAM,SAAiB,QAAQ,UAAU;CACzC,MAAM,SAAS,QAAQ,OAAO;CAC9B,IAAI,QAAQ,QAAQ,QAAQ,SAAS,oBAAoB;CACzD,IAAI,OAAO;CAEX,MAAM,MAAM,YAAY;EACtB,MAAM,SAAS;GAAE;GAAO;GAAQ;EAAO,CAAC;EACxC,IAAI,QAAQ,SAAS;GACnB,MAAM,aAAa,QAAQ,MAAM,QAAQ,QAAQ,OAAO,QAAQ;GAChE,MAAM,iBAAiB;IACrB,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,MAAM;IAC5C,WAAW;IACX,GAAI,QAAQ,QAAQ,eAChB,EAAE,cAAc,QAAQ,MAAM,QAAQ,QAAQ,YAAY,EAAE,IAC5D,CAAC;GACP,CAAC;GACD,IAAI,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,YAC1C,MAAM,qBAAqB,YAAY;IACrC,MAAM,QAAQ,QAAQ;IACtB,YAAY,QAAQ,QAAQ;IAC5B,GAAI,QAAQ,QAAQ,kBAChB,EAAE,iBAAiB,QAAQ,QAAQ,gBAAgB,IACnD,CAAC;GACP,CAAC;EAEL;CACF;CAEA,OAAO;EACL,MAAM;EAEN,eAAe,QAAQ;GACrB,OAAO,OAAO;GACd,QAAQ,QAAQ,OAAO,MAAM,QAAQ,SAAS,oBAAoB;EACpE;EACA,MAAM,aAAa;GACjB,KAAK,aAAa,KAAK;GACvB,MAAM,IAAI;EACZ;EACA,MAAM,YAAY,IAAI;GACpB,IAAI,QAAQ,EAAE,MAAM,OAAO,MAAM,IAAI;EACvC;EACA,gBAAgB,QAAQ;GACtB,OAAO,QAAQ,IAAI,KAAK;GACxB,OAAO,QAAQ,GAAG,UAAU,OAAO,SAAS;IAC1C,IAAI,QAAQ,IAAI,MAAM,OAAO;IAC7B,MAAM,IAAI;IACV,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;GACxC,CAAC;EACH;CACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @getvitops/vite — a Vite plugin that generates Vitops design-system output from a\n * `design-system.json` during a Vite/Astro (EmDash) build, and hot-regenerates when\n * the config changes in dev.\n *\n * import vitops from '@getvitops/vite';\n * export default { plugins: [vitops({ input: 'design-system.json', format: 'tailwind', out: 'src/styles' })] };\n *\n * Thin wrapper over @getvitops/generator — the same generator the CLI uses.\n */\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport type { Plugin } from 'vite';\nimport { generate, validate, type Format } from '@getvitops/generator';\nimport { generateFavicons, writeFaviconManifest } from '@getvitops/utils';\n\n/** Endpoint `<wc-theme-editor>` probes for, and POSTs its patch to. */\nconst EDITOR_ENDPOINT = '/__vitops/design-system';\n\n/**\n * Recursively merge a patch into a config. Plain objects merge key-wise;\n * everything else (scalars, and arrays — a token list is replaced, not appended)\n * is overwritten by the patch.\n */\nfunction deepMerge(base: unknown, patch: unknown): unknown {\n const isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n if (!isPlain(base) || !isPlain(patch)) return patch;\n const out: Record<string, unknown> = { ...base };\n for (const [k, v] of Object.entries(patch)) out[k] = deepMerge(base[k], v);\n return out;\n}\n\n/** Printed width the config is formatted to — matches the repo formatter's default. */\nconst PRINT_WIDTH = 100;\n\n/**\n * Serialize a config the way a formatter would: 2-space indent, but arrays of\n * scalars kept on one line when they fit.\n *\n * `JSON.stringify(v, null, 2)` explodes every array onto its own lines, so writing\n * back a two-key patch reflowed ~300 lines of `design-system.json` — a diff nobody\n * can review, for a change of two values. Matching the prevailing style keeps the\n * write surgical, which is the whole point of saving to source rather than copying\n * a patch by hand.\n */\nfunction formatConfig(value: unknown, col = 0, indent = 0): string {\n const pad = ' '.repeat(indent);\n if (Array.isArray(value)) {\n if (!value.length) return '[]';\n if (value.every((v) => v === null || typeof v !== 'object')) {\n const inline = `[${value.map((v) => JSON.stringify(v)).join(', ')}]`;\n if (col + inline.length <= PRINT_WIDTH) return inline;\n }\n const items = value.map((v) => `${pad} ${formatConfig(v, indent + 2, indent + 2)}`);\n return `[\\n${items.join(',\\n')}\\n${pad}]`;\n }\n if (value !== null && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>);\n if (!entries.length) return '{}';\n const items = entries.map(([k, v]) => {\n const head = `${pad} ${JSON.stringify(k)}: `;\n return head + formatConfig(v, head.length, indent + 2);\n });\n return `{\\n${items.join(',\\n')}\\n${pad}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n\nexport interface VitopsFaviconOptions {\n /** Source SVG or PNG. */\n source: string;\n /** Optional simplified source for the 16px icon. */\n lowResSource?: string;\n /** Directory to write the favicon set into. Default: 'public'. */\n out?: string;\n /** App name — when set (with `themeColor`), also emit `site.webmanifest`. */\n name?: string;\n /** PWA theme color (also drives `<meta name=\"theme-color\">`). */\n themeColor?: string;\n /** PWA background color. */\n backgroundColor?: string;\n}\n\nexport interface VitopsPluginOptions {\n /** Path to the design-system.json. Default: 'design-system.json'. */\n input?: string;\n /** Output target. Default: 'tailwind' (the EmDash/Astro case). */\n format?: Format;\n /** Directory to write generated output into. Default: 'src/styles'. */\n out?: string;\n /** Also generate a favicon set on build from this source image. */\n favicon?: VitopsFaviconOptions;\n /**\n * Directory to mirror `design-manifest.json` into as `vitops/design-manifest.json`\n * — the URL `<wc-theme-editor>` fetches by default. Set by the Astro integration's\n * `editor` option. Copied inside the generate pass rather than by the caller, so\n * it can't race the first generation and can't go stale on regeneration.\n */\n editorManifestDir?: string;\n}\n\nexport default function vitops(options: VitopsPluginOptions = {}): Plugin {\n const format: Format = options.format ?? 'tailwind';\n const outDir = options.out ?? 'src/styles';\n let input = resolve(options.input ?? 'design-system.json');\n let root = '';\n\n const run = async () => {\n await generate({ input, format, outDir });\n if (options.editorManifestDir) {\n const src = resolve(root, outDir, 'design-manifest.json');\n if (existsSync(src)) {\n const dest = resolve(root, options.editorManifestDir, 'vitops');\n mkdirSync(dest, { recursive: true });\n copyFileSync(src, join(dest, 'design-manifest.json'));\n }\n }\n if (options.favicon) {\n const faviconOut = resolve(root, options.favicon.out ?? 'public');\n await generateFavicons({\n source: resolve(root, options.favicon.source),\n outputDir: faviconOut,\n ...(options.favicon.lowResSource\n ? { lowResSource: resolve(root, options.favicon.lowResSource) }\n : {}),\n });\n if (options.favicon.name && options.favicon.themeColor) {\n await writeFaviconManifest(faviconOut, {\n name: options.favicon.name,\n themeColor: options.favicon.themeColor,\n ...(options.favicon.backgroundColor\n ? { backgroundColor: options.favicon.backgroundColor }\n : {}),\n });\n }\n }\n };\n\n return {\n name: '@getvitops/vite',\n // Resolve paths against Vite's project root once it's known.\n configResolved(config) {\n root = config.root;\n input = resolve(config.root, options.input ?? 'design-system.json');\n },\n async buildStart() {\n this.addWatchFile(input);\n await run();\n },\n async watchChange(id) {\n if (resolve(id) === input) await run();\n },\n configureServer(server) {\n server.watcher.add(input);\n server.watcher.on('change', async (file) => {\n if (resolve(file) !== input) return;\n await run();\n server.ws.send({ type: 'full-reload' });\n });\n\n // Dev-only design-system write-back, for `<wc-theme-editor>`'s \"Save to\n // source\". Registered in configureServer only, so it exists in `vite dev`\n // and never in a build — on a static deploy the editor's probe 404s and the\n // button simply isn't rendered. The only writable path is `input`, already\n // resolved from config: a request supplies a patch, never a destination.\n server.middlewares.use(EDITOR_ENDPOINT, (req, res, next) => {\n const json = (status: number, body: unknown): void => {\n res.statusCode = status;\n res.setHeader('content-type', 'application/json');\n res.end(JSON.stringify(body));\n };\n\n if (req.method === 'GET') {\n try {\n return json(200, {\n writable: true,\n path: input,\n config: JSON.parse(readFileSync(input, 'utf8')),\n });\n } catch (err) {\n return json(500, { error: (err as Error).message });\n }\n }\n\n if (req.method !== 'POST') return next();\n\n const chunks: Buffer[] = [];\n req.on('data', (c: Buffer) => chunks.push(c));\n req.on('end', () => {\n try {\n const { patch } = JSON.parse(Buffer.concat(chunks).toString('utf8')) as {\n patch?: unknown;\n };\n if (patch == null || typeof patch !== 'object')\n return json(400, { errors: ['body must be { patch: object }'] });\n\n const current = JSON.parse(readFileSync(input, 'utf8')) as unknown;\n const merged = deepMerge(current, patch);\n // Validate the *merged* result, not the patch: a patch is a partial\n // by design, so it can't be validated on its own, and writing an\n // invalid config would break the very dev server doing the writing.\n const result = validate(merged);\n if (!result.ok)\n return json(400, {\n errors: result.errors.map((e) => `${e.path.join('.') || '(root)'}: ${e.message}`),\n });\n\n writeFileSync(input, `${formatConfig(merged)}\\n`);\n // The watcher above picks the write up and regenerates + reloads.\n return json(200, { ok: true, warnings: result.warnings });\n } catch (err) {\n return json(400, { errors: [(err as Error).message] });\n }\n });\n });\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvitops/vite",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Vite plugin that generates Vitops design-system outputs from a design-system.json during a Vite/Astro build.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -18,8 +18,8 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@getvitops/generator": "0.7.0",
22
- "@getvitops/utils": "0.7.0"
21
+ "@getvitops/generator": "0.9.0",
22
+ "@getvitops/utils": "0.9.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "vite": "^6.0.0"