@africode/core 5.0.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 (136) hide show
  1. package/AFRICODE_FRAMEWORK_GUIDE.md +707 -0
  2. package/LICENSE +623 -0
  3. package/README.md +442 -0
  4. package/bin/africode.js +73 -0
  5. package/bin/africode.js.1758507140 +343 -0
  6. package/bin/cli.ts +83 -0
  7. package/bin/create-africode.js +158 -0
  8. package/bin/scaffold.ts +219 -0
  9. package/components/accordion.js +183 -0
  10. package/components/alert.js +131 -0
  11. package/components/auth.js +172 -0
  12. package/components/avatar.js +117 -0
  13. package/components/badge.js +104 -0
  14. package/components/base.d.ts +139 -0
  15. package/components/base.js +184 -0
  16. package/components/button.js +164 -0
  17. package/components/card.js +137 -0
  18. package/components/cultural-card.js +243 -0
  19. package/components/divider.js +83 -0
  20. package/components/dropdown.js +171 -0
  21. package/components/error-boundary.js +155 -0
  22. package/components/form.js +131 -0
  23. package/components/grid.js +273 -0
  24. package/components/hero.js +138 -0
  25. package/components/icon.js +36 -0
  26. package/components/index.js +57 -0
  27. package/components/input.js +256 -0
  28. package/components/kanga-card.js +185 -0
  29. package/components/language-switcher.js +108 -0
  30. package/components/loader.js +80 -0
  31. package/components/modal.js +262 -0
  32. package/components/motion.js +84 -0
  33. package/components/navbar.js +236 -0
  34. package/components/pattern-showcase.js +225 -0
  35. package/components/progress.js +134 -0
  36. package/components/react.js +111 -0
  37. package/components/section.js +54 -0
  38. package/components/select.js +322 -0
  39. package/components/sidebar.js +180 -0
  40. package/components/skeleton.js +85 -0
  41. package/components/table.js +181 -0
  42. package/components/tabs.js +202 -0
  43. package/components/theme-toggle.js +82 -0
  44. package/components/toast.js +139 -0
  45. package/components/tooltip.js +167 -0
  46. package/core/a2ui-schema-manager.js +344 -0
  47. package/core/a2ui.js +431 -0
  48. package/core/bun-runtime.js +799 -0
  49. package/core/cli/commands/add.js +23 -0
  50. package/core/cli/commands/audit.js +58 -0
  51. package/core/cli/commands/build.js +137 -0
  52. package/core/cli/commands/create-plugin.js +241 -0
  53. package/core/cli/commands/dev.js +228 -0
  54. package/core/cli/commands/lint.js +23 -0
  55. package/core/cli/commands/test.js +34 -0
  56. package/core/cli/migrator.js +71 -0
  57. package/core/cli/ui.js +46 -0
  58. package/core/compliance.js +628 -0
  59. package/core/config.js +263 -0
  60. package/core/db-advanced.js +481 -0
  61. package/core/db.js +284 -0
  62. package/core/enhanced-hmr.js +404 -0
  63. package/core/errors.js +222 -0
  64. package/core/file-router.js +290 -0
  65. package/core/heartbeat.js +64 -0
  66. package/core/hmr-client.js +204 -0
  67. package/core/hmr.js +196 -0
  68. package/core/html.d.ts +116 -0
  69. package/core/html.js +160 -0
  70. package/core/hydration.js +52 -0
  71. package/core/lipa-namba-journey.js +572 -0
  72. package/core/motion.js +106 -0
  73. package/core/nida-cig-middleware.js +455 -0
  74. package/core/patterns.d.ts +124 -0
  75. package/core/patterns.js +833 -0
  76. package/core/plugins/index.js +312 -0
  77. package/core/router.js +387 -0
  78. package/core/sdk-client.js +62 -0
  79. package/core/sdk.d.ts +133 -0
  80. package/core/sdk.js +123 -0
  81. package/core/seo.js +76 -0
  82. package/core/server/auth-endpoints.js +339 -0
  83. package/core/server/auth.js +180 -0
  84. package/core/server/csrf.js +206 -0
  85. package/core/server/db.js +39 -0
  86. package/core/server/middleware.js +324 -0
  87. package/core/server/rate-limit.js +238 -0
  88. package/core/server/render.js +69 -0
  89. package/core/server/router.js +120 -0
  90. package/core/shim.js +28 -0
  91. package/core/state.d.ts +86 -0
  92. package/core/state.js +242 -0
  93. package/core/store.d.ts +122 -0
  94. package/core/store.js +61 -0
  95. package/core/validation.d.ts +233 -0
  96. package/core/validation.js +590 -0
  97. package/core/websocket.js +639 -0
  98. package/dist/africode.js +2905 -0
  99. package/dist/africode.js.map +61 -0
  100. package/dist/build-info.json +23 -0
  101. package/dist/components.js +2888 -0
  102. package/dist/components.js.map +58 -0
  103. package/dist/styles/africanity.css +322 -0
  104. package/dist/styles/typography.css +141 -0
  105. package/docs/IDE-Guide.md +50 -0
  106. package/package.json +110 -0
  107. package/src/index.ts +196 -0
  108. package/styles/africanity.css +322 -0
  109. package/styles/typography.css +141 -0
  110. package/templates/starter/.env.example +15 -0
  111. package/templates/starter/africode.config.js +40 -0
  112. package/templates/starter/package.json +14 -0
  113. package/templates/starter/src/pages/index.html +46 -0
  114. package/templates/starter/src/pages/index.js +32 -0
  115. package/templates/starter/src/styles/main.css +4 -0
  116. package/templates/starter-3d/.env.example +7 -0
  117. package/templates/starter-3d/africode.config.js +29 -0
  118. package/templates/starter-3d/components/af-model-viewer.js +125 -0
  119. package/templates/starter-3d/package.json +15 -0
  120. package/templates/starter-3d/src/pages/index.html +46 -0
  121. package/templates/starter-3d/src/pages/index.js +50 -0
  122. package/templates/starter-3d/src/styles/main.css +4 -0
  123. package/templates/starter-react/.env.example +15 -0
  124. package/templates/starter-react/africode.config.js +40 -0
  125. package/templates/starter-react/package.json +16 -0
  126. package/templates/starter-react/src/pages/index.html +46 -0
  127. package/templates/starter-react/src/pages/index.js +68 -0
  128. package/templates/starter-react/src/styles/main.css +4 -0
  129. package/templates/starter-tailwind/.env.example +15 -0
  130. package/templates/starter-tailwind/africode.config.js +40 -0
  131. package/templates/starter-tailwind/package.json +20 -0
  132. package/templates/starter-tailwind/src/pages/index.html +46 -0
  133. package/templates/starter-tailwind/src/pages/index.js +37 -0
  134. package/templates/starter-tailwind/src/styles/main.css +4 -0
  135. package/templates/starter-tailwind/src/styles/tailwind.css +1 -0
  136. package/templates/starter-tailwind/src/tailwind-loader.js +30 -0
