@kubuild/ai 0.3.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.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-27AY2KBI.js +500 -0
  3. package/dist/chunk-27AY2KBI.js.map +1 -0
  4. package/dist/chunk-JY4NHD3Q.js +227 -0
  5. package/dist/chunk-JY4NHD3Q.js.map +1 -0
  6. package/dist/chunk-UH24LHRY.js +443 -0
  7. package/dist/chunk-UH24LHRY.js.map +1 -0
  8. package/dist/client/ai-client.d.ts +59 -0
  9. package/dist/client/ai-client.d.ts.map +1 -0
  10. package/dist/client/index.cjs +254 -0
  11. package/dist/client/index.cjs.map +1 -0
  12. package/dist/client/index.d.ts +2 -0
  13. package/dist/client/index.d.ts.map +1 -0
  14. package/dist/client/index.js +9 -0
  15. package/dist/client/index.js.map +1 -0
  16. package/dist/core/index.d.ts +3 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/normalizer.d.ts +9 -0
  19. package/dist/core/normalizer.d.ts.map +1 -0
  20. package/dist/core/prompt-compiler.d.ts +10 -0
  21. package/dist/core/prompt-compiler.d.ts.map +1 -0
  22. package/dist/index.cjs +468 -0
  23. package/dist/index.cjs.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +23 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/react/index.cjs +584 -0
  29. package/dist/react/index.cjs.map +1 -0
  30. package/dist/react/index.d.ts +3 -0
  31. package/dist/react/index.d.ts.map +1 -0
  32. package/dist/react/index.js +336 -0
  33. package/dist/react/index.js.map +1 -0
  34. package/dist/react/use-ai-chat.d.ts +63 -0
  35. package/dist/react/use-ai-chat.d.ts.map +1 -0
  36. package/dist/react/use-ai-generator.d.ts +19 -0
  37. package/dist/react/use-ai-generator.d.ts.map +1 -0
  38. package/dist/server/adapters/anthropic.d.ts +30 -0
  39. package/dist/server/adapters/anthropic.d.ts.map +1 -0
  40. package/dist/server/adapters/base.d.ts +2 -0
  41. package/dist/server/adapters/base.d.ts.map +1 -0
  42. package/dist/server/adapters/custom.d.ts +18 -0
  43. package/dist/server/adapters/custom.d.ts.map +1 -0
  44. package/dist/server/adapters/gemini.d.ts +22 -0
  45. package/dist/server/adapters/gemini.d.ts.map +1 -0
  46. package/dist/server/adapters/index.cjs +529 -0
  47. package/dist/server/adapters/index.cjs.map +1 -0
  48. package/dist/server/adapters/index.d.ts +6 -0
  49. package/dist/server/adapters/index.d.ts.map +1 -0
  50. package/dist/server/adapters/index.js +13 -0
  51. package/dist/server/adapters/index.js.map +1 -0
  52. package/dist/server/adapters/openai.d.ts +26 -0
  53. package/dist/server/adapters/openai.d.ts.map +1 -0
  54. package/dist/server/adapters/stream-utils.d.ts +12 -0
  55. package/dist/server/adapters/stream-utils.d.ts.map +1 -0
  56. package/dist/server/engine.d.ts +59 -0
  57. package/dist/server/engine.d.ts.map +1 -0
  58. package/dist/server/handler.d.ts +66 -0
  59. package/dist/server/handler.d.ts.map +1 -0
  60. package/dist/server/index.cjs +1824 -0
  61. package/dist/server/index.cjs.map +1 -0
  62. package/dist/server/index.d.ts +4 -0
  63. package/dist/server/index.d.ts.map +1 -0
  64. package/dist/server/index.js +890 -0
  65. package/dist/server/index.js.map +1 -0
  66. package/dist/types.d.ts +184 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/package.json +94 -0
