@africode/core 5.0.0 → 5.0.1

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.
@@ -0,0 +1,803 @@
1
+ {
2
+ "version": "5.0.0",
3
+ "timestamp": "2026-05-02T15:31:51.816Z",
4
+ "components": [
5
+ {
6
+ "tagName": "af-components\\accordion",
7
+ "filePath": "components\\accordion.js",
8
+ "slots": [
9
+ "default"
10
+ ],
11
+ "attributes": {
12
+ "theme": {
13
+ "type": "string"
14
+ },
15
+ "multiple": {
16
+ "type": "string"
17
+ }
18
+ },
19
+ "events": [],
20
+ "cssCustomProperties": [],
21
+ "example": "<af-components\\accordion></af-components\\accordion>",
22
+ "securityNotes": "Sanitizes slot content"
23
+ },
24
+ {
25
+ "tagName": "af-components\\alert",
26
+ "filePath": "components\\alert.js",
27
+ "slots": [
28
+ "default"
29
+ ],
30
+ "attributes": {
31
+ "type": {
32
+ "type": "string"
33
+ },
34
+ "title": {
35
+ "type": "string"
36
+ },
37
+ "dismissible": {
38
+ "type": "string"
39
+ }
40
+ },
41
+ "events": [],
42
+ "cssCustomProperties": [],
43
+ "example": "<af-components\\alert></af-components\\alert>",
44
+ "securityNotes": "Sanitizes slot content"
45
+ },
46
+ {
47
+ "tagName": "af-components\\auth",
48
+ "filePath": "components\\auth.js",
49
+ "slots": [
50
+ "default"
51
+ ],
52
+ "attributes": {},
53
+ "events": [],
54
+ "cssCustomProperties": [],
55
+ "example": "<af-components\\auth></af-components\\auth>",
56
+ "securityNotes": "Sanitizes slot content"
57
+ },
58
+ {
59
+ "tagName": "af-components\\avatar",
60
+ "filePath": "components\\avatar.js",
61
+ "slots": [
62
+ "default"
63
+ ],
64
+ "attributes": {
65
+ "src": {
66
+ "type": "string"
67
+ },
68
+ "name": {
69
+ "type": "string"
70
+ },
71
+ "size": {
72
+ "type": "string"
73
+ },
74
+ "status": {
75
+ "type": "string"
76
+ },
77
+ "theme": {
78
+ "type": "string"
79
+ }
80
+ },
81
+ "events": [],
82
+ "cssCustomProperties": [],
83
+ "example": "<af-components\\avatar></af-components\\avatar>",
84
+ "securityNotes": "Sanitizes slot content"
85
+ },
86
+ {
87
+ "tagName": "af-components\\badge",
88
+ "filePath": "components\\badge.js",
89
+ "slots": [
90
+ "default"
91
+ ],
92
+ "attributes": {
93
+ "variant": {
94
+ "type": "string"
95
+ },
96
+ "size": {
97
+ "type": "string"
98
+ },
99
+ "removable": {
100
+ "type": "string"
101
+ }
102
+ },
103
+ "events": [],
104
+ "cssCustomProperties": [],
105
+ "example": "<af-components\\badge></af-components\\badge>",
106
+ "securityNotes": "Sanitizes slot content"
107
+ },
108
+ {
109
+ "tagName": "af-components\\button",
110
+ "filePath": "components\\button.js",
111
+ "slots": [
112
+ "default"
113
+ ],
114
+ "attributes": {
115
+ "variant": {
116
+ "type": "string"
117
+ },
118
+ "size": {
119
+ "type": "string"
120
+ },
121
+ "theme": {
122
+ "type": "string"
123
+ },
124
+ "disabled": {
125
+ "type": "string"
126
+ },
127
+ "loading": {
128
+ "type": "string"
129
+ },
130
+ "icon": {
131
+ "type": "string"
132
+ },
133
+ "aria-label": {
134
+ "type": "string"
135
+ }
136
+ },
137
+ "events": [
138
+ {
139
+ "name": "click",
140
+ "detail": {
141
+ "type": "object"
142
+ }
143
+ }
144
+ ],
145
+ "cssCustomProperties": [],
146
+ "example": "<af-components\\button></af-components\\button>",
147
+ "securityNotes": "Sanitizes slot content"
148
+ },
149
+ {
150
+ "tagName": "af-components\\card",
151
+ "filePath": "components\\card.js",
152
+ "slots": [
153
+ "default"
154
+ ],
155
+ "attributes": {
156
+ "theme": {
157
+ "type": "string"
158
+ },
159
+ "variant": {
160
+ "type": "string"
161
+ },
162
+ "clickable": {
163
+ "type": "string"
164
+ },
165
+ "image": {
166
+ "type": "string"
167
+ }
168
+ },
169
+ "events": [],
170
+ "cssCustomProperties": [],
171
+ "example": "<af-components\\card></af-components\\card>",
172
+ "securityNotes": "Sanitizes slot content"
173
+ },
174
+ {
175
+ "tagName": "af-components\\cultural-card",
176
+ "filePath": "components\\cultural-card.js",
177
+ "slots": [
178
+ "default"
179
+ ],
180
+ "attributes": {
181
+ "culture": {
182
+ "type": "string"
183
+ },
184
+ "interactive": {
185
+ "type": "string"
186
+ }
187
+ },
188
+ "events": [],
189
+ "cssCustomProperties": [],
190
+ "example": "<af-components\\cultural-card></af-components\\cultural-card>",
191
+ "securityNotes": "Sanitizes slot content"
192
+ },
193
+ {
194
+ "tagName": "af-components\\divider",
195
+ "filePath": "components\\divider.js",
196
+ "slots": [
197
+ "default"
198
+ ],
199
+ "attributes": {
200
+ "pattern": {
201
+ "type": "string"
202
+ },
203
+ "height": {
204
+ "type": "string"
205
+ },
206
+ "color": {
207
+ "type": "string"
208
+ },
209
+ "flip": {
210
+ "type": "string"
211
+ }
212
+ },
213
+ "events": [],
214
+ "cssCustomProperties": [],
215
+ "example": "<af-components\\divider></af-components\\divider>",
216
+ "securityNotes": "Sanitizes slot content"
217
+ },
218
+ {
219
+ "tagName": "af-components\\dropdown",
220
+ "filePath": "components\\dropdown.js",
221
+ "slots": [
222
+ "default"
223
+ ],
224
+ "attributes": {
225
+ "label": {
226
+ "type": "string"
227
+ },
228
+ "open": {
229
+ "type": "string"
230
+ }
231
+ },
232
+ "events": [],
233
+ "cssCustomProperties": [],
234
+ "example": "<af-components\\dropdown></af-components\\dropdown>",
235
+ "securityNotes": "Sanitizes slot content"
236
+ },
237
+ {
238
+ "tagName": "af-components\\error-boundary",
239
+ "filePath": "components\\error-boundary.js",
240
+ "slots": [
241
+ "default"
242
+ ],
243
+ "attributes": {
244
+ "theme": {
245
+ "type": "string"
246
+ },
247
+ "fallback-message": {
248
+ "type": "string"
249
+ }
250
+ },
251
+ "events": [],
252
+ "cssCustomProperties": [],
253
+ "example": "<af-components\\error-boundary></af-components\\error-boundary>",
254
+ "securityNotes": "Sanitizes slot content"
255
+ },
256
+ {
257
+ "tagName": "af-components\\form",
258
+ "filePath": "components\\form.js",
259
+ "slots": [
260
+ "default"
261
+ ],
262
+ "attributes": {
263
+ "action": {
264
+ "type": "string"
265
+ },
266
+ "method": {
267
+ "type": "string"
268
+ },
269
+ "error": {
270
+ "type": "string"
271
+ },
272
+ "success": {
273
+ "type": "string"
274
+ },
275
+ "schema": {
276
+ "type": "string"
277
+ }
278
+ },
279
+ "events": [],
280
+ "cssCustomProperties": [],
281
+ "example": "<af-components\\form></af-components\\form>",
282
+ "securityNotes": "Sanitizes slot content"
283
+ },
284
+ {
285
+ "tagName": "af-components\\grid",
286
+ "filePath": "components\\grid.js",
287
+ "slots": [
288
+ "default"
289
+ ],
290
+ "attributes": {
291
+ "min-width": {
292
+ "type": "string"
293
+ },
294
+ "gap": {
295
+ "type": "string"
296
+ },
297
+ "columns": {
298
+ "type": "string"
299
+ },
300
+ "rows": {
301
+ "type": "string"
302
+ },
303
+ "layout": {
304
+ "type": "string"
305
+ },
306
+ "align": {
307
+ "type": "string"
308
+ },
309
+ "justify": {
310
+ "type": "string"
311
+ },
312
+ "dense": {
313
+ "type": "string"
314
+ },
315
+ "sidebar-side": {
316
+ "type": "string"
317
+ },
318
+ "sidebar-width": {
319
+ "type": "string"
320
+ },
321
+ "": {
322
+ "type": "string"
323
+ }
324
+ },
325
+ "events": [],
326
+ "cssCustomProperties": [],
327
+ "example": "<af-components\\grid></af-components\\grid>",
328
+ "securityNotes": "Sanitizes slot content"
329
+ },
330
+ {
331
+ "tagName": "af-components\\hero",
332
+ "filePath": "components\\hero.js",
333
+ "slots": [
334
+ "default"
335
+ ],
336
+ "attributes": {
337
+ "title": {
338
+ "type": "string"
339
+ },
340
+ "subtitle": {
341
+ "type": "string"
342
+ },
343
+ "pattern": {
344
+ "type": "string"
345
+ },
346
+ "overlay": {
347
+ "type": "string"
348
+ }
349
+ },
350
+ "events": [],
351
+ "cssCustomProperties": [],
352
+ "example": "<af-components\\hero></af-components\\hero>",
353
+ "securityNotes": "Sanitizes slot content"
354
+ },
355
+ {
356
+ "tagName": "af-components\\icon",
357
+ "filePath": "components\\icon.js",
358
+ "slots": [
359
+ "default"
360
+ ],
361
+ "attributes": {
362
+ "name": {
363
+ "type": "string"
364
+ },
365
+ "size": {
366
+ "type": "string"
367
+ }
368
+ },
369
+ "events": [],
370
+ "cssCustomProperties": [],
371
+ "example": "<af-components\\icon></af-components\\icon>",
372
+ "securityNotes": "Sanitizes slot content"
373
+ },
374
+ {
375
+ "tagName": "af-components\\input",
376
+ "filePath": "components\\input.js",
377
+ "slots": [
378
+ "default"
379
+ ],
380
+ "attributes": {
381
+ "type": {
382
+ "type": "string"
383
+ },
384
+ "name": {
385
+ "type": "string"
386
+ },
387
+ "label": {
388
+ "type": "string"
389
+ },
390
+ "placeholder": {
391
+ "type": "string"
392
+ },
393
+ "error": {
394
+ "type": "string"
395
+ },
396
+ "helper": {
397
+ "type": "string"
398
+ },
399
+ "theme": {
400
+ "type": "string"
401
+ },
402
+ "icon": {
403
+ "type": "string"
404
+ },
405
+ "required": {
406
+ "type": "string"
407
+ },
408
+ "aria-label": {
409
+ "type": "string"
410
+ },
411
+ "aria-describedby": {
412
+ "type": "string"
413
+ },
414
+ "validation": {
415
+ "type": "string"
416
+ }
417
+ },
418
+ "events": [],
419
+ "cssCustomProperties": [],
420
+ "example": "<af-components\\input></af-components\\input>",
421
+ "securityNotes": "Sanitizes slot content"
422
+ },
423
+ {
424
+ "tagName": "af-components\\kanga-card",
425
+ "filePath": "components\\kanga-card.js",
426
+ "slots": [
427
+ "default"
428
+ ],
429
+ "attributes": {
430
+ "theme": {
431
+ "type": "string"
432
+ },
433
+ "proverb": {
434
+ "type": "string"
435
+ },
436
+ "proverb-translation": {
437
+ "type": "string"
438
+ }
439
+ },
440
+ "events": [],
441
+ "cssCustomProperties": [],
442
+ "example": "<af-components\\kanga-card></af-components\\kanga-card>",
443
+ "securityNotes": "Sanitizes slot content"
444
+ },
445
+ {
446
+ "tagName": "af-components\\language-switcher",
447
+ "filePath": "components\\language-switcher.js",
448
+ "slots": [
449
+ "default"
450
+ ],
451
+ "attributes": {
452
+ "current": {
453
+ "type": "string"
454
+ }
455
+ },
456
+ "events": [],
457
+ "cssCustomProperties": [],
458
+ "example": "<af-components\\language-switcher></af-components\\language-switcher>",
459
+ "securityNotes": "Sanitizes slot content"
460
+ },
461
+ {
462
+ "tagName": "af-components\\loader",
463
+ "filePath": "components\\loader.js",
464
+ "slots": [
465
+ "default"
466
+ ],
467
+ "attributes": {
468
+ "size": {
469
+ "type": "string"
470
+ },
471
+ "color": {
472
+ "type": "string"
473
+ },
474
+ "type": {
475
+ "type": "string"
476
+ }
477
+ },
478
+ "events": [],
479
+ "cssCustomProperties": [],
480
+ "example": "<af-components\\loader></af-components\\loader>",
481
+ "securityNotes": "Sanitizes slot content"
482
+ },
483
+ {
484
+ "tagName": "af-components\\modal",
485
+ "filePath": "components\\modal.js",
486
+ "slots": [
487
+ "default"
488
+ ],
489
+ "attributes": {
490
+ "open": {
491
+ "type": "string"
492
+ },
493
+ "theme": {
494
+ "type": "string"
495
+ },
496
+ "size": {
497
+ "type": "string"
498
+ },
499
+ "aria-label": {
500
+ "type": "string"
501
+ },
502
+ "aria-labelledby": {
503
+ "type": "string"
504
+ }
505
+ },
506
+ "events": [],
507
+ "cssCustomProperties": [],
508
+ "example": "<af-components\\modal></af-components\\modal>",
509
+ "securityNotes": "Sanitizes slot content"
510
+ },
511
+ {
512
+ "tagName": "af-components\\motion",
513
+ "filePath": "components\\motion.js",
514
+ "slots": [
515
+ "default"
516
+ ],
517
+ "attributes": {
518
+ "animate": {
519
+ "type": "string"
520
+ },
521
+ "transition": {
522
+ "type": "string"
523
+ }
524
+ },
525
+ "events": [],
526
+ "cssCustomProperties": [],
527
+ "example": "<af-components\\motion></af-components\\motion>",
528
+ "securityNotes": "Sanitizes slot content"
529
+ },
530
+ {
531
+ "tagName": "af-components\\navbar",
532
+ "filePath": "components\\navbar.js",
533
+ "slots": [
534
+ "default"
535
+ ],
536
+ "attributes": {
537
+ "theme": {
538
+ "type": "string"
539
+ },
540
+ "logo": {
541
+ "type": "string"
542
+ },
543
+ "sticky": {
544
+ "type": "string"
545
+ }
546
+ },
547
+ "events": [],
548
+ "cssCustomProperties": [],
549
+ "example": "<af-components\\navbar></af-components\\navbar>",
550
+ "securityNotes": "Sanitizes slot content"
551
+ },
552
+ {
553
+ "tagName": "af-components\\pattern-showcase",
554
+ "filePath": "components\\pattern-showcase.js",
555
+ "slots": [
556
+ "default"
557
+ ],
558
+ "attributes": {
559
+ "region": {
560
+ "type": "string"
561
+ },
562
+ "size": {
563
+ "type": "string"
564
+ }
565
+ },
566
+ "events": [],
567
+ "cssCustomProperties": [],
568
+ "example": "<af-components\\pattern-showcase></af-components\\pattern-showcase>",
569
+ "securityNotes": "Sanitizes slot content"
570
+ },
571
+ {
572
+ "tagName": "af-components\\progress",
573
+ "filePath": "components\\progress.js",
574
+ "slots": [
575
+ "default"
576
+ ],
577
+ "attributes": {
578
+ "value": {
579
+ "type": "string"
580
+ },
581
+ "max": {
582
+ "type": "string"
583
+ },
584
+ "theme": {
585
+ "type": "string"
586
+ },
587
+ "size": {
588
+ "type": "string"
589
+ },
590
+ "label": {
591
+ "type": "string"
592
+ },
593
+ "animated": {
594
+ "type": "string"
595
+ }
596
+ },
597
+ "events": [],
598
+ "cssCustomProperties": [],
599
+ "example": "<af-components\\progress></af-components\\progress>",
600
+ "securityNotes": "Sanitizes slot content"
601
+ },
602
+ {
603
+ "tagName": "af-components\\react",
604
+ "filePath": "components\\react.js",
605
+ "slots": [
606
+ "default"
607
+ ],
608
+ "attributes": {
609
+ "component": {
610
+ "type": "string"
611
+ }
612
+ },
613
+ "events": [],
614
+ "cssCustomProperties": [],
615
+ "example": "<af-components\\react></af-components\\react>",
616
+ "securityNotes": "Sanitizes slot content"
617
+ },
618
+ {
619
+ "tagName": "af-components\\section",
620
+ "filePath": "components\\section.js",
621
+ "slots": [
622
+ "default"
623
+ ],
624
+ "attributes": {},
625
+ "events": [],
626
+ "cssCustomProperties": [],
627
+ "example": "<af-components\\section></af-components\\section>",
628
+ "securityNotes": "Sanitizes slot content"
629
+ },
630
+ {
631
+ "tagName": "af-components\\select",
632
+ "filePath": "components\\select.js",
633
+ "slots": [
634
+ "default"
635
+ ],
636
+ "attributes": {
637
+ "label": {
638
+ "type": "string"
639
+ },
640
+ "placeholder": {
641
+ "type": "string"
642
+ },
643
+ "theme": {
644
+ "type": "string"
645
+ },
646
+ "error": {
647
+ "type": "string"
648
+ },
649
+ "required": {
650
+ "type": "string"
651
+ },
652
+ "aria-label": {
653
+ "type": "string"
654
+ },
655
+ "aria-describedby": {
656
+ "type": "string"
657
+ }
658
+ },
659
+ "events": [],
660
+ "cssCustomProperties": [],
661
+ "example": "<af-components\\select></af-components\\select>",
662
+ "securityNotes": "Sanitizes slot content"
663
+ },
664
+ {
665
+ "tagName": "af-components\\sidebar",
666
+ "filePath": "components\\sidebar.js",
667
+ "slots": [
668
+ "default"
669
+ ],
670
+ "attributes": {
671
+ "position": {
672
+ "type": "string"
673
+ }
674
+ },
675
+ "events": [],
676
+ "cssCustomProperties": [],
677
+ "example": "<af-components\\sidebar></af-components\\sidebar>",
678
+ "securityNotes": "Sanitizes slot content"
679
+ },
680
+ {
681
+ "tagName": "af-components\\skeleton",
682
+ "filePath": "components\\skeleton.js",
683
+ "slots": [
684
+ "default"
685
+ ],
686
+ "attributes": {
687
+ "variant": {
688
+ "type": "string"
689
+ },
690
+ "width": {
691
+ "type": "string"
692
+ },
693
+ "height": {
694
+ "type": "string"
695
+ },
696
+ "lines": {
697
+ "type": "string"
698
+ }
699
+ },
700
+ "events": [],
701
+ "cssCustomProperties": [],
702
+ "example": "<af-components\\skeleton></af-components\\skeleton>",
703
+ "securityNotes": "Sanitizes slot content"
704
+ },
705
+ {
706
+ "tagName": "af-components\\table",
707
+ "filePath": "components\\table.js",
708
+ "slots": [
709
+ "default"
710
+ ],
711
+ "attributes": {
712
+ "theme": {
713
+ "type": "string"
714
+ },
715
+ "striped": {
716
+ "type": "string"
717
+ },
718
+ "hoverable": {
719
+ "type": "string"
720
+ }
721
+ },
722
+ "events": [],
723
+ "cssCustomProperties": [],
724
+ "example": "<af-components\\table></af-components\\table>",
725
+ "securityNotes": "Sanitizes slot content"
726
+ },
727
+ {
728
+ "tagName": "af-components\\tabs",
729
+ "filePath": "components\\tabs.js",
730
+ "slots": [
731
+ "default"
732
+ ],
733
+ "attributes": {
734
+ "theme": {
735
+ "type": "string"
736
+ }
737
+ },
738
+ "events": [],
739
+ "cssCustomProperties": [],
740
+ "example": "<af-components\\tabs></af-components\\tabs>",
741
+ "securityNotes": "Sanitizes slot content"
742
+ },
743
+ {
744
+ "tagName": "af-components\\theme-toggle",
745
+ "filePath": "components\\theme-toggle.js",
746
+ "slots": [
747
+ "default"
748
+ ],
749
+ "attributes": {},
750
+ "events": [],
751
+ "cssCustomProperties": [],
752
+ "example": "<af-components\\theme-toggle></af-components\\theme-toggle>",
753
+ "securityNotes": "Sanitizes slot content"
754
+ },
755
+ {
756
+ "tagName": "af-components\\toast",
757
+ "filePath": "components\\toast.js",
758
+ "slots": [
759
+ "default"
760
+ ],
761
+ "attributes": {
762
+ "type": {
763
+ "type": "string"
764
+ },
765
+ "message": {
766
+ "type": "string"
767
+ },
768
+ "duration": {
769
+ "type": "string"
770
+ }
771
+ },
772
+ "events": [],
773
+ "cssCustomProperties": [],
774
+ "example": "<af-components\\toast></af-components\\toast>",
775
+ "securityNotes": "Sanitizes slot content"
776
+ },
777
+ {
778
+ "tagName": "af-components\\tooltip",
779
+ "filePath": "components\\tooltip.js",
780
+ "slots": [
781
+ "default"
782
+ ],
783
+ "attributes": {
784
+ "text": {
785
+ "type": "string"
786
+ },
787
+ "position": {
788
+ "type": "string"
789
+ }
790
+ },
791
+ "events": [],
792
+ "cssCustomProperties": [],
793
+ "example": "<af-components\\tooltip></af-components\\tooltip>",
794
+ "securityNotes": "Sanitizes slot content"
795
+ }
796
+ ],
797
+ "forbiddenPatterns": [
798
+ "eval()",
799
+ "innerHTML = userInput",
800
+ "fetch without CORS headers",
801
+ "localStorage for sensitive data"
802
+ ]
803
+ }
@@ -173,57 +173,6 @@ export class LipaNambaJourney extends EventEmitter {
173
173
  expiresIn: this.regulatoryLimits.sessionTimeout / 1000
174
174
  };