package/core/a2ui.js ADDED
@@ -0,0 +1,431 @@
1
+ /**
2
+ * A2UI Protocol Implementation
3
+ * Agent-to-User Interface declarative protocol for generative AI
4
+ *
5
+ * Enables AI agents to return UI widgets as part of responses without
6
+ * executing arbitrary code, ensuring security and consistency.
7
+ *
8
+ * @module core/a2ui
9
+ */
10
+
11
+ /**
12
+ * A2UI Message Types
13
+ */
14
+ export const A2UI_TYPES = {
15
+ COMPONENT: 'component',
16
+ FORM: 'form',
17
+ LIST: 'list',
18
+ CARD: 'card',
19
+ MODAL: 'modal',
20
+ TOAST: 'toast',
21
+ PROGRESS: 'progress'
22
+ };
23
+
24
+ /**
25
+ * A2UI Component Schemas
26
+ */
27
+ export const A2UI_SCHEMAS = {
28
+ component: {
29
+ type: 'object',
30
+ properties: {
31
+ id: { type: 'string' },
32
+ type: { type: 'string', enum: Object.values(A2UI_TYPES) },
33
+ props: { type: 'object' },
34
+ children: { type: 'array', items: { $ref: '#' } }
35
+ },
36
+ required: ['id', 'type']
37
+ }
38
+ };
39
+
40
+ /**
41
+ * A2UI Renderer
42
+ * Renders A2UI messages into actual DOM elements
43
+ */
44
+ export class A2UIRenderer {
45
+ constructor(rootElement) {
46
+ this.root = rootElement;
47
+ this.components = new Map();
48
+ }
49
+
50
+ /**
51
+ * Render an A2UI message
52
+ * @param {Object} message - A2UI message object
53
+ */
54
+ async render(message) {
55
+ if (!message || !message.type) {
56
+ throw new Error('Invalid A2UI message');
57
+ }
58
+
59
+ const canRenderToDOM = this.root && typeof this.root.appendChild === 'function';
60
+
61
+ if (!canRenderToDOM) {
62
+ const placeholder = {
63
+ id: message.id || `a2ui-${Date.now()}`,
64
+ type: message.type,
65
+ props: message.props || {},
66
+ children: message.children || []
67
+ };
68
+
69
+ if (placeholder.id) {
70
+ this.components.set(placeholder.id, placeholder);
71
+ }
72
+
73
+ return placeholder;
74
+ }
75
+
76
+ const element = await this.createElement(message);
77
+ this.root.appendChild(element);
78
+ return element;
79
+ }
80
+
81
+ /**
82
+ * Create DOM element from A2UI component
83
+ * @param {Object} component - A2UI component definition
84
+ */
85
+ async createElement(component) {
86
+ const { type, props = {}, children = [] } = component;
87
+
88
+ let element;
89
+
90
+ switch (type) {
91
+ case A2UI_TYPES.COMPONENT:
92
+ element = await this.createCustomComponent(props);
93
+ break;
94
+ case A2UI_TYPES.FORM:
95
+ element = await this.createForm(props);
96
+ break;
97
+ case A2UI_TYPES.LIST:
98
+ element = await this.createList(props);
99
+ break;
100
+ case A2UI_TYPES.CARD:
101
+ element = await this.createCard(props);
102
+ break;
103
+ case A2UI_TYPES.MODAL:
104
+ element = await this.createModal(props);
105
+ break;
106
+ case A2UI_TYPES.TOAST:
107
+ element = await this.createToast(props);
108
+ break;
109
+ case A2UI_TYPES.PROGRESS:
110
+ element = await this.createProgress(props);
111
+ break;
112
+ default:
113
+ throw new Error(`Unknown A2UI component type: ${type}`);
114
+ }
115
+
116
+ // Render children
117
+ if (children.length > 0) {
118
+ for (const child of children) {
119
+ const childElement = await this.createElement(child);
120
+ element.appendChild(childElement);
121
+ }
122
+ }
123
+
124
+ return element;
125
+ }
126
+
127
+ /**
128
+ * Create custom AfriCode component
129
+ */
130
+ async createCustomComponent({ tag, ...props }) {
131
+ const element = document.createElement(tag || 'div');
132
+ Object.assign(element, props);
133
+ return element;
134
+ }
135
+
136
+ /**
137
+ * Create form component
138
+ */
139
+ async createForm({ fields = [], onSubmit }) {
140
+ const form = document.createElement('af-form');
141
+
142
+ for (const field of fields) {
143
+ const input = document.createElement('af-input');
144
+ input.setAttribute('name', field.name);
145
+ input.setAttribute('placeholder', field.placeholder || '');
146
+ input.setAttribute('type', field.type || 'text');
147
+ form.appendChild(input);
148
+ }
149
+
150
+ if (onSubmit) {
151
+ form.addEventListener('submit', onSubmit);
152
+ }
153
+
154
+ return form;
155
+ }
156
+
157
+ /**
158
+ * Create list component
159
+ */
160
+ async createList({ items = [] }) {
161
+ const list = document.createElement('af-grid');
162
+
163
+ for (const item of items) {
164
+ const card = await this.createCard(item);
165
+ list.appendChild(card);
166
+ }
167
+
168
+ return list;
169
+ }
170
+
171
+ /**
172
+ * Create card component
173
+ */
174
+ async createCard({ title, content, image }) {
175
+ const card = document.createElement('af-card');
176
+
177
+ if (title) {
178
+ const titleEl = document.createElement('h3');
179
+ titleEl.textContent = title;
180
+ card.appendChild(titleEl);
181
+ }
182
+
183
+ if (content) {
184
+ const contentEl = document.createElement('p');
185
+ contentEl.textContent = content;
186
+ card.appendChild(contentEl);
187
+ }
188
+
189
+ if (image) {
190
+ const img = document.createElement('img');
191
+ img.src = image;
192
+ img.alt = title || 'Card image';
193
+ card.appendChild(img);
194
+ }
195
+
196
+ return card;
197
+ }
198
+
199
+ /**
200
+ * Create modal component
201
+ */
202
+ async createModal({ title, content, actions = [] }) {
203
+ const modal = document.createElement('af-modal');
204
+ modal.setAttribute('open', '');
205
+
206
+ if (title) {
207
+ const titleEl = document.createElement('h2');
208
+ titleEl.slot = 'header';
209
+ titleEl.textContent = title;
210
+ modal.appendChild(titleEl);
211
+ }
212
+
213
+ if (content) {
214
+ const contentEl = document.createElement('p');
215
+ contentEl.textContent = content;
216
+ modal.appendChild(contentEl);
217
+ }
218
+
219
+ const actionsContainer = document.createElement('div');
220
+ actionsContainer.slot = 'footer';
221
+
222
+ for (const action of actions) {
223
+ const button = document.createElement('af-button');
224
+ button.textContent = action.label;
225
+ if (action.primary) {
226
+ button.setAttribute('variant', 'primary');
227
+ }
228
+ if (action.onClick) {
229
+ button.addEventListener('click', action.onClick);
230
+ }
231
+ actionsContainer.appendChild(button);
232
+ }
233
+
234
+ modal.appendChild(actionsContainer);
235
+ return modal;
236
+ }
237
+
238
+ /**
239
+ * Create toast component
240
+ */
241
+ async createToast({ message, type = 'info', duration = 3000 }) {
242
+ const toast = document.createElement('af-toast');
243
+ toast.setAttribute('type', type);
244
+ toast.textContent = message;
245
+
246
+ // Auto-remove after duration
247
+ setTimeout(() => {
248
+ toast.remove();
249
+ }, duration);
250
+
251
+ return toast;
252
+ }
253
+
254
+ /**
255
+ * Create progress component
256
+ */
257
+ async createProgress({ value = 0, max = 100, label }) {
258
+ const progress = document.createElement('af-progress');
259
+ progress.setAttribute('value', value);
260
+ progress.setAttribute('max', max);
261
+
262
+ if (label) {
263
+ progress.setAttribute('label', label);
264
+ }
265
+
266
+ return progress;
267
+ }
268
+
269
+ /**
270
+ * Update existing component
271
+ */
272
+ async update(id, newProps) {
273
+ const element = this.components.get(id);
274
+ if (element) {
275
+ Object.assign(element, newProps);
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Remove component
281
+ */
282
+ remove(id) {
283
+ const element = this.components.get(id);
284
+ if (element) {
285
+ element.remove();
286
+ this.components.delete(id);
287
+ }
288
+ }
289
+ }
290
+
291
+ /**
292
+ * A2UI Protocol Handler
293
+ * Processes streaming A2UI messages from AI agents
294
+ */
295
+ export class A2UIProtocol {
296
+ constructor(renderer) {
297
+ this.renderer = renderer;
298
+ this.messageQueue = [];
299
+ this.messageHandlers = [];
300
+ this.isProcessing = false;
301
+ }
302
+
303
+ /**
304
+ * Register a message handler callback
305
+ * @param {Function} callback - Handler to receive processed messages
306
+ */
307
+ onMessage(callback) {
308
+ if (typeof callback === 'function') {
309
+ this.messageHandlers.push(callback);
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Send a message into the A2UI system
315
+ * @param {Object|string} message - A2UI message
316
+ */
317
+ async sendMessage(message) {
318
+ return this.processMessage(message);
319
+ }
320
+
321
+ /**
322
+ * Process incoming A2UI message
323
+ * @param {Object|string} message - A2UI message
324
+ */
325
+ async processMessage(message) {
326
+ if (typeof message === 'string') {
327
+ try {
328
+ message = JSON.parse(message);
329
+ } catch {
330
+ console.warn('Invalid A2UI message format:', message);
331
+ return;
332
+ }
333
+ }
334
+
335
+ this.messageQueue.push(message);
336
+ await this.processQueue();
337
+
338
+ for (const handler of this.messageHandlers) {
339
+ handler(message);
340
+ }
341
+ }
342
+
343
+ /**
344
+ * Process queued messages
345
+ */
346
+ async processQueue() {
347
+ if (this.isProcessing || this.messageQueue.length === 0) {
348
+ return;
349
+ }
350
+
351
+ this.isProcessing = true;
352
+
353
+ while (this.messageQueue.length > 0) {
354
+ const message = this.messageQueue.shift();
355
+
356
+ try {
357
+ await this.renderer.render(message);
358
+ } catch (error) {
359
+ console.error('A2UI render error:', error);
360
+ }
361
+ }
362
+
363
+ this.isProcessing = false;
364
+ }
365
+
366
+ /**
367
+ * Stream handler for real-time AI responses
368
+ * @param {ReadableStream} stream - AI response stream
369
+ */
370
+ async handleStream(stream) {
371
+ const reader = stream.getReader();
372
+ const decoder = new TextDecoder();
373
+
374
+ let buffer = '';
375
+
376
+ while (true) {
377
+ const { done, value } = await reader.read();
378
+
379
+ if (done) {
380
+ break;
381
+ }
382
+
383
+ buffer += decoder.decode(value, { stream: true });
384
+
385
+ // Process complete messages
386
+ const messages = buffer.split('\n');
387
+ buffer = messages.pop(); // Keep incomplete message in buffer
388
+
389
+ for (const message of messages) {
390
+ if (message.trim()) {
391
+ await this.processMessage(message.trim());
392
+ }
393
+ }
394
+ }
395
+
396
+ // Process any remaining buffer
397
+ if (buffer.trim()) {
398
+ await this.processMessage(buffer.trim());
399
+ }
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Initialize A2UI system
405
+ * @param {HTMLElement} root - Root element for rendering
406
+ */
407
+ export function initA2UI(root) {
408
+ // Handle server-side rendering (no DOM)
409
+ if (typeof document === 'undefined') {
410
+ root = null;
411
+ } else {
412
+ root = root || document.body;
413
+ }
414
+
415
+ const renderer = new A2UIRenderer(root);
416
+ const protocol = new A2UIProtocol(renderer);
417
+
418
+ // Make globally available for AI agents
419
+ if (typeof window !== 'undefined') {
420
+ window.a2ui = {
421
+ render: (message) => protocol.processMessage(message),
422
+ handleStream: (stream) => protocol.handleStream(stream),
423
+ update: (id, props) => renderer.update(id, props),
424
+ remove: (id) => renderer.remove(id),
425
+ sendMessage: (message) => protocol.sendMessage(message),
426
+ onMessage: (callback) => protocol.onMessage(callback)
427
+ };
428
+ }
429
+
430
+ return { renderer, protocol };
431
+ }