@meissa_a/meissa 0.1.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 (65) hide show
  1. package/README.md +350 -0
  2. package/dist/apps/app-generator.d.ts +30 -0
  3. package/dist/apps/index.d.ts +25 -0
  4. package/dist/apps/postmessage.d.ts +24 -0
  5. package/dist/apps/template.d.ts +10 -0
  6. package/dist/apps/types.d.ts +107 -0
  7. package/dist/apps.cjs +687 -0
  8. package/dist/apps.js +645 -0
  9. package/dist/client/component.d.ts +17 -0
  10. package/dist/client/content.d.ts +12 -0
  11. package/dist/client/index.d.ts +7 -0
  12. package/dist/client/patch.d.ts +6 -0
  13. package/dist/client/renderer.d.ts +43 -0
  14. package/dist/client/types.d.ts +52 -0
  15. package/dist/client.cjs +3558 -0
  16. package/dist/client.js +3524 -0
  17. package/dist/renderer/ComponentRenderer.d.ts +11 -0
  18. package/dist/renderer/MeissaRenderer.d.ts +8 -0
  19. package/dist/renderer/components/Alert.d.ts +2 -0
  20. package/dist/renderer/components/Badge.d.ts +2 -0
  21. package/dist/renderer/components/Btn.d.ts +2 -0
  22. package/dist/renderer/components/Card.d.ts +2 -0
  23. package/dist/renderer/components/Chart.d.ts +2 -0
  24. package/dist/renderer/components/Code.d.ts +2 -0
  25. package/dist/renderer/components/Col.d.ts +2 -0
  26. package/dist/renderer/components/Divider.d.ts +2 -0
  27. package/dist/renderer/components/Form.d.ts +2 -0
  28. package/dist/renderer/components/Grid.d.ts +2 -0
  29. package/dist/renderer/components/Heading.d.ts +2 -0
  30. package/dist/renderer/components/Img.d.ts +2 -0
  31. package/dist/renderer/components/Input.d.ts +2 -0
  32. package/dist/renderer/components/List.d.ts +2 -0
  33. package/dist/renderer/components/Progress.d.ts +2 -0
  34. package/dist/renderer/components/Row.d.ts +2 -0
  35. package/dist/renderer/components/Select.d.ts +2 -0
  36. package/dist/renderer/components/Split.d.ts +2 -0
  37. package/dist/renderer/components/Stat.d.ts +2 -0
  38. package/dist/renderer/components/Table.d.ts +2 -0
  39. package/dist/renderer/components/Tabs.d.ts +2 -0
  40. package/dist/renderer/components/Text.d.ts +2 -0
  41. package/dist/renderer/components/index.d.ts +2 -0
  42. package/dist/renderer/context/ActionContext.d.ts +3 -0
  43. package/dist/renderer/context/DataContext.d.ts +3 -0
  44. package/dist/renderer/context/FormContext.d.ts +10 -0
  45. package/dist/renderer/core/binder.d.ts +17 -0
  46. package/dist/renderer/core/evaluator.d.ts +13 -0
  47. package/dist/renderer/core/iterator.d.ts +10 -0
  48. package/dist/renderer/core/normalizer.d.ts +5 -0
  49. package/dist/renderer/core/parser.d.ts +8 -0
  50. package/dist/renderer/core/resolver.d.ts +6 -0
  51. package/dist/renderer/core/types.d.ts +68 -0
  52. package/dist/renderer/index.d.ts +7 -0
  53. package/dist/renderer/utils/cn.d.ts +2 -0
  54. package/dist/renderer/utils/filters.d.ts +8 -0
  55. package/dist/renderer/utils/sanitize.d.ts +9 -0
  56. package/dist/renderer.cjs +3273 -0
  57. package/dist/renderer.js +3239 -0
  58. package/dist/server/index.d.ts +4 -0
  59. package/dist/server/markdown.d.ts +9 -0
  60. package/dist/server/server.d.ts +39 -0
  61. package/dist/server/types.d.ts +56 -0
  62. package/dist/server/validator.d.ts +5 -0
  63. package/dist/server.cjs +345 -0
  64. package/dist/server.js +303 -0
  65. package/package.json +84 -0