@@ -0,0 +1,443 @@
1
+ // src/core/prompt-compiler.ts
2
+ function compileComponentCatalog(registry) {
3
+ if (!registry) return [];
4
+ const definitions = registry.list();
5
+ return definitions.map((def) => {
6
+ const props = [];
7
+ if (def.propFields && Array.isArray(def.propFields)) {
8
+ for (const field of def.propFields) {
9
+ props.push({
10
+ name: field.name,
11
+ type: field.type || "string",
12
+ defaultValue: field.defaultValue,
13
+ options: field.options?.map((o) => o.value),
14
+ description: field.description
15
+ });
16
+ }
17
+ }
18
+ return {
19
+ type: def.type,
20
+ label: def.label || def.type,
21
+ category: def.category || "custom",
22
+ description: def.description,
23
+ acceptsChildren: def.acceptsChildren ?? false,
24
+ allowedChildren: def.allowedChildren,
25
+ disallowedParents: def.disallowedParents,
26
+ defaultProps: def.defaultProps,
27
+ props: props.length > 0 ? props : void 0
28
+ };
29
+ });
30
+ }
31
+ function buildSystemPrompt(options) {
32
+ const { catalog, mode, prefix, stylePreference } = options;
33
+ const catalogSummary = catalog.map((c) => {
34
+ let desc = `- **${c.type}** (${c.category}): ${c.label}`;
35
+ if (c.description) desc += ` - ${c.description}`;
36
+ desc += ` | acceptsChildren: ${c.acceptsChildren}`;
37
+ if (c.allowedChildren && c.allowedChildren.length > 0) {
38
+ desc += ` | allowedChildren: [${c.allowedChildren.join(", ")}]`;
39
+ }
40
+ if (c.props && c.props.length > 0) {
41
+ const propList = c.props.map((p) => {
42
+ let pStr = `${p.name} (${p.type})`;
43
+ if (p.options) pStr += `[${p.options.map(String).join("|")}]`;
44
+ return pStr;
45
+ }).join(", ");
46
+ desc += ` | props: { ${propList} }`;
47
+ }
48
+ return desc;
49
+ }).join("\n");
50
+ let modeInstructions = "";
51
+ if (mode === "full-page") {
52
+ modeInstructions = `
53
+ You must generate a complete, valid KUBUILD PageDocument JSON with this exact structure:
54
+ {
55
+ "schema": "stora.page",
56
+ "version": "1.0.0",
57
+ "metadata": {
58
+ "title": "<Page Title>",
59
+ "description": "<Page Description>",
60
+ "tags": ["<tag1>", "<tag2>"],
61
+ "category": "<category>"
62
+ },
63
+ "document": {
64
+ "id": "root-page",
65
+ "type": "page",
66
+ "styles": {
67
+ "base": {
68
+ "backgroundColor": "#ffffff",
69
+ "fontFamily": "Inter, system-ui, sans-serif",
70
+ "color": "#111827",
71
+ "minHeight": "100vh"
72
+ }
73
+ },
74
+ "children": [
75
+ // Sections here...
76
+ ]
77
+ }
78
+ }
79
+ `;
80
+ } else if (mode === "section") {
81
+ modeInstructions = `
82
+ You must generate a single valid KUBUILD section Node JSON with this structure:
83
+ {
84
+ "id": "section_<unique_suffix>",
85
+ "type": "section",
86
+ "styles": {
87
+ "base": {
88
+ "paddingTop": "64px",
89
+ "paddingBottom": "64px",
90
+ "paddingLeft": "24px",
91
+ "paddingRight": "24px"
92
+ }
93
+ },
94
+ "children": [
95
+ // Container and child nodes...
96
+ ]
97
+ }
98
+ `;
99
+ } else if (mode === "refactor") {
100
+ modeInstructions = `
101
+ You must refactor the provided KUBUILD Node based on the user's instructions.
102
+ Return ONLY the updated Node JSON while maintaining structural integrity.
103
+ `;
104
+ }
105
+ const styleGuide = stylePreference ? `
106
+ User Style Preference: "${stylePreference}". Follow this visual aesthetic closely.` : "\nStyle with modern, clean, high-conversion design patterns (accessible contrast, harmonious spacing, beautiful typography, subtle shadows/borders).";
107
+ return `${prefix ? prefix + "\n\n" : ""}You are an expert web designer and KUBUILD architecture generator.
108
+ KUBUILD is a component-driven visual website builder. Your job is to output pure, valid JSON (and NOTHING ELSE) matching the KUBUILD schema and the registered component definitions.
109
+
110
+ ### RULES & CONSTRAINTS:
111
+ 1. Output MUST be valid JSON only. No markdown fences, no explanatory text, no HTML tags outside html-embed.
112
+ 2. Only use component types listed in the Component Catalog below. Do NOT invent new component types.
113
+ 3. Obey \`acceptsChildren\` and \`allowedChildren\`:
114
+ - Layout hierarchy: \`page\` -> \`section\` -> \`container\` or \`columns\` -> content components (\`heading\`, \`paragraph\`, \`button\`, \`image\`, \`form\`, etc.).
115
+ - Leaf components (e.g. \`button\`, \`input\`, \`heading\`, \`text\`, \`badge\`) must have \`acceptsChildren: false\` and empty or omitted \`children\`.
116
+ 4. Every node MUST have a unique string \`id\` (e.g. "hero-section", "hero-title", "cta-btn").
117
+ 5. Responsive & Interactive State Styling:
118
+ - Use the \`styles\` object with breakpoint keys: \`base\` (all viewports/desktop), and optionally \`tablet\` or \`mobile\`.
119
+ - In \`base\`, \`tablet\`, and \`mobile\`, values MUST be CSS primitives (strings or numbers, e.g. "backgroundColor": "#3b82f6"). NEVER put nested objects or ":hover" inside "base"!
120
+ - For hover, active, or interactive pseudo-classes, use \`styles.states\` with pseudo-class keys (e.g. \`":hover"\`), like:
121
+ "styles": {
122
+ "base": { "backgroundColor": "#3b82f6", "color": "#ffffff" },
123
+ "states": {
124
+ ":hover": { "backgroundColor": "#2563eb" }
125
+ }
126
+ }
127
+ 6. NEVER include dangerous scripts, \`javascript:\` URIs, or malicious payload attributes.
128
+ ${styleGuide}
129
+
130
+ ### OUTPUT SPECIFICATION:
131
+ ${modeInstructions}
132
+
133
+ ### REGISTERED COMPONENT CATALOG:
134
+ ${catalogSummary || "(Standard core components: page, section, container, columns, heading, paragraph, text, button, input, textarea, select, image, video, icon, badge, code-block)"}
135
+ `;
136
+ }
137
+ function buildJsonSchemaForMode(mode) {
138
+ const nodeSchema = {
139
+ type: "object",
140
+ required: ["id", "type"],
141
+ properties: {
142
+ id: { type: "string" },
143
+ type: { type: "string" },
144
+ props: { type: "object" },
145
+ styles: {
146
+ type: "object",
147
+ properties: {
148
+ base: { type: "object" },
149
+ tablet: { type: "object" },
150
+ mobile: { type: "object" },
151
+ states: { type: "object" }
152
+ }
153
+ },
154
+ children: {
155
+ type: "array",
156
+ items: { $ref: "#" }
157
+ }
158
+ }
159
+ };
160
+ if (mode === "full-page") {
161
+ return {
162
+ type: "object",
163
+ required: ["schema", "version", "document"],
164
+ properties: {
165
+ schema: { type: "string", const: "stora.page" },
166
+ version: { type: "string", const: "1.0.0" },
167
+ metadata: {
168
+ type: "object",
169
+ properties: {
170
+ title: { type: "string" },
171
+ description: { type: "string" },
172
+ tags: { type: "array", items: { type: "string" } },
173
+ category: { type: "string" }
174
+ }
175
+ },
176
+ document: nodeSchema
177
+ }
178
+ };
179
+ }
180
+ return nodeSchema;
181
+ }
182
+
183
+ // src/core/normalizer.ts
184
+ import {
185
+ PageDocumentSchema,
186
+ DocumentMetadataSchema,
187
+ NodeSchema,
188
+ CURRENT_SCHEMA_VERSION,
189
+ SCHEMA_NAME
190
+ } from "@kubuild/schema";
191
+ import {
192
+ validateDocument,
193
+ validateDocumentSecurity
194
+ } from "@kubuild/core";
195
+ function extractJsonFromResponse(raw) {
196
+ let cleaned = raw.trim();
197
+ if (cleaned.startsWith("```")) {
198
+ const firstNewline = cleaned.indexOf("\n");
199
+ if (firstNewline !== -1) {
200
+ cleaned = cleaned.slice(firstNewline + 1);
201
+ }
202
+ if (cleaned.endsWith("```")) {
203
+ cleaned = cleaned.slice(0, cleaned.length - 3).trim();
204
+ }
205
+ }
206
+ const firstBrace = cleaned.indexOf("{");
207
+ const lastBrace = cleaned.lastIndexOf("}");
208
+ if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
209
+ cleaned = cleaned.slice(firstBrace, lastBrace + 1);
210
+ }
211
+ try {
212
+ return JSON.parse(cleaned);
213
+ } catch (err) {
214
+ const msg = err instanceof Error ? err.message : String(err);
215
+ throw new Error(`Failed to parse AI response as JSON: ${msg}. Response was: ${raw.slice(0, 200)}...`);
216
+ }
217
+ }
218
+ function normalizeStyles(rawStyles) {
219
+ if (!rawStyles || typeof rawStyles !== "object" || Array.isArray(rawStyles)) {
220
+ return void 0;
221
+ }
222
+ const raw = rawStyles;
223
+ const result = {};
224
+ const states = {};
225
+ if (raw.states && typeof raw.states === "object" && !Array.isArray(raw.states)) {
226
+ for (const [stateKey, stateVal] of Object.entries(raw.states)) {
227
+ if (stateVal && typeof stateVal === "object" && !Array.isArray(stateVal)) {
228
+ states[stateKey] = { ...stateVal };
229
+ }
230
+ }
231
+ }
232
+ const knownBreakpoints = ["base", "desktop", "tablet", "mobile"];
233
+ const hasBreakpoint = Object.keys(raw).some((k) => knownBreakpoints.includes(k));
234
+ if (!hasBreakpoint) {
235
+ const baseStyles = {};
236
+ for (const [key, value] of Object.entries(raw)) {
237
+ if (key === "states") continue;
238
+ if (key.startsWith(":") || key === "hover" || key === "focus" || key === "active") {
239
+ const stateKey = key.startsWith(":") ? key : `:${key}`;
240
+ if (value && typeof value === "object" && !Array.isArray(value)) {
241
+ states[stateKey] = { ...states[stateKey] || {}, ...value };
242
+ }
243
+ } else if (typeof value !== "object" || value === null) {
244
+ baseStyles[key] = value;
245
+ }
246
+ }
247
+ if (Object.keys(baseStyles).length > 0) {
248
+ result.base = baseStyles;
249
+ }
250
+ } else {
251
+ for (const bp of knownBreakpoints) {
252
+ const bpVal = raw[bp];
253
+ if (bpVal && typeof bpVal === "object" && !Array.isArray(bpVal)) {
254
+ const cleanBp = {};
255
+ for (const [key, value] of Object.entries(bpVal)) {
256
+ if (key.startsWith(":") || key === "hover" || key === "focus" || key === "active") {
257
+ const stateKey = key.startsWith(":") ? key : `:${key}`;
258
+ if (value && typeof value === "object" && !Array.isArray(value)) {
259
+ states[stateKey] = { ...states[stateKey] || {}, ...value };
260
+ }
261
+ } else if (typeof value !== "object" || value === null) {
262
+ cleanBp[key] = value;
263
+ }
264
+ }
265
+ if (Object.keys(cleanBp).length > 0) {
266
+ result[bp] = cleanBp;
267
+ }
268
+ }
269
+ }
270
+ for (const [key, value] of Object.entries(raw)) {
271
+ if (knownBreakpoints.includes(key) || key === "states") continue;
272
+ if (key.startsWith(":") || key === "hover" || key === "focus" || key === "active") {
273
+ const stateKey = key.startsWith(":") ? key : `:${key}`;
274
+ if (value && typeof value === "object" && !Array.isArray(value)) {
275
+ states[stateKey] = { ...states[stateKey] || {}, ...value };
276
+ }
277
+ }
278
+ }
279
+ }
280
+ const cleanStates = {};
281
+ for (const [stateKey, stateDef] of Object.entries(states)) {
282
+ const cleanDef = {};
283
+ for (const [propKey, propVal] of Object.entries(stateDef)) {
284
+ if (typeof propVal !== "object" || propVal === null) {
285
+ cleanDef[propKey] = propVal;
286
+ }
287
+ }
288
+ if (Object.keys(cleanDef).length > 0) {
289
+ cleanStates[stateKey] = cleanDef;
290
+ }
291
+ }
292
+ if (Object.keys(cleanStates).length > 0) {
293
+ result.states = cleanStates;
294
+ }
295
+ return Object.keys(result).length > 0 ? result : void 0;
296
+ }
297
+ function normalizeNodeTree(node, usedIds = /* @__PURE__ */ new Set(), depth = 0) {
298
+ if (!node || typeof node !== "object") {
299
+ throw new Error(`Invalid node at depth ${depth}: must be an object`);
300
+ }
301
+ const raw = node;
302
+ const type = typeof raw.type === "string" && raw.type.trim() ? raw.type.trim() : "container";
303
+ let id = typeof raw.id === "string" && raw.id.trim() ? raw.id.trim() : "";
304
+ if (!id || usedIds.has(id)) {
305
+ let counter = 1;
306
+ let candidate = `${type}-${counter}`;
307
+ while (usedIds.has(candidate)) {
308
+ counter++;
309
+ candidate = `${type}-${counter}`;
310
+ }
311
+ id = candidate;
312
+ }
313
+ usedIds.add(id);
314
+ const props = raw.props && typeof raw.props === "object" && !Array.isArray(raw.props) ? { ...raw.props } : {};
315
+ if (type === "heading" && typeof props.level === "string") {
316
+ const parsedLevel = parseInt(props.level, 10);
317
+ if (!isNaN(parsedLevel) && parsedLevel >= 1 && parsedLevel <= 6) {
318
+ props.level = parsedLevel;
319
+ }
320
+ }
321
+ const styles = normalizeStyles(raw.styles);
322
+ let children = void 0;
323
+ if (Array.isArray(raw.children)) {
324
+ children = raw.children.filter((c) => c && typeof c === "object").map((c) => normalizeNodeTree(c, usedIds, depth + 1));
325
+ }
326
+ return {
327
+ id,
328
+ type,
329
+ props: Object.keys(props).length > 0 ? props : void 0,
330
+ styles,
331
+ children
332
+ };
333
+ }
334
+ function normalizeAndValidatePageDocument(rawJson, securityLimits) {
335
+ if (!rawJson || typeof rawJson !== "object") {
336
+ throw new Error("AI output must be a JSON object");
337
+ }
338
+ const obj = rawJson;
339
+ let docObject;
340
+ if (obj.type === "page" && !obj.document) {
341
+ docObject = {
342
+ schema: SCHEMA_NAME,
343
+ version: CURRENT_SCHEMA_VERSION,
344
+ metadata: {
345
+ title: typeof obj.props === "object" && obj.props !== null && obj.props.title || "AI Generated Page",
346
+ description: "Generated by KUBUILD AI"
347
+ },
348
+ document: obj
349
+ };
350
+ } else {
351
+ docObject = {
352
+ schema: SCHEMA_NAME,
353
+ version: typeof obj.version === "string" ? obj.version : CURRENT_SCHEMA_VERSION,
354
+ metadata: typeof obj.metadata === "object" && obj.metadata !== null ? obj.metadata : { title: "AI Generated Page", description: "Generated by KUBUILD AI" },
355
+ document: obj.document || obj
356
+ };
357
+ }
358
+ const usedIds = /* @__PURE__ */ new Set();
359
+ const normalizedRoot = normalizeNodeTree(docObject.document, usedIds);
360
+ if (normalizedRoot.type !== "page") {
361
+ normalizedRoot.type = "page";
362
+ }
363
+ const parsedMetadata = DocumentMetadataSchema.parse({
364
+ title: "AI Generated Page",
365
+ description: "Generated by KUBUILD AI",
366
+ author: "KUBUILD AI",
367
+ tags: ["ai-generated"],
368
+ category: "general",
369
+ version: "1.0.0",
370
+ ...typeof docObject.metadata === "object" && docObject.metadata !== null ? docObject.metadata : {}
371
+ });
372
+ const finalDocument = {
373
+ schema: SCHEMA_NAME,
374
+ version: CURRENT_SCHEMA_VERSION,
375
+ metadata: parsedMetadata,
376
+ document: normalizedRoot
377
+ };
378
+ const parsed = PageDocumentSchema.safeParse(finalDocument);
379
+ if (!parsed.success) {
380
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
381
+ throw new Error(`Document schema validation failed: ${issues}`);
382
+ }
383
+ const validationResult = validateDocument(finalDocument, { securityLimits });
384
+ if (!validationResult.valid) {
385
+ const errorMsgs = validationResult.errors.map((e) => `${e.code}: ${e.message} (${e.path})`).join("; ");
386
+ throw new Error(`Document validation failed: ${errorMsgs}`);
387
+ }
388
+ return parsed.data;
389
+ }
390
+ function normalizeAndValidateSectionNode(rawJson, securityLimits) {
391
+ if (!rawJson || typeof rawJson !== "object") {
392
+ throw new Error("AI output must be a JSON object");
393
+ }
394
+ const usedIds = /* @__PURE__ */ new Set();
395
+ const normalized = normalizeNodeTree(rawJson, usedIds);
396
+ if (normalized.type !== "section") {
397
+ normalized.type = "section";
398
+ }
399
+ const parsed = NodeSchema.safeParse(normalized);
400
+ if (!parsed.success) {
401
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
402
+ throw new Error(`Section node schema validation failed: ${issues}`);
403
+ }
404
+ const secCheck = validateDocumentSecurity({ document: normalized }, securityLimits);
405
+ if (!secCheck.safe) {
406
+ const issues = secCheck.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
407
+ throw new Error(`Section security check failed: ${issues}`);
408
+ }
409
+ return parsed.data;
410
+ }
411
+ function normalizeAndValidateRefactoredNode(rawJson, originalNode, securityLimits) {
412
+ if (!rawJson || typeof rawJson !== "object") {
413
+ throw new Error("AI output must be a JSON object");
414
+ }
415
+ const usedIds = /* @__PURE__ */ new Set();
416
+ const normalized = normalizeNodeTree(rawJson, usedIds);
417
+ normalized.id = originalNode.id;
418
+ normalized.type = originalNode.type;
419
+ const parsed = NodeSchema.safeParse(normalized);
420
+ if (!parsed.success) {
421
+ const issues = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
422
+ throw new Error(`Refactored node schema validation failed: ${issues}`);
423
+ }
424
+ const secCheck = validateDocumentSecurity({ document: normalized }, securityLimits);
425
+ if (!secCheck.safe) {
426
+ const issues = secCheck.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
427
+ throw new Error(`Refactored node security check failed: ${issues}`);
428
+ }
429
+ return parsed.data;
430
+ }
431
+
432
+ export {
433
+ compileComponentCatalog,
434
+ buildSystemPrompt,
435
+ buildJsonSchemaForMode,
436
+ extractJsonFromResponse,
437
+ normalizeStyles,
438
+ normalizeNodeTree,
439
+ normalizeAndValidatePageDocument,
440
+ normalizeAndValidateSectionNode,
441
+ normalizeAndValidateRefactoredNode
442
+ };
443
+ //# sourceMappingURL=chunk-UH24LHRY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/prompt-compiler.ts","../src/core/normalizer.ts"],"sourcesContent":["import type {\n AiCompiledComponentSpec,\n AiCompiledComponentProp,\n ComponentRegistryLike,\n ComponentDefinitionLike,\n AiGenerationMode,\n} from '../types';\n\nexport function compileComponentCatalog(\n registry?: ComponentRegistryLike,\n): AiCompiledComponentSpec[] {\n if (!registry) return [];\n\n const definitions = registry.list();\n return definitions.map((def: ComponentDefinitionLike) => {\n const props: AiCompiledComponentProp[] = [];\n\n if (def.propFields && Array.isArray(def.propFields)) {\n for (const field of def.propFields) {\n props.push({\n name: field.name,\n type: field.type || 'string',\n defaultValue: field.defaultValue,\n options: field.options?.map((o) => o.value),\n description: field.description,\n });\n }\n }\n\n return {\n type: def.type,\n label: def.label || def.type,\n category: def.category || 'custom',\n description: def.description,\n acceptsChildren: def.acceptsChildren ?? false,\n allowedChildren: def.allowedChildren,\n disallowedParents: def.disallowedParents,\n defaultProps: def.defaultProps,\n props: props.length > 0 ? props : undefined,\n };\n });\n}\n\nexport function buildSystemPrompt(options: {\n catalog: AiCompiledComponentSpec[];\n mode: AiGenerationMode;\n prefix?: string;\n stylePreference?: string;\n}): string {\n const { catalog, mode, prefix, stylePreference } = options;\n\n const catalogSummary = catalog\n .map((c) => {\n let desc = `- **${c.type}** (${c.category}): ${c.label}`;\n if (c.description) desc += ` - ${c.description}`;\n desc += ` | acceptsChildren: ${c.acceptsChildren}`;\n if (c.allowedChildren && c.allowedChildren.length > 0) {\n desc += ` | allowedChildren: [${c.allowedChildren.join(', ')}]`;\n }\n if (c.props && c.props.length > 0) {\n const propList = c.props\n .map((p) => {\n let pStr = `${p.name} (${p.type})`;\n if (p.options) pStr += `[${p.options.map(String).join('|')}]`;\n return pStr;\n })\n .join(', ');\n desc += ` | props: { ${propList} }`;\n }\n return desc;\n })\n .join('\\n');\n\n let modeInstructions = '';\n if (mode === 'full-page') {\n modeInstructions = `\nYou must generate a complete, valid KUBUILD PageDocument JSON with this exact structure:\n{\n \"schema\": \"stora.page\",\n \"version\": \"1.0.0\",\n \"metadata\": {\n \"title\": \"<Page Title>\",\n \"description\": \"<Page Description>\",\n \"tags\": [\"<tag1>\", \"<tag2>\"],\n \"category\": \"<category>\"\n },\n \"document\": {\n \"id\": \"root-page\",\n \"type\": \"page\",\n \"styles\": {\n \"base\": {\n \"backgroundColor\": \"#ffffff\",\n \"fontFamily\": \"Inter, system-ui, sans-serif\",\n \"color\": \"#111827\",\n \"minHeight\": \"100vh\"\n }\n },\n \"children\": [\n // Sections here...\n ]\n }\n}\n`;\n } else if (mode === 'section') {\n modeInstructions = `\nYou must generate a single valid KUBUILD section Node JSON with this structure:\n{\n \"id\": \"section_<unique_suffix>\",\n \"type\": \"section\",\n \"styles\": {\n \"base\": {\n \"paddingTop\": \"64px\",\n \"paddingBottom\": \"64px\",\n \"paddingLeft\": \"24px\",\n \"paddingRight\": \"24px\"\n }\n },\n \"children\": [\n // Container and child nodes...\n ]\n}\n`;\n } else if (mode === 'refactor') {\n modeInstructions = `\nYou must refactor the provided KUBUILD Node based on the user's instructions.\nReturn ONLY the updated Node JSON while maintaining structural integrity.\n`;\n }\n\n const styleGuide = stylePreference\n ? `\\nUser Style Preference: \"${stylePreference}\". Follow this visual aesthetic closely.`\n : '\\nStyle with modern, clean, high-conversion design patterns (accessible contrast, harmonious spacing, beautiful typography, subtle shadows/borders).';\n\n return `${prefix ? prefix + '\\n\\n' : ''}You are an expert web designer and KUBUILD architecture generator.\nKUBUILD is a component-driven visual website builder. Your job is to output pure, valid JSON (and NOTHING ELSE) matching the KUBUILD schema and the registered component definitions.\n\n### RULES & CONSTRAINTS:\n1. Output MUST be valid JSON only. No markdown fences, no explanatory text, no HTML tags outside html-embed.\n2. Only use component types listed in the Component Catalog below. Do NOT invent new component types.\n3. Obey \\`acceptsChildren\\` and \\`allowedChildren\\`:\n - Layout hierarchy: \\`page\\` -> \\`section\\` -> \\`container\\` or \\`columns\\` -> content components (\\`heading\\`, \\`paragraph\\`, \\`button\\`, \\`image\\`, \\`form\\`, etc.).\n - Leaf components (e.g. \\`button\\`, \\`input\\`, \\`heading\\`, \\`text\\`, \\`badge\\`) must have \\`acceptsChildren: false\\` and empty or omitted \\`children\\`.\n4. Every node MUST have a unique string \\`id\\` (e.g. \"hero-section\", \"hero-title\", \"cta-btn\").\n5. Responsive & Interactive State Styling:\n - Use the \\`styles\\` object with breakpoint keys: \\`base\\` (all viewports/desktop), and optionally \\`tablet\\` or \\`mobile\\`.\n - In \\`base\\`, \\`tablet\\`, and \\`mobile\\`, values MUST be CSS primitives (strings or numbers, e.g. \"backgroundColor\": \"#3b82f6\"). NEVER put nested objects or \":hover\" inside \"base\"!\n - For hover, active, or interactive pseudo-classes, use \\`styles.states\\` with pseudo-class keys (e.g. \\`\":hover\"\\`), like:\n \"styles\": {\n \"base\": { \"backgroundColor\": \"#3b82f6\", \"color\": \"#ffffff\" },\n \"states\": {\n \":hover\": { \"backgroundColor\": \"#2563eb\" }\n }\n }\n6. NEVER include dangerous scripts, \\`javascript:\\` URIs, or malicious payload attributes.\n${styleGuide}\n\n### OUTPUT SPECIFICATION:\n${modeInstructions}\n\n### REGISTERED COMPONENT CATALOG:\n${catalogSummary || '(Standard core components: page, section, container, columns, heading, paragraph, text, button, input, textarea, select, image, video, icon, badge, code-block)'}\n`;\n}\n\nexport function buildJsonSchemaForMode(mode: AiGenerationMode): Record<string, unknown> {\n const nodeSchema: Record<string, unknown> = {\n type: 'object',\n required: ['id', 'type'],\n properties: {\n id: { type: 'string' },\n type: { type: 'string' },\n props: { type: 'object' },\n styles: {\n type: 'object',\n properties: {\n base: { type: 'object' },\n tablet: { type: 'object' },\n mobile: { type: 'object' },\n states: { type: 'object' },\n },\n },\n children: {\n type: 'array',\n items: { $ref: '#' },\n },\n },\n };\n\n if (mode === 'full-page') {\n return {\n type: 'object',\n required: ['schema', 'version', 'document'],\n properties: {\n schema: { type: 'string', const: 'stora.page' },\n version: { type: 'string', const: '1.0.0' },\n metadata: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n category: { type: 'string' },\n },\n },\n document: nodeSchema,\n },\n };\n }\n\n return nodeSchema;\n}\n","import {\n PageDocument,\n PageDocumentSchema,\n DocumentMetadata,\n DocumentMetadataSchema,\n Node,\n NodeSchema,\n CURRENT_SCHEMA_VERSION,\n SCHEMA_NAME,\n} from '@kubuild/schema';\nimport {\n validateDocument,\n validateDocumentSecurity,\n DocumentSecurityLimits,\n} from '@kubuild/core';\n\nexport function extractJsonFromResponse(raw: string): unknown {\n let cleaned = raw.trim();\n // Strip Markdown code blocks if present (```json ... ``` or ``` ...)\n if (cleaned.startsWith('```')) {\n const firstNewline = cleaned.indexOf('\\n');\n if (firstNewline !== -1) {\n cleaned = cleaned.slice(firstNewline + 1);\n }\n if (cleaned.endsWith('```')) {\n cleaned = cleaned.slice(0, cleaned.length - 3).trim();\n }\n }\n\n // Find the outermost JSON object bounds if there is extraneous text\n const firstBrace = cleaned.indexOf('{');\n const lastBrace = cleaned.lastIndexOf('}');\n if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {\n cleaned = cleaned.slice(firstBrace, lastBrace + 1);\n }\n\n try {\n return JSON.parse(cleaned);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to parse AI response as JSON: ${msg}. Response was: ${raw.slice(0, 200)}...`);\n }\n}\n\nexport function normalizeStyles(rawStyles: unknown): Node['styles'] {\n if (!rawStyles || typeof rawStyles !== 'object' || Array.isArray(rawStyles)) {\n return undefined;\n }\n\n const raw = rawStyles as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n const states: Record<string, Record<string, unknown>> = {};\n\n // Existing states\n if (raw.states && typeof raw.states === 'object' && !Array.isArray(raw.states)) {\n for (const [stateKey, stateVal] of Object.entries(raw.states as Record<string, unknown>)) {\n if (stateVal && typeof stateVal === 'object' && !Array.isArray(stateVal)) {\n states[stateKey] = { ...(stateVal as Record<string, unknown>) };\n }\n }\n }\n\n const knownBreakpoints = ['base', 'desktop', 'tablet', 'mobile'];\n const hasBreakpoint = Object.keys(raw).some((k) => knownBreakpoints.includes(k));\n\n if (!hasBreakpoint) {\n // If AI output flat CSS properties without 'base' wrapper\n const baseStyles: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (key === 'states') continue;\n if (key.startsWith(':') || key === 'hover' || key === 'focus' || key === 'active') {\n const stateKey = key.startsWith(':') ? key : `:${key}`;\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n states[stateKey] = { ...(states[stateKey] || {}), ...(value as Record<string, unknown>) };\n }\n } else if (typeof value !== 'object' || value === null) {\n baseStyles[key] = value;\n }\n }\n if (Object.keys(baseStyles).length > 0) {\n result.base = baseStyles;\n }\n } else {\n for (const bp of knownBreakpoints) {\n const bpVal = raw[bp];\n if (bpVal && typeof bpVal === 'object' && !Array.isArray(bpVal)) {\n const cleanBp: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(bpVal as Record<string, unknown>)) {\n if (key.startsWith(':') || key === 'hover' || key === 'focus' || key === 'active') {\n const stateKey = key.startsWith(':') ? key : `:${key}`;\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n states[stateKey] = { ...(states[stateKey] || {}), ...(value as Record<string, unknown>) };\n }\n } else if (typeof value !== 'object' || value === null) {\n cleanBp[key] = value;\n }\n }\n if (Object.keys(cleanBp).length > 0) {\n result[bp] = cleanBp;\n }\n }\n }\n\n // Also extract any pseudo-classes at top level\n for (const [key, value] of Object.entries(raw)) {\n if (knownBreakpoints.includes(key) || key === 'states') continue;\n if (key.startsWith(':') || key === 'hover' || key === 'focus' || key === 'active') {\n const stateKey = key.startsWith(':') ? key : `:${key}`;\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n states[stateKey] = { ...(states[stateKey] || {}), ...(value as Record<string, unknown>) };\n }\n }\n }\n }\n\n // Clean and sanitize states: each state can only have primitives\n const cleanStates: Record<string, Record<string, unknown>> = {};\n for (const [stateKey, stateDef] of Object.entries(states)) {\n const cleanDef: Record<string, unknown> = {};\n for (const [propKey, propVal] of Object.entries(stateDef)) {\n if (typeof propVal !== 'object' || propVal === null) {\n cleanDef[propKey] = propVal;\n }\n }\n if (Object.keys(cleanDef).length > 0) {\n cleanStates[stateKey] = cleanDef;\n }\n }\n\n if (Object.keys(cleanStates).length > 0) {\n result.states = cleanStates;\n }\n\n return Object.keys(result).length > 0 ? (result as Node['styles']) : undefined;\n}\n\nexport function normalizeNodeTree(\n node: unknown,\n usedIds: Set<string> = new Set(),\n depth = 0,\n): Node {\n if (!node || typeof node !== 'object') {\n throw new Error(`Invalid node at depth ${depth}: must be an object`);\n }\n\n const raw = node as Record<string, unknown>;\n const type = typeof raw.type === 'string' && raw.type.trim() ? raw.type.trim() : 'container';\n\n // Ensure deterministic, unique ID\n let id = typeof raw.id === 'string' && raw.id.trim() ? raw.id.trim() : '';\n if (!id || usedIds.has(id)) {\n let counter = 1;\n let candidate = `${type}-${counter}`;\n while (usedIds.has(candidate)) {\n counter++;\n candidate = `${type}-${counter}`;\n }\n id = candidate;\n }\n usedIds.add(id);\n\n // Normalize props\n const props =\n raw.props && typeof raw.props === 'object' && !Array.isArray(raw.props)\n ? { ...(raw.props as Record<string, unknown>) }\n : {};\n\n // Fix common LLM prop quirks:\n // e.g. heading level passed as string \"1\" instead of number 1\n if (type === 'heading' && typeof props.level === 'string') {\n const parsedLevel = parseInt(props.level, 10);\n if (!isNaN(parsedLevel) && parsedLevel >= 1 && parsedLevel <= 6) {\n props.level = parsedLevel;\n }\n }\n\n // Normalize styles\n const styles = normalizeStyles(raw.styles);\n\n // Normalize children recursively\n let children: Node[] | undefined = undefined;\n if (Array.isArray(raw.children)) {\n children = raw.children\n .filter((c) => c && typeof c === 'object')\n .map((c) => normalizeNodeTree(c, usedIds, depth + 1));\n }\n\n return {\n id,\n type,\n props: Object.keys(props).length > 0 ? props : undefined,\n styles,\n children,\n };\n}\n\nexport function normalizeAndValidatePageDocument(\n rawJson: unknown,\n securityLimits?: DocumentSecurityLimits,\n): PageDocument {\n if (!rawJson || typeof rawJson !== 'object') {\n throw new Error('AI output must be a JSON object');\n }\n\n const obj = rawJson as Record<string, unknown>;\n\n // Case 1: AI returned directly a page node instead of PageDocument\n let docObject: Record<string, unknown>;\n if (obj.type === 'page' && !obj.document) {\n docObject = {\n schema: SCHEMA_NAME,\n version: CURRENT_SCHEMA_VERSION,\n metadata: {\n title: (typeof obj.props === 'object' && obj.props !== null && (obj.props as Record<string, unknown>).title) || 'AI Generated Page',\n description: 'Generated by KUBUILD AI',\n },\n document: obj,\n };\n } else {\n docObject = {\n schema: SCHEMA_NAME,\n version: typeof obj.version === 'string' ? obj.version : CURRENT_SCHEMA_VERSION,\n metadata: typeof obj.metadata === 'object' && obj.metadata !== null\n ? obj.metadata\n : { title: 'AI Generated Page', description: 'Generated by KUBUILD AI' },\n document: obj.document || obj,\n };\n }\n\n // Normalize the node tree and ensure IDs\n const usedIds = new Set<string>();\n const normalizedRoot = normalizeNodeTree(docObject.document, usedIds);\n\n if (normalizedRoot.type !== 'page') {\n normalizedRoot.type = 'page';\n }\n\n const parsedMetadata = DocumentMetadataSchema.parse({\n title: 'AI Generated Page',\n description: 'Generated by KUBUILD AI',\n author: 'KUBUILD AI',\n tags: ['ai-generated'],\n category: 'general',\n version: '1.0.0',\n ...(typeof docObject.metadata === 'object' && docObject.metadata !== null\n ? (docObject.metadata as Record<string, unknown>)\n : {}),\n });\n\n const finalDocument: PageDocument = {\n schema: SCHEMA_NAME,\n version: CURRENT_SCHEMA_VERSION,\n metadata: parsedMetadata,\n document: normalizedRoot as PageDocument['document'],\n };\n\n // 1. Zod Schema parse\n const parsed = PageDocumentSchema.safeParse(finalDocument);\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');\n throw new Error(`Document schema validation failed: ${issues}`);\n }\n\n // 2. Core document and security validation\n const validationResult = validateDocument(finalDocument, { securityLimits });\n if (!validationResult.valid) {\n const errorMsgs = validationResult.errors.map((e) => `${e.code}: ${e.message} (${e.path})`).join('; ');\n throw new Error(`Document validation failed: ${errorMsgs}`);\n }\n\n return parsed.data;\n}\n\nexport function normalizeAndValidateSectionNode(\n rawJson: unknown,\n securityLimits?: DocumentSecurityLimits,\n): Node {\n if (!rawJson || typeof rawJson !== 'object') {\n throw new Error('AI output must be a JSON object');\n }\n\n const usedIds = new Set<string>();\n const normalized = normalizeNodeTree(rawJson, usedIds);\n\n if (normalized.type !== 'section') {\n // If AI wrapped it or returned another root, enforce section\n normalized.type = 'section';\n }\n\n const parsed = NodeSchema.safeParse(normalized);\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');\n throw new Error(`Section node schema validation failed: ${issues}`);\n }\n\n // Security check\n const secCheck = validateDocumentSecurity({ document: normalized }, securityLimits);\n if (!secCheck.safe) {\n const issues = secCheck.errors.map((e) => `${e.code}: ${e.message}`).join('; ');\n throw new Error(`Section security check failed: ${issues}`);\n }\n\n return parsed.data;\n}\n\nexport function normalizeAndValidateRefactoredNode(\n rawJson: unknown,\n originalNode: Node,\n securityLimits?: DocumentSecurityLimits,\n): Node {\n if (!rawJson || typeof rawJson !== 'object') {\n throw new Error('AI output must be a JSON object');\n }\n\n const usedIds = new Set<string>();\n const normalized = normalizeNodeTree(rawJson, usedIds);\n\n // Preserve original ID and type if AI changed them accidentally\n normalized.id = originalNode.id;\n normalized.type = originalNode.type;\n\n const parsed = NodeSchema.safeParse(normalized);\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');\n throw new Error(`Refactored node schema validation failed: ${issues}`);\n }\n\n const secCheck = validateDocumentSecurity({ document: normalized }, securityLimits);\n if (!secCheck.safe) {\n const issues = secCheck.errors.map((e) => `${e.code}: ${e.message}`).join('; ');\n throw new Error(`Refactored node security check failed: ${issues}`);\n }\n\n return parsed.data;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,59 @@
1
+ import type { PageDocument, Node } from '@kubuild/schema';
2
+ import type { AiGeneratePageRequest, AiGenerateSectionRequest, AiRefactorNodeRequest, AiChatRequest, AiChatResponse, AiChatMessage, AiStreamCallbacks } from '../types';
3
+ export interface AiClientOptions {
4
+ endpoint: string;
5
+ headers?: Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);
6
+ fetch?: typeof fetch;
7
+ }
8
+ export declare class KubuildAiClient {
9
+ private endpoint;
10
+ private headers?;
11
+ private fetchFn;
12
+ constructor(options: AiClientOptions);
13
+ private resolveHeaders;
14
+ private sendRequest;
15
+ /**
16
+ * Standard single-pass full page generator (non-streaming).
17
+ */
18
+ generatePage(params: AiGeneratePageRequest, options?: {
19
+ signal?: AbortSignal;
20
+ }): Promise<PageDocument>;
21
+ /**
22
+ * Low-level SSE frame consumer shared by every streaming method on this client
23
+ * (`streamPage`, `chatStream`) — one transport implementation, reused rather than
24
+ * duplicated per stream "flavor" (STORA-515).
25
+ *
26
+ * Reads `res.body`, decodes `data: <json>\n\n` frames into `AiStreamEvent`s, and
27
+ * invokes `onEvent` for each one in arrival order. If `onEvent` throws (the
28
+ * conventional way callers signal a fatal `error` event), the throw propagates out of
29
+ * this method after the reader lock is released.
30
+ */
31
+ private consumeSse;
32
+ /**
33
+ * Progressive section streamer (SSE).
34
+ * Calls callbacks on each event (status, metadata, section, complete).
35
+ */
36
+ streamPage(params: AiGeneratePageRequest, callbacks?: AiStreamCallbacks, options?: {
37
+ signal?: AbortSignal;
38
+ }): Promise<PageDocument>;
39
+ /**
40
+ * Token-level streaming chat (STORA-515). Calls `onChatChunk` for every partial chunk
41
+ * as it arrives and resolves with the fully assembled assistant `AiChatMessage` once
42
+ * the stream's terminal `chat-complete` event is received. Reuses the exact same SSE
43
+ * transport as `streamPage` via `consumeSse` — no separate parsing path.
44
+ */
45
+ chatStream(params: AiChatRequest, callbacks?: Pick<AiStreamCallbacks, 'onChatChunk' | 'onChatComplete' | 'onError'>, options?: {
46
+ signal?: AbortSignal;
47
+ }): Promise<AiChatMessage>;
48
+ generateSection(params: AiGenerateSectionRequest, options?: {
49
+ signal?: AbortSignal;
50
+ }): Promise<Node>;
51
+ refactorNode(params: AiRefactorNodeRequest, options?: {
52
+ signal?: AbortSignal;
53
+ }): Promise<Node>;
54
+ chat(params: AiChatRequest, options?: {
55
+ signal?: AbortSignal;
56
+ }): Promise<AiChatResponse>;
57
+ }
58
+ export declare function createAiClient(options: AiClientOptions): KubuildAiClient;
59
+ //# sourceMappingURL=ai-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-client.d.ts","sourceRoot":"","sources":["../../src/client/ai-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,aAAa,EAEb,iBAAiB,EAElB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAA6B;IAC7C,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,eAAe;YAStB,cAAc;YAQd,WAAW;IA6BzB;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,YAAY,CAAC;IAUxB;;;;;;;;;OASG;YACW,UAAU;IA0CxB;;;OAGG;IACG,UAAU,CACd,MAAM,EAAE,qBAAqB,EAC7B,SAAS,CAAC,EAAE,iBAAiB,EAC7B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,YAAY,CAAC;IAmDxB;;;;;OAKG;IACG,UAAU,CACd,MAAM,EAAE,aAAa,EACrB,SAAS,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAAC,EACjF,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,aAAa,CAAC;IA+CnB,eAAe,CACnB,MAAM,EAAE,wBAAwB,EAChC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,IAAI,CAAC;IAUV,YAAY,CAChB,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,IAAI,CAAC;IAUV,IAAI,CACR,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,cAAc,CAAC;CAS3B;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe,CAExE"}