175
175
  }
176
- const schema = z.object({
177
- merchantId: z.string().min(1),
178
- customerPhone: z.string().regex(/^255\d{9}$/), // Tanzanian format
179
- amount: z.number().positive(),
180
- description: z.string().min(1),
181
- reference: z.string().optional(),
182
- callbackUrl: z.string().url().optional()
183
- });
184
-
185
- const validated = schema.parse(request);
186
-
187
- // Check merchant limits
188
- const merchantStatus = await this._checkMerchantLimits(
189
- validated.merchantId,
190
- validated.amount
191
- );
192
-
193
- if (!merchantStatus.ok) {
194
- return {
195
- ok: false,
196
- error: merchantStatus.error,
197
- code: 'MERCHANT_LIMIT_EXCEEDED'
198
- };
199
- }
200
-
201
- // Generate payment request ID
202
- const paymentRequestId = this._generatePaymentId();
203
-
204
- // Store payment request
205
- const paymentRequest = {
206
- id: paymentRequestId,
207
- merchantId: validated.merchantId,
208
- customerPhone: validated.customerPhone,
209
- amount: validated.amount,
210
- description: validated.description,
211
- reference: validated.reference || paymentRequestId,
212
- status: 'INITIATED',
213
- createdAt: new Date(),
214
- expiresAt: new Date(Date.now() + 30 * 60 * 1000), // 30 min expiry
215
- callbackUrl: validated.callbackUrl
216
- };
217
-
218
- await this._storePaymentRequest(paymentRequest);
219
-
220
- return {
221
- ok: true,
222
- paymentRequestId,
223
- redirectUrl: `https://lipa.example.com/pay/${paymentRequestId}`,
224
- expiresIn: 30 * 60 // seconds
225
- };
226
- }
227
176
 