package/dist/apps.cjs ADDED
@@ -0,0 +1,687 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/apps/index.ts
40
+ var exports_apps = {};
41
+ __export(exports_apps, {
42
+ createMeissaApp: () => createMeissaApp,
43
+ MESSAGE_TYPES: () => MESSAGE_TYPES
44
+ });
45
+ module.exports = __toCommonJS(exports_apps);
46
+
47
+ // src/apps/postmessage.ts
48
+ var MESSAGE_TYPES = {
49
+ ACTION: "meissa:action",
50
+ NAVIGATE: "meissa:navigate",
51
+ READY: "meissa:ready",
52
+ RESIZE: "meissa:resize",
53
+ DATA: "meissa:data",
54
+ PATCH: "meissa:patch",
55
+ UPDATE: "meissa:update",
56
+ ACTION_RESPONSE: "meissa:action-response"
57
+ };
58
+ function getPostMessageHandlerCode() {
59
+ return `
60
+ // PostMessage protocol handler
61
+ window.addEventListener('message', (event) => {
62
+ const msg = event.data;
63
+ if (!msg || !msg.type) return;
64
+
65
+ switch (msg.type) {
66
+ case '${MESSAGE_TYPES.DATA}':
67
+ data = msg.data || {};
68
+ render();
69
+ break;
70
+ case '${MESSAGE_TYPES.PATCH}':
71
+ applyPatches(data, msg.patches || []);
72
+ render();
73
+ break;
74
+ case '${MESSAGE_TYPES.UPDATE}':
75
+ data = msg.data || {};
76
+ render();
77
+ break;
78
+ case '${MESSAGE_TYPES.ACTION_RESPONSE}':
79
+ // Action responses can be handled by the app if needed
80
+ if (window.__meissaActionCallbacks) {
81
+ const cb = window.__meissaActionCallbacks.shift();
82
+ if (cb) cb(msg.result);
83
+ }
84
+ break;
85
+ }
86
+ });
87
+
88
+ // Signal ready to host
89
+ window.parent.postMessage({ type: '${MESSAGE_TYPES.READY}' }, '*');
90
+
91
+ // Notify host of content height changes
92
+ let lastHeight = 0;
93
+ const resizeObserver = new ResizeObserver(() => {
94
+ const height = document.documentElement.scrollHeight;
95
+ if (height !== lastHeight) {
96
+ lastHeight = height;
97
+ window.parent.postMessage({ type: '${MESSAGE_TYPES.RESIZE}', height }, '*');
98
+ }
99
+ });
100
+ resizeObserver.observe(document.body);
101
+
102
+ // Action handler — sends action to parent
103
+ function handleAction(action, args) {
104
+ window.parent.postMessage({
105
+ type: '${MESSAGE_TYPES.ACTION}',
106
+ action: action,
107
+ args: args || {}
108
+ }, '*');
109
+ }
110
+
111
+ // Navigate handler — sends navigate to parent
112
+ function handleNavigate(uri) {
113
+ window.parent.postMessage({
114
+ type: '${MESSAGE_TYPES.NAVIGATE}',
115
+ uri: uri
116
+ }, '*');
117
+ }
118
+ `;
119
+ }
120
+
121
+ // src/apps/template.ts
122
+ var DEFAULT_THEME = {
123
+ bg: "#ffffff",
124
+ fg: "#1a1a2e",
125
+ primary: "#6366f1",
126
+ secondary: "#8b5cf6",
127
+ muted: "#6b7280",
128
+ border: "#e5e7eb",
129
+ error: "#ef4444",
130
+ success: "#22c55e",
131
+ warning: "#f59e0b",
132
+ radius: "0.5rem",
133
+ font: "system-ui, -apple-system, sans-serif"
134
+ };
135
+ function generateThemeCSS(theme = {}) {
136
+ const merged = { ...DEFAULT_THEME, ...theme };
137
+ return `
138
+ :root {
139
+ --meissa-bg: ${merged.bg};
140
+ --meissa-fg: ${merged.fg};
141
+ --meissa-primary: ${merged.primary};
142
+ --meissa-secondary: ${merged.secondary};
143
+ --meissa-muted: ${merged.muted};
144
+ --meissa-border: ${merged.border};
145
+ --meissa-error: ${merged.error};
146
+ --meissa-success: ${merged.success};
147
+ --meissa-warning: ${merged.warning};
148
+ --meissa-radius: ${merged.radius};
149
+ --meissa-font: ${merged.font};
150
+ }
151
+ * { box-sizing: border-box; margin: 0; padding: 0; }
152
+ body {
153
+ font-family: var(--meissa-font);
154
+ background: var(--meissa-bg);
155
+ color: var(--meissa-fg);
156
+ line-height: 1.6;
157
+ padding: 1rem;
158
+ }
159
+ .meissa-btn {
160
+ display: inline-flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ padding: 0.5rem 1rem;
164
+ border-radius: var(--meissa-radius);
165
+ border: 1px solid var(--meissa-border);
166
+ background: var(--meissa-primary);
167
+ color: #fff;
168
+ font-size: 0.875rem;
169
+ font-weight: 500;
170
+ cursor: pointer;
171
+ transition: opacity 0.15s;
172
+ }
173
+ .meissa-btn:hover { opacity: 0.85; }
174
+ .meissa-btn-secondary {
175
+ background: transparent;
176
+ color: var(--meissa-primary);
177
+ border-color: var(--meissa-primary);
178
+ }
179
+ .meissa-card {
180
+ border: 1px solid var(--meissa-border);
181
+ border-radius: var(--meissa-radius);
182
+ padding: 1rem;
183
+ margin-bottom: 0.75rem;
184
+ }
185
+ .meissa-table {
186
+ width: 100%;
187
+ border-collapse: collapse;
188
+ font-size: 0.875rem;
189
+ }
190
+ .meissa-table th,
191
+ .meissa-table td {
192
+ padding: 0.5rem 0.75rem;
193
+ border-bottom: 1px solid var(--meissa-border);
194
+ text-align: left;
195
+ }
196
+ .meissa-table th {
197
+ font-weight: 600;
198
+ color: var(--meissa-muted);
199
+ font-size: 0.75rem;
200
+ text-transform: uppercase;
201
+ letter-spacing: 0.05em;
202
+ }
203
+ .meissa-input {
204
+ width: 100%;
205
+ padding: 0.5rem 0.75rem;
206
+ border: 1px solid var(--meissa-border);
207
+ border-radius: var(--meissa-radius);
208
+ font-size: 0.875rem;
209
+ outline: none;
210
+ transition: border-color 0.15s;
211
+ }
212
+ .meissa-input:focus {
213
+ border-color: var(--meissa-primary);
214
+ }
215
+ .meissa-badge {
216
+ display: inline-flex;
217
+ align-items: center;
218
+ padding: 0.125rem 0.5rem;
219
+ border-radius: 9999px;
220
+ font-size: 0.75rem;
221
+ font-weight: 500;
222
+ background: var(--meissa-primary);
223
+ color: #fff;
224
+ }
225
+ .meissa-divider {
226
+ border: none;
227
+ border-top: 1px solid var(--meissa-border);
228
+ margin: 1rem 0;
229
+ }
230
+ .meissa-placeholder {
231
+ display: flex;
232
+ align-items: center;
233
+ justify-content: center;
234
+ min-height: 120px;
235
+ border: 2px dashed var(--meissa-border);
236
+ border-radius: var(--meissa-radius);
237
+ color: var(--meissa-muted);
238
+ font-size: 0.875rem;
239
+ }
240
+ `;
241
+ }
242
+ function getInlineRendererCode() {
243
+ return `
244
+ // Minimal Meissa DOM renderer
245
+ const root = document.getElementById('meissa-root');
246
+
247
+ function resolveBinding(text, ctx) {
248
+ if (typeof text !== 'string') return text;
249
+ return text.replace(/\\{\\{\\s*([^}]+)\\s*\\}\\}/g, (_, path) => {
250
+ const keys = path.trim().split('.');
251
+ let val = ctx;
252
+ for (const k of keys) {
253
+ if (val == null) return '';
254
+ val = val[k];
255
+ }
256
+ return val != null ? String(val) : '';
257
+ });
258
+ }
259
+
260
+ function resolveValue(val, ctx) {
261
+ if (typeof val === 'string') return resolveBinding(val, ctx);
262
+ return val;
263
+ }
264
+
265
+ function createElement(tag, attrs, ...children) {
266
+ const el = document.createElement(tag);
267
+ if (attrs) {
268
+ for (const [key, value] of Object.entries(attrs)) {
269
+ if (key === 'className') el.className = value;
270
+ else if (key === 'style' && typeof value === 'object') {
271
+ Object.assign(el.style, value);
272
+ } else if (key.startsWith('on') && typeof value === 'function') {
273
+ el.addEventListener(key.slice(2).toLowerCase(), value);
274
+ } else {
275
+ el.setAttribute(key, value);
276
+ }
277
+ }
278
+ }
279
+ for (const child of children) {
280
+ if (child == null) continue;
281
+ if (typeof child === 'string' || typeof child === 'number') {
282
+ el.appendChild(document.createTextNode(String(child)));
283
+ } else if (child instanceof Node) {
284
+ el.appendChild(child);
285
+ }
286
+ }
287
+ return el;
288
+ }
289
+
290
+ function renderElement(item, ctx) {
291
+ if (!Array.isArray(item) || item.length === 0) return null;
292
+
293
+ const [type, ...args] = item;
294
+ const props = (args.length > 0 && typeof args[0] === 'object' && !Array.isArray(args[0]))
295
+ ? args[0]
296
+ : null;
297
+ const children = props
298
+ ? args.slice(1)
299
+ : args;
300
+
301
+ switch (type) {
302
+ case 'heading':
303
+ case 'h1': {
304
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
305
+ const level = props?.level || (type === 'h1' ? 1 : 2);
306
+ const tag = 'h' + Math.min(Math.max(level, 1), 6);
307
+ return createElement(tag, {
308
+ className: 'font-bold mb-3 ' + (level <= 1 ? 'text-2xl' : level === 2 ? 'text-xl' : 'text-lg')
309
+ }, text);
310
+ }
311
+
312
+ case 'text':
313
+ case 'p': {
314
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
315
+ return createElement('p', { className: 'mb-2' }, text);
316
+ }
317
+
318
+ case 'span': {
319
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
320
+ return createElement('span', null, text);
321
+ }
322
+
323
+ case 'bold':
324
+ case 'strong': {
325
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
326
+ return createElement('strong', null, text);
327
+ }
328
+
329
+ case 'italic':
330
+ case 'em': {
331
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
332
+ return createElement('em', null, text);
333
+ }
334
+
335
+ case 'code': {
336
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
337
+ return createElement('code', {
338
+ className: 'px-1.5 py-0.5 bg-gray-100 rounded text-sm font-mono'
339
+ }, text);
340
+ }
341
+
342
+ case 'pre': {
343
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : '';
344
+ const pre = createElement('pre', {
345
+ className: 'p-3 bg-gray-100 rounded overflow-x-auto text-sm font-mono mb-3'
346
+ });
347
+ pre.appendChild(createElement('code', null, text));
348
+ return pre;
349
+ }
350
+
351
+ case 'link':
352
+ case 'a': {
353
+ const href = props?.href || (typeof args[1] === 'string' ? args[1] : '#');
354
+ const text = typeof args[0] === 'string' ? resolveValue(args[0], ctx) : props?.label || 'Link';
355
+ const el = createElement('a', {
356
+ className: 'text-indigo-600 underline hover:text-indigo-800',
357
+ href: resolveValue(href, ctx),
358
+ }, resolveValue(text, ctx));
359
+ if (props?.navigate) {
360
+ el.addEventListener('click', (e) => {
361
+ e.preventDefault();
362
+ handleNavigate(props.navigate);
363
+ });
364
+ }
365
+ return el;
366
+ }
367
+
368
+ case 'btn':
369
+ case 'button': {
370
+ const label = props?.label || (typeof args[0] === 'string' ? args[0] : 'Button');
371
+ const action = props?.action || '';
372
+ const actionArgs = props?.args || {};
373
+ const variant = props?.variant || 'primary';
374
+ const cls = variant === 'secondary' ? 'meissa-btn meissa-btn-secondary' : 'meissa-btn';
375
+ const el = createElement('button', { className: cls }, resolveValue(label, ctx));
376
+ el.addEventListener('click', () => {
377
+ handleAction(action, actionArgs);
378
+ });
379
+ return el;
380
+ }
381
+
382
+ case 'input': {
383
+ const placeholder = props?.placeholder || '';
384
+ const name = props?.name || '';
385
+ const inputType = props?.inputType || 'text';
386
+ return createElement('input', {
387
+ className: 'meissa-input',
388
+ type: inputType,
389
+ name: name,
390
+ placeholder: resolveValue(placeholder, ctx),
391
+ });
392
+ }
393
+
394
+ case 'img':
395
+ case 'image': {
396
+ const src = props?.src || (typeof args[0] === 'string' ? args[0] : '');
397
+ const alt = props?.alt || '';
398
+ return createElement('img', {
399
+ src: resolveValue(src, ctx),
400
+ alt: resolveValue(alt, ctx),
401
+ className: 'max-w-full rounded',
402
+ });
403
+ }
404
+
405
+ case 'badge': {
406
+ const text = props?.label || (typeof args[0] === 'string' ? args[0] : '');
407
+ const color = props?.color;
408
+ const style = color ? { background: color } : {};
409
+ return createElement('span', { className: 'meissa-badge', style }, resolveValue(text, ctx));
410
+ }
411
+
412
+ case 'divider':
413
+ case 'hr': {
414
+ return createElement('hr', { className: 'meissa-divider' });
415
+ }
416
+
417
+ case 'spacer': {
418
+ const size = props?.size || '1rem';
419
+ return createElement('div', { style: { height: size } });
420
+ }
421
+
422
+ case 'row': {
423
+ const gap = props?.gap || '0.75rem';
424
+ const align = props?.align || 'center';
425
+ const justify = props?.justify || 'flex-start';
426
+ const container = createElement('div', {
427
+ style: { display: 'flex', flexDirection: 'row', gap, alignItems: align, justifyContent: justify, flexWrap: 'wrap' }
428
+ });
429
+ const childItems = Array.isArray(args[0]) && Array.isArray(args[0][0]) ? args[0] : children.filter(Array.isArray);
430
+ for (const child of childItems) {
431
+ const childEl = renderElement(child, ctx);
432
+ if (childEl) container.appendChild(childEl);
433
+ }
434
+ return container;
435
+ }
436
+
437
+ case 'col':
438
+ case 'column': {
439
+ const gap = props?.gap || '0.75rem';
440
+ const container = createElement('div', {
441
+ style: { display: 'flex', flexDirection: 'column', gap }
442
+ });
443
+ const childItems = Array.isArray(args[0]) && Array.isArray(args[0][0]) ? args[0] : children.filter(Array.isArray);
444
+ for (const child of childItems) {
445
+ const childEl = renderElement(child, ctx);
446
+ if (childEl) container.appendChild(childEl);
447
+ }
448
+ return container;
449
+ }
450
+
451
+ case 'grid': {
452
+ const cols = props?.cols || 2;
453
+ const gap = props?.gap || '0.75rem';
454
+ const container = createElement('div', {
455
+ style: { display: 'grid', gridTemplateColumns: 'repeat(' + cols + ', 1fr)', gap }
456
+ });
457
+ const childItems = Array.isArray(args[0]) && Array.isArray(args[0][0]) ? args[0] : children.filter(Array.isArray);
458
+ for (const child of childItems) {
459
+ const childEl = renderElement(child, ctx);
460
+ if (childEl) container.appendChild(childEl);
461
+ }
462
+ return container;
463
+ }
464
+
465
+ case 'card': {
466
+ const title = props?.title;
467
+ const container = createElement('div', { className: 'meissa-card' });
468
+ if (title) {
469
+ container.appendChild(createElement('h3', {
470
+ className: 'font-semibold mb-2'
471
+ }, resolveValue(title, ctx)));
472
+ }
473
+ const childItems = Array.isArray(args[0]) && Array.isArray(args[0][0]) ? args[0] : children.filter(Array.isArray);
474
+ for (const child of childItems) {
475
+ const childEl = renderElement(child, ctx);
476
+ if (childEl) container.appendChild(childEl);
477
+ }
478
+ return container;
479
+ }
480
+
481
+ case 'table': {
482
+ const columns = props?.columns || [];
483
+ const rows = props?.rows || props?.data || [];
484
+ const dataKey = props?.dataKey;
485
+ const resolvedRows = dataKey ? getNestedValue(ctx, dataKey) || [] : rows;
486
+
487
+ const table = createElement('table', { className: 'meissa-table mb-3' });
488
+
489
+ // Header
490
+ if (columns.length > 0) {
491
+ const thead = createElement('thead');
492
+ const headerRow = createElement('tr');
493
+ for (const col of columns) {
494
+ const label = typeof col === 'string' ? col : col.label || col.key || '';
495
+ headerRow.appendChild(createElement('th', null, resolveValue(label, ctx)));
496
+ }
497
+ thead.appendChild(headerRow);
498
+ table.appendChild(thead);
499
+ }
500
+
501
+ // Body
502
+ const tbody = createElement('tbody');
503
+ const dataRows = Array.isArray(resolvedRows) ? resolvedRows : [];
504
+ for (const row of dataRows) {
505
+ const tr = createElement('tr');
506
+ if (columns.length > 0) {
507
+ for (const col of columns) {
508
+ const key = typeof col === 'string' ? col : col.key || '';
509
+ const cellVal = row[key] != null ? String(row[key]) : '';
510
+ tr.appendChild(createElement('td', null, cellVal));
511
+ }
512
+ } else if (Array.isArray(row)) {
513
+ for (const cell of row) {
514
+ tr.appendChild(createElement('td', null, cell != null ? String(cell) : ''));
515
+ }
516
+ }
517
+ tbody.appendChild(tr);
518
+ }
519
+ table.appendChild(tbody);
520
+ return table;
521
+ }
522
+
523
+ case 'list': {
524
+ const items = props?.items || [];
525
+ const ordered = props?.ordered || false;
526
+ const dataKey = props?.dataKey;
527
+ const resolvedItems = dataKey ? getNestedValue(ctx, dataKey) || [] : items;
528
+ const tag = ordered ? 'ol' : 'ul';
529
+ const list = createElement(tag, {
530
+ className: 'list-disc list-inside mb-3 space-y-1'
531
+ });
532
+ for (const item of resolvedItems) {
533
+ const text = typeof item === 'string' ? resolveValue(item, ctx) : String(item);
534
+ list.appendChild(createElement('li', null, text));
535
+ }
536
+ return list;
537
+ }
538
+
539
+ case 'chart':
540
+ case 'graph': {
541
+ const chartType = props?.type || 'chart';
542
+ return createElement('div', { className: 'meissa-placeholder' },
543
+ '[' + chartType + ' chart placeholder — requires full renderer]'
544
+ );
545
+ }
546
+
547
+ case 'progress': {
548
+ const value = props?.value || 0;
549
+ const max = props?.max || 100;
550
+ const pct = Math.min(100, Math.max(0, (value / max) * 100));
551
+ const outer = createElement('div', {
552
+ className: 'w-full bg-gray-200 rounded-full h-2.5 mb-3'
553
+ });
554
+ outer.appendChild(createElement('div', {
555
+ style: { width: pct + '%', height: '100%', borderRadius: '9999px', background: 'var(--meissa-primary)' }
556
+ }));
557
+ return outer;
558
+ }
559
+
560
+ case 'fragment':
561
+ case 'group': {
562
+ const frag = document.createDocumentFragment();
563
+ const childItems = Array.isArray(args[0]) && Array.isArray(args[0][0]) ? args[0] : children.filter(Array.isArray);
564
+ for (const child of childItems) {
565
+ const childEl = renderElement(child, ctx);
566
+ if (childEl) frag.appendChild(childEl);
567
+ }
568
+ return frag;
569
+ }
570
+
571
+ default: {
572
+ // Unknown component — render as a div with type as class
573
+ const container = createElement('div', {
574
+ className: 'mb-2',
575
+ 'data-meissa-type': type
576
+ });
577
+ if (typeof args[0] === 'string') {
578
+ container.textContent = resolveValue(args[0], ctx);
579
+ }
580
+ const childItems = children.filter(Array.isArray);
581
+ for (const child of childItems) {
582
+ const childEl = renderElement(child, ctx);
583
+ if (childEl) container.appendChild(childEl);
584
+ }
585
+ return container;
586
+ }
587
+ }
588
+ }
589
+
590
+ function getNestedValue(obj, path) {
591
+ if (!path) return obj;
592
+ const keys = path.split('.');
593
+ let val = obj;
594
+ for (const k of keys) {
595
+ if (val == null) return undefined;
596
+ val = val[k];
597
+ }
598
+ return val;
599
+ }
600
+
601
+ function applyPatches(obj, patches) {
602
+ for (const patch of patches) {
603
+ const pathParts = patch.path.split('/').filter(Boolean);
604
+ if (pathParts.length === 0) continue;
605
+
606
+ const parent = pathParts.slice(0, -1).reduce((acc, key) => {
607
+ if (acc == null) return undefined;
608
+ return acc[key];
609
+ }, obj);
610
+
611
+ const lastKey = pathParts[pathParts.length - 1];
612
+ if (parent == null) continue;
613
+
614
+ switch (patch.op) {
615
+ case 'add':
616
+ case 'replace':
617
+ parent[lastKey] = patch.value;
618
+ break;
619
+ case 'remove':
620
+ if (Array.isArray(parent)) {
621
+ parent.splice(Number(lastKey), 1);
622
+ } else {
623
+ delete parent[lastKey];
624
+ }
625
+ break;
626
+ }
627
+ }
628
+ }
629
+
630
+ function render() {
631
+ root.innerHTML = '';
632
+ for (const item of schema) {
633
+ const el = renderElement(item, data);
634
+ if (el) root.appendChild(el);
635
+ }
636
+ }
637
+
638
+ // Initial render
639
+ render();
640
+ `;
641
+ }
642
+ function generateHtml(schema, options = {}) {
643
+ const { title = "Meissa App", theme } = options;
644
+ const themeCSS = generateThemeCSS(theme);
645
+ const postMessageHandler = getPostMessageHandlerCode();
646
+ const inlineRenderer = getInlineRendererCode();
647
+ const schemaJson = JSON.stringify(schema);
648
+ return `<!DOCTYPE html>
649
+ <html lang="en">
650
+ <head>
651
+ <meta charset="UTF-8">
652
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
653
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline' https://cdn.tailwindcss.com; script-src 'unsafe-inline'; img-src https:">
654
+ <title>${escapeHtml(title)}</title>
655
+ <script src="https://cdn.tailwindcss.com"></script>
656
+ <style>${themeCSS}</style>
657
+ </head>
658
+ <body>
659
+ <div id="meissa-root"></div>
660
+ <script type="module">
661
+ const schema = ${schemaJson};
662
+ let data = {};
663
+ window.__meissaActionCallbacks = [];
664
+
665
+ ${postMessageHandler}
666
+ ${inlineRenderer}
667
+ </script>
668
+ </body>
669
+ </html>`;
670
+ }
671
+ function escapeHtml(str) {
672
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
673
+ }
674
+
675
+ // src/apps/app-generator.ts
676
+ function createMeissaApp(schema, options) {
677
+ const html = generateHtml(schema, {
678
+ title: options?.title,
679
+ theme: options?.theme,
680
+ width: options?.width,
681
+ height: options?.height
682
+ });
683
+ return {
684
+ content: html,
685
+ mimeType: "text/html"
686
+ };
687
+ }