@auto-engineer/generate-react-client 1.76.0 → 1.77.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,24 @@
1
1
  # @auto-engineer/generate-react-client
2
2
 
3
+ ## 1.77.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`86f1663`](https://github.com/BeOnAuto/auto-engineer/commit/86f166399983a32804d3cc43ea51638b044c0ecc) Thanks [@osamanar](https://github.com/osamanar)! - - Fixed component generation in the React component implementer
8
+
9
+ - [`2040186`](https://github.com/BeOnAuto/auto-engineer/commit/2040186f95edbc78748e79d79b9e606e058bce08) Thanks [@osamanar](https://github.com/osamanar)! - - **react-component-implementer**: add comprehensive visual design system to prompt
10
+
11
+ ### Patch Changes
12
+
13
+ - [`b668102`](https://github.com/BeOnAuto/auto-engineer/commit/b668102043e71071c4fb5f776fdcd68b357606ee) Thanks [@github-actions[bot]](https://github.com/github-actions%5Bbot%5D)! - - **dev-server**: kill stale port holders before spawning services
14
+ - **dev-server**: make port-cleanup a pure utility with no lifecycle side effects
15
+ - **server-generator-apollo-emmett**: remove try/catch that swallows command errors
16
+ - **global**: version packages
17
+ - **dev-server**: finalize ketchup plan for port-cleanup fix
18
+ - Updated dependencies [[`86f1663`](https://github.com/BeOnAuto/auto-engineer/commit/86f166399983a32804d3cc43ea51638b044c0ecc), [`2040186`](https://github.com/BeOnAuto/auto-engineer/commit/2040186f95edbc78748e79d79b9e606e058bce08), [`b668102`](https://github.com/BeOnAuto/auto-engineer/commit/b668102043e71071c4fb5f776fdcd68b357606ee)]:
19
+ - @auto-engineer/file-upload@1.77.0
20
+ - @auto-engineer/message-bus@1.77.0
21
+
3
22
  ## 1.76.0
4
23
 
5
24
  ### Minor Changes
@@ -0,0 +1,5 @@
1
+ export declare function buildThemeSystemPrompt(): string;
2
+ export declare function buildThemeUserPrompt(modelJson: unknown): string;
3
+ export declare function parseThemeCss(text: string): string;
4
+ export declare function generateThemeCss(modelJson: unknown): Promise<string>;
5
+ //# sourceMappingURL=generate-theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-theme.d.ts","sourceRoot":"","sources":["../../src/generate-theme.ts"],"names":[],"mappings":"AAoKA,wBAAgB,sBAAsB,IAAI,MAAM,CAgE/C;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAmD/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBlD;AAsBD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB1E"}
@@ -0,0 +1,316 @@
1
+ import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
2
+ import { generateText } from 'ai';
3
+ import createDebug from 'debug';
4
+ const debug = createDebug('auto:generate-react-client:theme');
5
+ function requireEnv(name) {
6
+ const value = process.env[name];
7
+ if (!value) {
8
+ throw new Error(`Missing required environment variable: ${name}`);
9
+ }
10
+ return value;
11
+ }
12
+ function createModel() {
13
+ const name = requireEnv('CUSTOM_PROVIDER_NAME');
14
+ const baseURL = requireEnv('CUSTOM_PROVIDER_BASE_URL');
15
+ const apiKey = requireEnv('CUSTOM_PROVIDER_API_KEY');
16
+ const model = requireEnv('CUSTOM_PROVIDER_DEFAULT_MODEL');
17
+ return createOpenAICompatible({ name, baseURL, apiKey }).chatModel(model);
18
+ }
19
+ const TEMPLATE_CSS = `@import "tailwindcss";
20
+ @import "tw-animate-css";
21
+
22
+ @custom-variant dark (&:is(.dark *));
23
+
24
+ @theme inline {
25
+ --color-background: var(--background);
26
+ --color-foreground: var(--foreground);
27
+ --color-card: var(--card);
28
+ --color-card-foreground: var(--card-foreground);
29
+ --color-popover: var(--popover);
30
+ --color-popover-foreground: var(--popover-foreground);
31
+ --color-primary: var(--primary);
32
+ --color-primary-foreground: var(--primary-foreground);
33
+ --color-secondary: var(--secondary);
34
+ --color-secondary-foreground: var(--secondary-foreground);
35
+ --color-muted: var(--muted);
36
+ --color-muted-foreground: var(--muted-foreground);
37
+ --color-accent: var(--accent);
38
+ --color-accent-foreground: var(--accent-foreground);
39
+ --color-destructive: var(--destructive);
40
+ --color-destructive-foreground: var(--destructive-foreground);
41
+ --color-border: var(--border);
42
+ --color-input: var(--input);
43
+ --color-ring: var(--ring);
44
+ --color-chart-1: var(--chart-1);
45
+ --color-chart-2: var(--chart-2);
46
+ --color-chart-3: var(--chart-3);
47
+ --color-chart-4: var(--chart-4);
48
+ --color-chart-5: var(--chart-5);
49
+ --color-sidebar: var(--sidebar);
50
+ --color-sidebar-foreground: var(--sidebar-foreground);
51
+ --color-sidebar-primary: var(--sidebar-primary);
52
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
53
+ --color-sidebar-accent: var(--sidebar-accent);
54
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
55
+ --color-sidebar-border: var(--sidebar-border);
56
+ --color-sidebar-ring: var(--sidebar-ring);
57
+ --radius-sm: calc(var(--radius) - 4px);
58
+ --radius-md: calc(var(--radius) - 2px);
59
+ --radius-lg: var(--radius);
60
+ --radius-xl: calc(var(--radius) + 4px);
61
+ --font-sans: var(--font-sans);
62
+ --font-heading: var(--font-heading);
63
+ --shadow-xs: var(--shadow-xs);
64
+ --shadow-sm: var(--shadow-sm);
65
+ --shadow-md: var(--shadow-md);
66
+ --shadow-lg: var(--shadow-lg);
67
+ --shadow-2xl: var(--shadow-2xl);
68
+ }
69
+
70
+ :root {
71
+ --radius: 0.625rem;
72
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
73
+ --font-heading: "Inter", ui-sans-serif, system-ui, sans-serif;
74
+ --spacing: 0.25rem;
75
+ --tracking-tight: -0.025em;
76
+ --tracking-wide: 0.025em;
77
+ --leading-normal: 1.5;
78
+ --leading-relaxed: 1.75;
79
+ --shadow-xs: 0 1px 2px 0 oklch(0 0 0 / 5%);
80
+ --shadow-sm: 0 1px 3px 0 oklch(0 0 0 / 10%), 0 1px 2px -1px oklch(0 0 0 / 10%);
81
+ --shadow-md: 0 4px 6px -1px oklch(0 0 0 / 10%), 0 2px 4px -2px oklch(0 0 0 / 10%);
82
+ --shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 10%), 0 4px 6px -4px oklch(0 0 0 / 10%);
83
+ --shadow-2xl: 0 25px 50px -12px oklch(0 0 0 / 25%);
84
+ --background: oklch(1 0 0);
85
+ --foreground: oklch(0.145 0 0);
86
+ --card: oklch(1 0 0);
87
+ --card-foreground: oklch(0.145 0 0);
88
+ --popover: oklch(1 0 0);
89
+ --popover-foreground: oklch(0.145 0 0);
90
+ --primary: oklch(0.205 0 0);
91
+ --primary-foreground: oklch(0.985 0 0);
92
+ --secondary: oklch(0.97 0 0);
93
+ --secondary-foreground: oklch(0.205 0 0);
94
+ --muted: oklch(0.97 0 0);
95
+ --muted-foreground: oklch(0.556 0 0);
96
+ --accent: oklch(0.97 0 0);
97
+ --accent-foreground: oklch(0.205 0 0);
98
+ --destructive: oklch(0.577 0.245 27.325);
99
+ --border: oklch(0.922 0 0);
100
+ --input: oklch(0.922 0 0);
101
+ --ring: oklch(0.708 0 0);
102
+ --chart-1: oklch(0.646 0.222 41.116);
103
+ --chart-2: oklch(0.6 0.118 184.704);
104
+ --chart-3: oklch(0.398 0.07 227.392);
105
+ --chart-4: oklch(0.828 0.189 84.429);
106
+ --chart-5: oklch(0.769 0.188 70.08);
107
+ --sidebar: oklch(0.985 0 0);
108
+ --sidebar-foreground: oklch(0.145 0 0);
109
+ --sidebar-primary: oklch(0.205 0 0);
110
+ --sidebar-primary-foreground: oklch(0.985 0 0);
111
+ --sidebar-accent: oklch(0.97 0 0);
112
+ --sidebar-accent-foreground: oklch(0.205 0 0);
113
+ --sidebar-border: oklch(0.922 0 0);
114
+ --sidebar-ring: oklch(0.708 0 0);
115
+ }
116
+
117
+ .dark {
118
+ --background: oklch(0.129 0.042 264.695);
119
+ --foreground: oklch(0.985 0 0);
120
+ --card: oklch(0.205 0 0);
121
+ --card-foreground: oklch(0.985 0 0);
122
+ --popover: oklch(0.205 0 0);
123
+ --popover-foreground: oklch(0.985 0 0);
124
+ --primary: oklch(0.922 0 0);
125
+ --primary-foreground: oklch(0.205 0 0);
126
+ --secondary: oklch(0.269 0 0);
127
+ --secondary-foreground: oklch(0.985 0 0);
128
+ --muted: oklch(0.269 0 0);
129
+ --muted-foreground: oklch(0.708 0 0);
130
+ --accent: oklch(0.269 0 0);
131
+ --accent-foreground: oklch(0.985 0 0);
132
+ --destructive: oklch(0.704 0.191 22.216);
133
+ --border: oklch(1 0 0 / 10%);
134
+ --input: oklch(1 0 0 / 15%);
135
+ --ring: oklch(0.556 0 0);
136
+ --chart-1: oklch(0.488 0.243 264.376);
137
+ --chart-2: oklch(0.696 0.17 162.48);
138
+ --chart-3: oklch(0.769 0.188 70.08);
139
+ --chart-4: oklch(0.627 0.265 303.9);
140
+ --chart-5: oklch(0.645 0.246 16.439);
141
+ --sidebar: oklch(0.205 0 0);
142
+ --sidebar-foreground: oklch(0.985 0 0);
143
+ --sidebar-primary: oklch(0.488 0.243 264.376);
144
+ --sidebar-primary-foreground: oklch(0.985 0 0);
145
+ --sidebar-accent: oklch(0.269 0 0);
146
+ --sidebar-accent-foreground: oklch(0.985 0 0);
147
+ --sidebar-border: oklch(1 0 0 / 10%);
148
+ --sidebar-ring: oklch(0.556 0 0);
149
+ }
150
+
151
+ @layer base {
152
+ * {
153
+ @apply border-border outline-ring/50;
154
+ }
155
+ body {
156
+ @apply bg-background text-foreground;
157
+ }
158
+ }`;
159
+ export function buildThemeSystemPrompt() {
160
+ return `You are a design system specialist who generates themed CSS for web applications. Given a narrative model describing an application's domain, you infer the app's personality and generate a complete index.css with appropriate theming.
161
+
162
+ ## Color Personality Mapping
163
+ - Blue/Indigo (hue 240-270) = trust, professionalism, enterprise (banking, finance, corporate)
164
+ - Green (hue 140-160) = growth, nature, health, wellness (fitness, healthcare, eco)
165
+ - Gold/Amber (hue 70-90) = luxury, premium, sophisticated (fashion, jewelry, high-end)
166
+ - Pink/Rose (hue 340-360) = fun, creative, playful (social, kids, entertainment)
167
+ - Red/Orange (hue 15-45) = energy, urgency, action (sports, gaming, deals)
168
+ - Purple (hue 280-310) = creativity, wisdom, innovation (education, AI, art)
169
+ - Teal/Cyan (hue 180-200) = modern, clean, technical (dev tools, SaaS, analytics)
170
+
171
+ ## Color Rules
172
+ - All colors MUST use oklch(L C H) format
173
+ - Greys should be slightly saturated with the dominant hue (warm or cool, never pure grey with chroma 0 for primary/accent colors)
174
+ - Background/foreground must have >= 4.5:1 contrast ratio (WCAG AA)
175
+ - Never use true black; use very dark saturated tones
176
+ - Light mode: background L=0.97-1.0, foreground L=0.1-0.2
177
+ - Dark mode: background L=0.1-0.15 with blue-tinted hue, use alpha transparency for borders
178
+
179
+ ## Border Radius
180
+ - 0rem = stark/brutalist
181
+ - 0.25rem = formal/serious
182
+ - 0.5-0.625rem = neutral/balanced
183
+ - 0.75-1rem = playful/friendly
184
+
185
+ ## Font Selection (Google Fonts)
186
+ Pick a Google Font that matches the domain personality:
187
+ - Neutral sans-serif (Inter, DM Sans) for utility/SaaS apps
188
+ - Rounded sans-serif (Nunito, Quicksand) for playful/consumer apps
189
+ - Serif (Playfair Display, Lora) for elegant/editorial apps
190
+ - Monospace-influenced (Space Grotesk, JetBrains Mono) for developer tools
191
+ - Only use typefaces with 5+ weights available
192
+ - You may use the same font for both --font-sans and --font-heading, or pick a complementary heading font
193
+
194
+ ## Shadow System
195
+ 5 elevation levels (xs, sm, md, lg, 2xl):
196
+ - Use two-part shadows (direct light + ambient) for higher elevations
197
+ - Flat/minimal shadows for serious/professional apps
198
+ - Deeper/more dramatic shadows for playful/consumer apps
199
+
200
+ ## Spacing Density
201
+ - --spacing base unit: 0.25rem (dense/compact for dashboards) vs 0.3rem (comfortable for content-heavy)
202
+
203
+ ## Typography
204
+ - --tracking-tight: tighter letter-spacing for headlines (e.g., -0.025em to -0.05em)
205
+ - --tracking-wide: wider letter-spacing for all-caps or labels (e.g., 0.025em to 0.1em)
206
+ - --leading-normal: base line height (1.5 for readable text)
207
+ - --leading-relaxed: generous line height for content-heavy apps (1.625-1.75)
208
+ - Values should match the app's content density
209
+
210
+ ## Output Format
211
+ Output a COMPLETE index.css inside a \`\`\`css code block. The CSS must:
212
+ 1. Start with a Google Fonts @import at the very top (before @import "tailwindcss")
213
+ 2. Keep @import "tailwindcss" and @import "tw-animate-css"
214
+ 3. Keep @custom-variant dark (&:is(.dark *))
215
+ 4. In @theme inline, keep ALL existing --color-* variable mappings and --radius-* calculations, and ADD: --font-sans, --font-heading, --shadow-xs, --shadow-sm, --shadow-md, --shadow-lg, --shadow-2xl
216
+ 5. In :root, set ALL CSS variables with themed oklch values, PLUS: --font-sans, --font-heading, --spacing, --tracking-tight, --tracking-wide, --leading-normal, --leading-relaxed, --shadow-xs through --shadow-2xl
217
+ 6. In .dark, set ALL CSS variables with dark mode oklch values
218
+ 7. Keep the @layer base block unchanged
219
+
220
+ Here is the template CSS structure to follow (change the values, keep the structure):
221
+
222
+ ${TEMPLATE_CSS}`;
223
+ }
224
+ export function buildThemeUserPrompt(modelJson) {
225
+ const model = modelJson;
226
+ const lines = [];
227
+ lines.push('Here is the narrative model for the application:\n');
228
+ const narratives = model.narratives;
229
+ if (Array.isArray(narratives)) {
230
+ for (const narrative of narratives) {
231
+ lines.push(`## Narrative: ${narrative.name ?? 'Unnamed'}`);
232
+ if (narrative.description) {
233
+ lines.push(`Description: ${narrative.description}`);
234
+ }
235
+ const slices = narrative.slices;
236
+ if (Array.isArray(slices)) {
237
+ for (const slice of slices) {
238
+ lines.push(` - Slice: ${slice.name ?? 'Unnamed'} (type: ${slice.type ?? 'unknown'})`);
239
+ if (slice.description) {
240
+ lines.push(` Description: ${slice.description}`);
241
+ }
242
+ const messages = slice.messages;
243
+ if (messages) {
244
+ const msgTypes = ['commands', 'events', 'states', 'queries'];
245
+ for (const msgType of msgTypes) {
246
+ const items = messages[msgType];
247
+ if (Array.isArray(items) && items.length > 0) {
248
+ const names = items.map((m) => m.name ?? 'unnamed').join(', ');
249
+ lines.push(` ${msgType}: ${names}`);
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ lines.push('');
256
+ }
257
+ }
258
+ if (model.name) {
259
+ lines.push(`Application name: ${model.name}`);
260
+ }
261
+ if (model.description) {
262
+ lines.push(`Application description: ${model.description}`);
263
+ }
264
+ lines.push('\nBased on these narratives, infer the application domain and personality, then generate a themed index.css.');
265
+ return lines.join('\n');
266
+ }
267
+ export function parseThemeCss(text) {
268
+ const fencedMatch = text.match(/```css\s*\n([\s\S]*?)```/);
269
+ if (fencedMatch) {
270
+ return validateCss(fencedMatch[1].trim());
271
+ }
272
+ const bareFencedMatch = text.match(/```\s*\n([\s\S]*?)```/);
273
+ if (bareFencedMatch) {
274
+ return validateCss(bareFencedMatch[1].trim());
275
+ }
276
+ if (text.includes('@import "tailwindcss"') && text.includes('@theme inline')) {
277
+ return validateCss(text.trim());
278
+ }
279
+ throw new Error('Could not extract CSS from AI response');
280
+ }
281
+ function validateCss(css) {
282
+ const required = [
283
+ '@import "tailwindcss"',
284
+ '@theme inline',
285
+ ':root',
286
+ '.dark',
287
+ '@layer base',
288
+ '--background',
289
+ '--primary',
290
+ 'oklch',
291
+ ];
292
+ const missing = required.filter((token) => !css.includes(token));
293
+ if (missing.length > 0) {
294
+ throw new Error(`Generated CSS is missing required sections: ${missing.join(', ')}`);
295
+ }
296
+ return css;
297
+ }
298
+ export async function generateThemeCss(modelJson) {
299
+ debug('Starting theme generation from narrative model');
300
+ const systemPrompt = buildThemeSystemPrompt();
301
+ const userPrompt = buildThemeUserPrompt(modelJson);
302
+ debug('System prompt length: %d chars', systemPrompt.length);
303
+ debug('User prompt length: %d chars', userPrompt.length);
304
+ const { text } = await generateText({
305
+ model: createModel(),
306
+ messages: [
307
+ { role: 'system', content: systemPrompt },
308
+ { role: 'user', content: userPrompt },
309
+ ],
310
+ });
311
+ debug('Received AI response, length: %d chars', text.length);
312
+ const css = parseThemeCss(text);
313
+ debug('Successfully parsed and validated theme CSS');
314
+ return css;
315
+ }
316
+ //# sourceMappingURL=generate-theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-theme.js","sourceRoot":"","sources":["../../src/generate-theme.ts"],"names":[],"mappings":"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"}
@@ -81,6 +81,9 @@ importers:
81
81
  specifier: ^4.3.6
82
82
  version: 4.3.6
83
83
  devDependencies:
84
+ '@biomejs/biome':
85
+ specifier: ^2.3.10
86
+ version: 2.4.4
84
87
  '@graphql-codegen/cli':
85
88
  specifier: ^6.1.1
86
89
  version: 6.1.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(graphql@16.12.0)(typescript@5.9.3)
@@ -132,6 +135,9 @@ importers:
132
135
  graphql:
133
136
  specifier: ^16.12.0
134
137
  version: 16.12.0
138
+ happy-dom:
139
+ specifier: ^18.0.1
140
+ version: 18.0.1
135
141
  jsdom:
136
142
  specifier: ^26.1.0
137
143
  version: 26.1.0
@@ -158,7 +164,7 @@ importers:
158
164
  version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)
159
165
  vitest:
160
166
  specifier: ^3.2.1
161
- version: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
167
+ version: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
162
168
 
163
169
  packages:
164
170
 
@@ -284,6 +290,59 @@ packages:
284
290
  resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
285
291
  engines: {node: '>=18'}
286
292
 
293
+ '@biomejs/biome@2.4.4':
294
+ resolution: {integrity: sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q==}
295
+ engines: {node: '>=14.21.3'}
296
+ hasBin: true
297
+
298
+ '@biomejs/cli-darwin-arm64@2.4.4':
299
+ resolution: {integrity: sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A==}
300
+ engines: {node: '>=14.21.3'}
301
+ cpu: [arm64]
302
+ os: [darwin]
303
+
304
+ '@biomejs/cli-darwin-x64@2.4.4':
305
+ resolution: {integrity: sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg==}
306
+ engines: {node: '>=14.21.3'}
307
+ cpu: [x64]
308
+ os: [darwin]
309
+
310
+ '@biomejs/cli-linux-arm64-musl@2.4.4':
311
+ resolution: {integrity: sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ==}
312
+ engines: {node: '>=14.21.3'}
313
+ cpu: [arm64]
314
+ os: [linux]
315
+
316
+ '@biomejs/cli-linux-arm64@2.4.4':
317
+ resolution: {integrity: sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg==}
318
+ engines: {node: '>=14.21.3'}
319
+ cpu: [arm64]
320
+ os: [linux]
321
+
322
+ '@biomejs/cli-linux-x64-musl@2.4.4':
323
+ resolution: {integrity: sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g==}
324
+ engines: {node: '>=14.21.3'}
325
+ cpu: [x64]
326
+ os: [linux]
327
+
328
+ '@biomejs/cli-linux-x64@2.4.4':
329
+ resolution: {integrity: sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg==}
330
+ engines: {node: '>=14.21.3'}
331
+ cpu: [x64]
332
+ os: [linux]
333
+
334
+ '@biomejs/cli-win32-arm64@2.4.4':
335
+ resolution: {integrity: sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q==}
336
+ engines: {node: '>=14.21.3'}
337
+ cpu: [arm64]
338
+ os: [win32]
339
+
340
+ '@biomejs/cli-win32-x64@2.4.4':
341
+ resolution: {integrity: sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A==}
342
+ engines: {node: '>=14.21.3'}
343
+ cpu: [x64]
344
+ os: [win32]
345
+
287
346
  '@csstools/color-helpers@5.1.0':
288
347
  resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
289
348
  engines: {node: '>=18'}
@@ -2302,6 +2361,9 @@ packages:
2302
2361
  '@types/mdx@2.0.13':
2303
2362
  resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==}
2304
2363
 
2364
+ '@types/node@20.19.33':
2365
+ resolution: {integrity: sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==}
2366
+
2305
2367
  '@types/node@25.2.3':
2306
2368
  resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
2307
2369
 
@@ -2319,6 +2381,9 @@ packages:
2319
2381
  '@types/statuses@2.0.6':
2320
2382
  resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==}
2321
2383
 
2384
+ '@types/whatwg-mimetype@3.0.2':
2385
+ resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==}
2386
+
2322
2387
  '@types/ws@8.18.1':
2323
2388
  resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
2324
2389
 
@@ -2997,6 +3062,10 @@ packages:
2997
3062
  resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==}
2998
3063
  engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
2999
3064
 
3065
+ happy-dom@18.0.1:
3066
+ resolution: {integrity: sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==}
3067
+ engines: {node: '>=20.0.0'}
3068
+
3000
3069
  has-flag@4.0.0:
3001
3070
  resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
3002
3071
  engines: {node: '>=8'}
@@ -4094,6 +4163,9 @@ packages:
4094
4163
  resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==}
4095
4164
  engines: {node: '>=0.10.0'}
4096
4165
 
4166
+ undici-types@6.21.0:
4167
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
4168
+
4097
4169
  undici-types@7.16.0:
4098
4170
  resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
4099
4171
 
@@ -4264,6 +4336,10 @@ packages:
4264
4336
  engines: {node: '>=18'}
4265
4337
  deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
4266
4338
 
4339
+ whatwg-mimetype@3.0.0:
4340
+ resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
4341
+ engines: {node: '>=12'}
4342
+
4267
4343
  whatwg-mimetype@4.0.0:
4268
4344
  resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
4269
4345
  engines: {node: '>=18'}
@@ -4523,6 +4599,41 @@ snapshots:
4523
4599
 
4524
4600
  '@bcoe/v8-coverage@1.0.2': {}
4525
4601
 
4602
+ '@biomejs/biome@2.4.4':
4603
+ optionalDependencies:
4604
+ '@biomejs/cli-darwin-arm64': 2.4.4
4605
+ '@biomejs/cli-darwin-x64': 2.4.4
4606
+ '@biomejs/cli-linux-arm64': 2.4.4
4607
+ '@biomejs/cli-linux-arm64-musl': 2.4.4
4608
+ '@biomejs/cli-linux-x64': 2.4.4
4609
+ '@biomejs/cli-linux-x64-musl': 2.4.4
4610
+ '@biomejs/cli-win32-arm64': 2.4.4
4611
+ '@biomejs/cli-win32-x64': 2.4.4
4612
+
4613
+ '@biomejs/cli-darwin-arm64@2.4.4':
4614
+ optional: true
4615
+
4616
+ '@biomejs/cli-darwin-x64@2.4.4':
4617
+ optional: true
4618
+
4619
+ '@biomejs/cli-linux-arm64-musl@2.4.4':
4620
+ optional: true
4621
+
4622
+ '@biomejs/cli-linux-arm64@2.4.4':
4623
+ optional: true
4624
+
4625
+ '@biomejs/cli-linux-x64-musl@2.4.4':
4626
+ optional: true
4627
+
4628
+ '@biomejs/cli-linux-x64@2.4.4':
4629
+ optional: true
4630
+
4631
+ '@biomejs/cli-win32-arm64@2.4.4':
4632
+ optional: true
4633
+
4634
+ '@biomejs/cli-win32-x64@2.4.4':
4635
+ optional: true
4636
+
4526
4637
  '@csstools/color-helpers@5.1.0': {}
4527
4638
 
4528
4639
  '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
@@ -6658,6 +6769,10 @@ snapshots:
6658
6769
 
6659
6770
  '@types/mdx@2.0.13': {}
6660
6771
 
6772
+ '@types/node@20.19.33':
6773
+ dependencies:
6774
+ undici-types: 6.21.0
6775
+
6661
6776
  '@types/node@25.2.3':
6662
6777
  dependencies:
6663
6778
  undici-types: 7.16.0
@@ -6674,6 +6789,8 @@ snapshots:
6674
6789
 
6675
6790
  '@types/statuses@2.0.6': {}
6676
6791
 
6792
+ '@types/whatwg-mimetype@3.0.2': {}
6793
+
6677
6794
  '@types/ws@8.18.1':
6678
6795
  dependencies:
6679
6796
  '@types/node': 25.2.3
@@ -6705,7 +6822,7 @@ snapshots:
6705
6822
  std-env: 3.10.0
6706
6823
  test-exclude: 7.0.1
6707
6824
  tinyrainbow: 2.0.0
6708
- vitest: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
6825
+ vitest: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
6709
6826
  transitivePeerDependencies:
6710
6827
  - supports-color
6711
6828
 
@@ -6755,7 +6872,7 @@ snapshots:
6755
6872
  sirv: 3.0.2
6756
6873
  tinyglobby: 0.2.15
6757
6874
  tinyrainbow: 2.0.0
6758
- vitest: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
6875
+ vitest: 3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2)
6759
6876
 
6760
6877
  '@vitest/utils@3.2.4':
6761
6878
  dependencies:
@@ -7374,6 +7491,12 @@ snapshots:
7374
7491
 
7375
7492
  graphql@16.12.0: {}
7376
7493
 
7494
+ happy-dom@18.0.1:
7495
+ dependencies:
7496
+ '@types/node': 20.19.33
7497
+ '@types/whatwg-mimetype': 3.0.2
7498
+ whatwg-mimetype: 3.0.0
7499
+
7377
7500
  has-flag@4.0.0: {}
7378
7501
 
7379
7502
  hasown@2.0.2:
@@ -8485,6 +8608,8 @@ snapshots:
8485
8608
 
8486
8609
  unc-path-regex@0.1.2: {}
8487
8610
 
8611
+ undici-types@6.21.0: {}
8612
+
8488
8613
  undici-types@7.16.0: {}
8489
8614
 
8490
8615
  unixify@1.0.0:
@@ -8603,7 +8728,7 @@ snapshots:
8603
8728
  lightningcss: 1.30.2
8604
8729
  yaml: 2.8.2
8605
8730
 
8606
- vitest@3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2):
8731
+ vitest@3.2.4(@types/node@25.2.3)(@vitest/ui@3.2.4)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(msw@2.12.10(@types/node@25.2.3)(typescript@5.9.3))(yaml@2.8.2):
8607
8732
  dependencies:
8608
8733
  '@types/chai': 5.2.3
8609
8734
  '@vitest/expect': 3.2.4
@@ -8631,6 +8756,7 @@ snapshots:
8631
8756
  optionalDependencies:
8632
8757
  '@types/node': 25.2.3
8633
8758
  '@vitest/ui': 3.2.4(vitest@3.2.4)
8759
+ happy-dom: 18.0.1
8634
8760
  jsdom: 26.1.0
8635
8761
  transitivePeerDependencies:
8636
8762
  - jiti
@@ -8662,6 +8788,8 @@ snapshots:
8662
8788
  dependencies:
8663
8789
  iconv-lite: 0.6.3
8664
8790
 
8791
+ whatwg-mimetype@3.0.0: {}
8792
+
8665
8793
  whatwg-mimetype@4.0.0: {}
8666
8794
 
8667
8795
  whatwg-url@14.2.0:
@@ -280,18 +280,20 @@ function ChartLegendContent({
280
280
  // Helper to extract item config from a payload.
281
281
  function getPayloadConfigFromPayload(
282
282
  config: ChartConfig,
283
- payload: Record<string, string | number | Record<string, string>>,
283
+ payload: unknown,
284
284
  key: string,
285
285
  ) {
286
+ const typedPayload = payload as Record<string, unknown>;
287
+
286
288
  const payloadPayload =
287
- 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
288
- ? (payload.payload as Record<string, string>)
289
+ 'payload' in typedPayload && typeof typedPayload.payload === 'object' && typedPayload.payload !== null
290
+ ? (typedPayload.payload as Record<string, string>)
289
291
  : undefined;
290
292
 
291
293
  let configLabelKey: string = key;
292
294
 
293
- if (key in payload && typeof payload[key] === 'string') {
294
- configLabelKey = payload[key] as string;
295
+ if (key in typedPayload && typeof typedPayload[key] === 'string') {
296
+ configLabelKey = typedPayload[key] as string;
295
297
  } else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === 'string') {
296
298
  configLabelKey = payloadPayload[key] as string;
297
299
  }