228
177
  /**
229
178
  * Step 2: Customer Identification (via Prompt)
@@ -1,6 +1,6 @@
1
1
  {
2
- "timestamp": "2026-05-02T10:56:51.519Z",
3
- "version": "5.0.0",
2
+ "timestamp": "2026-05-02T15:45:08.414Z",
3
+ "version": "5.0.1",
4
4
  "bundles": {
5
5
  "core": {
6
6
  "file": "africode.js",
@@ -19,5 +19,5 @@
19
19
  ]
20
20
  }
21
21
  },
22
- "buildTime": "3316.57ms"
22
+ "buildTime": "2018.90ms"
23
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@africode/core",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Bun-native full-stack framework with generative AI, fintech compliance, and real-time performance - built for Tanzanian digital economy",
5
5
  "module": "src/index.ts",
6
6
  "main": "src/index.ts",
@@ -105,6 +105,8 @@
105
105
  "templates",
106
106
  "dist",
107
107
  "AFRICODE_FRAMEWORK_GUIDE.md",
108
- "docs/IDE-Guide.md"
108
+ "docs/IDE-Guide.md",
109
+ "COMPONENT_SCHEMA.json",
110
+ "scripts/generate-component-schema.js"
109
111
  ]
110
112
  }
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Component Schema Generator
5
+ * Generates COMPONENT_SCHEMA.json from component files
6
+ * Run with: bun run scripts/generate-component-schema.js
7
+ */
8
+
9
+ import { readdirSync, readFileSync, writeFileSync } from 'fs';
10
+ import { join, extname } from 'path';
11
+
12
+ const COMPONENTS_DIR = 'components';
13
+ const OUTPUT_FILE = 'COMPONENT_SCHEMA.json';
14
+
15
+ function parseComponentFile(filePath) {
16
+ const content = readFileSync(filePath, 'utf8');
17
+ const fileName = filePath.split('/').pop().replace('.js', '');
18
+
19
+ // Extract class name
20
+ const classMatch = content.match(/export class (\w+)/);
21
+ const className = classMatch ? classMatch[1] : fileName.charAt(0).toUpperCase() + fileName.slice(1) + 'Component';
22
+
23
+ // Extract observed attributes
24
+ const attrMatch = content.match(/observedAttributes\(\) \{\s*return \[([^\]]+)\]/);
25
+ const attributes = attrMatch ? attrMatch[1].split(',').map(attr => attr.trim().replace(/['"]/g, '')) : [];
26
+
27
+ // Generate tag name
28
+ const tagName = `af-${fileName.replace(/([A-Z])/g, '-$1').toLowerCase()}`;
29
+
30
+ // Basic schema structure
31
+ const component = {
32
+ tagName,
33
+ className,
34
+ filePath,
35
+ slots: ["default"], // Default slot
36
+ attributes: {},
37
+ events: [],
38
+ cssCustomProperties: [],
39
+ example: `<${tagName}></${tagName}>`,
40
+ securityNotes: "Sanitizes slot content"
41
+ };
42
+
43
+ // Add attributes
44
+ attributes.forEach(attr => {
45
+ component.attributes[attr] = { type: "string" };
46
+ });
47
+
48
+ // Add common events
49
+ if (attributes.includes('disabled') || attributes.includes('loading')) {
50
+ component.events.push({ name: "click", detail: { type: "object" } });
51
+ }
52
+
53
+ return component;
54
+ }
55
+
56
+ function generateSchema() {
57
+ const componentFiles = readdirSync(COMPONENTS_DIR)
58
+ .filter(file => extname(file) === '.js' && file !== 'index.js' && file !== 'base.js');
59
+
60
+ const components = componentFiles.map(file => {
61
+ const filePath = join(COMPONENTS_DIR, file);
62
+ return parseComponentFile(filePath);
63
+ });
64
+
65
+ const schema = {
66
+ version: "5.0.0",
67
+ timestamp: new Date().toISOString(),
68
+ components,
69
+ forbiddenPatterns: [
70
+ "eval()",
71
+ "innerHTML = userInput",
72
+ "fetch without CORS headers",
73
+ "localStorage for sensitive data"
74
+ ]
75
+ };
76
+
77
+ writeFileSync(OUTPUT_FILE, JSON.stringify(schema, null, 2));
78
+ }
79
+
80
+ generateSchema();