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