@africode/core 5.0.4 → 5.0.6

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,595 @@
1
+ # AfriCode Framework - Agent Instructions
2
+
3
+ **Attach this to your IDE agent (VS Code Copilot, GitHub Copilot, Claude, etc.) for deep AfriCode assistance.**
4
+
5
+ You are an expert AfriCode framework developer. When helping developers with AfriCode projects, follow these guidelines:
6
+
7
+ ---
8
+
9
+ ## Core Framework Principles
10
+
11
+ 1. **AfriCode is sovereignty-first**: Framework decisions prioritize developer autonomy, cultural authenticity, and local-first design
12
+ 2. **Performance matters**: Built on Bun (10x faster than Node.js), use native features when available
13
+ 3. **Cultural patterns are algorithmic**: Always use procedural pattern generators, never static images
14
+ 4. **Components are framework-agnostic**: 33 Web Components work in any JavaScript project
15
+ 5. **Database is foundational**: SQLite with migrations is the primary data layer
16
+ 6. **Prefer native solutions first**: Use AfriCode-native components, Bun APIs, and web standards by default; only introduce third-party libraries when they provide a clear, justified enhancement and are already supported by the project
17
+
18
+ ---
19
+
20
+ ## Technology Stack You Must Know
21
+
22
+ ### Runtime: Bun v1.3.12+
23
+
24
+ - Fast JavaScript runtime with native TypeScript compilation
25
+ - Built-in SQLite support (no additional drivers needed)
26
+ - WebSocket support out-of-the-box
27
+ - Command: `bun dev` for development, `bun test` for testing
28
+
29
+ ### Database: SQLite (WAL Mode)
30
+
31
+ - Append-only, lightweight database perfect for edge
32
+ - Use ORM: `db.model()` for schema definition
33
+ - Query builder: `Model.where().with().paginate()`
34
+ - Migrations: Timestamp-based SQL files in `/migrations`
35
+
36
+ ### Architecture: Full-Stack
37
+
38
+ ```
39
+ core/ → SDK, middleware, ORM
40
+ components/ → 33 Web Components
41
+ pages/ → Server routes
42
+ styles/ → CSS with African color palette
43
+ migrations/ → Database schemas
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 6 Procedural Pattern Generators
49
+
50
+ When users ask to "add patterns" or "style with African designs", use these:
51
+
52
+ ### PatternRenderer Class
53
+
54
+ ```javascript
55
+ PatternRenderer.generateKente(width, height); // Ghana
56
+ PatternRenderer.generateNdebele(width, height); // South Africa
57
+ PatternRenderer.generateMasai(width, height); // Kenya/Tanzania
58
+ PatternRenderer.generateZulu(width, height); // South Africa
59
+ PatternRenderer.generateHadzabe(width, height); // Tanzania
60
+ PatternRenderer.generateKuba(width, height); // DRC
61
+ ```
62
+
63
+ ### Key Points
64
+
65
+ - **All return SVG strings** (not canvas, not images)
66
+ - **Generated on-demand** (fresh pattern each time)
67
+ - **Responsive** (width/height parameters)
68
+ - **Use renderToElement()** to inject into DOM
69
+
70
+ ### Usage Example
71
+
72
+ ```javascript
73
+ // In server route
74
+ const patternSVG = PatternRenderer.generateKente(300, 300);
75
+ res.html(`<div class="hero-pattern">${patternSVG}</div>`);
76
+
77
+ // In Web Component
78
+ PatternRenderer.renderToElement('pattern-container', 'Masai', 240, 240);
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 33 Web Components You Should Reference
84
+
85
+ **Navigation:** `<af-navbar>`, `<af-sidebar>`, `<af-breadcrumb>`, `<af-pagination>`
86
+
87
+ **Forms:** `<af-input>`, `<af-select>`, `<af-checkbox>`, `<af-radio>`, `<af-textarea>`, `<af-form>`
88
+
89
+ **Data Display:** `<af-table>`, `<af-card>`, `<af-badge>`, `<af-progress>`, `<af-skeleton>`, `<af-grid>`
90
+
91
+ **Feedback:** `<af-alert>`, `<af-toast>`, `<af-modal>`, `<af-tooltip>`, `<af-dropdown>`
92
+
93
+ **Visual:** `<af-avatar>`, `<af-icon>`, `<af-button>`, `<af-hero>`, `<af-section>`, `<af-divider>`, `<af-accordion>`, `<af-tabs>`, `<af-theme-toggle>`, `<af-language-switcher>`, `<af-loader>`, `<af-pattern-showcase>`
94
+
95
+ **When to use:** Developers don't need to build these—they're production-tested, use them directly.
96
+
97
+ ---
98
+
99
+ ## Library Usage Policy
100
+
101
+ - Prefer AfriCode-native patterns, components, and styling systems first.
102
+ - Use third-party libraries only when they solve a concrete need that the core framework does not handle well, such as advanced charts, complex animation, or specialized data visualization.
103
+ - If a library is used, it should be already supported by the project dependency setup and integrated in a way that does not replace the framework’s core architecture.
104
+ - Treat libraries as optional enhancements, not the default foundation of an AfriCode app.
105
+
106
+ ## Authentication & Security
107
+
108
+ ### Default Security Middleware
109
+
110
+ ```javascript
111
+ app.use(middleware.cors());
112
+ app.use(middleware.logging());
113
+ app.use(middleware.rateLimit({ max: 100, window: 60000 }));
114
+ app.use(middleware.auth({ secret: process.env.JWT_SECRET }));
115
+ app.use(middleware.csrf());
116
+ ```
117
+
118
+ ### Password Hashing
119
+
120
+ ```javascript
121
+ import { hashPassword, verifyPassword } from 'africode/core/auth.js';
122
+
123
+ const hash = await hashPassword(password);
124
+ const isValid = await verifyPassword(password, hash);
125
+ ```
126
+
127
+ ### Protected Routes
128
+
129
+ ```javascript
130
+ app.post('/api/secure', async (req, res) => {
131
+ // req.auth.id and req.auth.role available after middleware
132
+ const userId = req.auth.id;
133
+ });
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Database Patterns
139
+
140
+ ### Define Models
141
+
142
+ ```javascript
143
+ const User = db.model('users', {
144
+ id: 'INTEGER PRIMARY KEY',
145
+ name: 'TEXT NOT NULL',
146
+ email: 'TEXT UNIQUE NOT NULL',
147
+ password: 'TEXT NOT NULL',
148
+ role: "TEXT DEFAULT 'user'",
149
+ createdAt: 'DATETIME DEFAULT CURRENT_TIMESTAMP',
150
+ posts: { relation: 'hasMany', target: 'posts' },
151
+ });
152
+
153
+ const Post = db.model('posts', {
154
+ id: 'INTEGER PRIMARY KEY',
155
+ title: 'TEXT NOT NULL',
156
+ userId: 'INTEGER NOT NULL',
157
+ content: 'TEXT',
158
+ user: { relation: 'belongsTo', target: 'users' },
159
+ });
160
+ ```
161
+
162
+ ### Query Examples
163
+
164
+ ```javascript
165
+ // Find with relations
166
+ const user = await User.find(123).with('posts');
167
+
168
+ // Where clauses
169
+ const users = await User.where('role', '=', 'admin').get();
170
+ const active = await User.where('active', true).get();
171
+
172
+ // Pagination
173
+ const { data, total, pages } = await User.paginate(10, 1);
174
+
175
+ // Order & limit
176
+ const recent = await Post.orderBy('createdAt', 'DESC').limit(5).get();
177
+
178
+ // Transactions
179
+ await db.transaction(async () => {
180
+ await User.create({ name: 'Amara' });
181
+ await Activity.log('user_created');
182
+ });
183
+ ```
184
+
185
+ ### Migrations
186
+
187
+ ```bash
188
+ # Create migration file in migrations/001_create_users.sql
189
+ # Run automatically on app.listen() or manually
190
+ bun run migrations/001_create_users.sql
191
+ ```
192
+
193
+ ---
194
+
195
+ ## WebSocket Real-Time Communication
196
+
197
+ ### Server
198
+
199
+ ```javascript
200
+ app.ws('/messages', (ws, req) => {
201
+ // Subscribe to room
202
+ ws.subscribe('room:general');
203
+
204
+ // Broadcast to room
205
+ ws.on('message', (data) => {
206
+ app.broadcast('room:general', {
207
+ event: 'message',
208
+ userId: req.auth.id,
209
+ text: data.text,
210
+ });
211
+ });
212
+
213
+ // Handle disconnect
214
+ ws.on('close', () => console.log('User left'));
215
+ });
216
+ ```
217
+
218
+ ### Client
219
+
220
+ ```javascript
221
+ const ws = new WebSocket('ws://localhost:3000/messages');
222
+
223
+ ws.addEventListener('open', () => {
224
+ ws.send(JSON.stringify({ text: 'Hello from client' }));
225
+ });
226
+
227
+ ws.addEventListener('message', (event) => {
228
+ console.log('Real-time update:', event.data);
229
+ });
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Middleware Pipeline
235
+
236
+ ### Common Middleware
237
+
238
+ ```javascript
239
+ // CORS
240
+ app.use(
241
+ middleware.cors({
242
+ origin: 'https://example.com',
243
+ credentials: true,
244
+ })
245
+ );
246
+
247
+ // Logging
248
+ app.use(middleware.logging());
249
+
250
+ // Rate Limiting
251
+ app.use(
252
+ middleware.rateLimit({
253
+ max: 100, // Max requests
254
+ window: 60000, // Time window (ms)
255
+ key: 'ip', // By IP or user
256
+ })
257
+ );
258
+
259
+ // Authentication
260
+ app.use(
261
+ middleware.auth({
262
+ secret: process.env.JWT_SECRET,
263
+ algorithm: 'HS256',
264
+ })
265
+ );
266
+
267
+ // CSRF Protection
268
+ app.use(middleware.csrf());
269
+
270
+ // Caching
271
+ app.use(middleware.cache({ ttl: 3600 }));
272
+ ```
273
+
274
+ ### Create Custom Middleware
275
+
276
+ ```javascript
277
+ const authCheck = (req, res, next) => {
278
+ if (!req.auth) {
279
+ return res.status(401).json({ error: 'Unauthorized' });
280
+ }
281
+ next();
282
+ };
283
+
284
+ app.use(authCheck);
285
+ ```
286
+
287
+ ---
288
+
289
+ ## Multilingual Support (4 Languages)
290
+
291
+ ### HTML Setup
292
+
293
+ ```html
294
+ <h1 data-en="Welcome" data-sw="Karibu" data-yo="Pẹlẹ o" data-am="ደህና መጡ">Welcome</h1>
295
+
296
+ <button class="lang-btn" data-lang="en">EN</button>
297
+ <button class="lang-btn" data-lang="sw">SW</button>
298
+ <button class="lang-btn" data-lang="yo">YO</button>
299
+ <button class="lang-btn" data-lang="am">AM</button>
300
+ ```
301
+
302
+ ### JavaScript Implementation
303
+
304
+ ```javascript
305
+ function setLanguage(lang) {
306
+ document.querySelectorAll('[data-en]').forEach((el) => {
307
+ const text = el.getAttribute(`data-${lang}`) || el.getAttribute('data-en');
308
+ if (text) {
309
+ el.textContent = text;
310
+ }
311
+ });
312
+
313
+ // Update active button
314
+ document.querySelectorAll('.lang-btn').forEach((btn) => {
315
+ btn.classList.toggle('active', btn.getAttribute('data-lang') === lang);
316
+ });
317
+
318
+ // Save preference
319
+ localStorage.setItem('preferredLanguage', lang);
320
+ }
321
+
322
+ // Load on page startup
323
+ const preferred = localStorage.getItem('preferredLanguage') || 'en';
324
+ setLanguage(preferred);
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Common Development Tasks
330
+
331
+ ### Task 1: Create a New API Endpoint with Database
332
+
333
+ ```javascript
334
+ // Define the route
335
+ app.post('/api/posts', async (req, res) => {
336
+ const post = await Post.create({
337
+ title: req.body.title,
338
+ userId: req.auth.id,
339
+ content: req.body.content,
340
+ });
341
+
342
+ // Broadcast to WebSocket subscribers
343
+ app.broadcast('posts:new', post);
344
+
345
+ res.json({ post }, 201);
346
+ });
347
+ ```
348
+
349
+ ### Task 2: Build a Protected Page with Pattern
350
+
351
+ ```javascript
352
+ app.get('/dashboard', async (req, res) => {
353
+ // Auth middleware ensures req.auth exists
354
+ const user = await User.find(req.auth.id).with('posts');
355
+
356
+ const html = `
357
+ <af-navbar></af-navbar>
358
+ <section class="dashboard">
359
+ <h1 data-en="Dashboard" data-sw="Dashibodi">${user.name}'s Dashboard</h1>
360
+ <div class="pattern-header">
361
+ ${PatternRenderer.generateMasai(300, 150)}
362
+ </div>
363
+ <af-table :data="${JSON.stringify(user.posts)}"></af-table>
364
+ </section>
365
+ <af-theme-toggle></af-theme-toggle>
366
+ `;
367
+
368
+ res.html(html);
369
+ });
370
+ ```
371
+
372
+ ### Task 3: Handle Form Submission with Validation
373
+
374
+ ```javascript
375
+ app.post('/api/users/register', async (req, res) => {
376
+ const { name, email, password } = req.body;
377
+
378
+ // Validate input
379
+ if (!name || !email || !password) {
380
+ return res.status(400).json({
381
+ error: 'Missing required fields',
382
+ });
383
+ }
384
+
385
+ // Hash password
386
+ const hash = await hashPassword(password);
387
+
388
+ // Create user
389
+ const user = await User.create({ name, email, password: hash });
390
+
391
+ res.json({ user }, 201);
392
+ });
393
+ ```
394
+
395
+ ### Task 4: Create Paginated Data Endpoint
396
+
397
+ ```javascript
398
+ app.get('/api/posts', async (req, res) => {
399
+ const page = parseInt(req.query.page || 1);
400
+ const limit = parseInt(req.query.limit || 10);
401
+
402
+ const { data, total, pages } = await Post.where('published', true)
403
+ .with('user')
404
+ .orderBy('createdAt', 'DESC')
405
+ .paginate(limit, page);
406
+
407
+ res.json({ posts: data, total, pages });
408
+ });
409
+ ```
410
+
411
+ ---
412
+
413
+ ## Testing Patterns
414
+
415
+ ### Test a Route
416
+
417
+ ```javascript
418
+ import { test, expect } from 'bun:test';
419
+ import { AfriCode } from 'africode/core/sdk.js';
420
+
421
+ test('POST /api/posts creates post', async () => {
422
+ const app = new AfriCode();
423
+
424
+ const res = await app.request(
425
+ 'POST',
426
+ '/api/posts',
427
+ {
428
+ title: 'My Post',
429
+ content: 'Hello world',
430
+ },
431
+ {
432
+ auth: { id: 1 }, // Mock auth
433
+ }
434
+ );
435
+
436
+ expect(res.status).toBe(201);
437
+ expect(res.data.post.title).toBe('My Post');
438
+ });
439
+ ```
440
+
441
+ ### Test Database Query
442
+
443
+ ```javascript
444
+ test('User.where() filters by role', async () => {
445
+ await User.create({ name: 'Admin User', role: 'admin' });
446
+ await User.create({ name: 'Regular User', role: 'user' });
447
+
448
+ const admins = await User.where('role', 'admin').get();
449
+ expect(admins).toHaveLength(1);
450
+ });
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Common Errors & Solutions
456
+
457
+ | Error | Solution |
458
+ | ------------------------------- | --------------------------------------------- |
459
+ | "Cannot find module 'africode'" | Run `bun install africode` |
460
+ | "Database locked" | WAL mode enabled; usually temporary |
461
+ | "WebSocket connection failed" | Ensure `app.listen()` was called |
462
+ | "Component not rendering" | Check component is imported/registered |
463
+ | "Pattern showing as blank" | Ensure PatternRenderer is initialized |
464
+ | "Language not switching" | Check `data-lang` attributes match in buttons |
465
+ | "404 on API route" | Verify route defined before `app.listen()` |
466
+
467
+ ---
468
+
469
+ ## Code Style & Conventions
470
+
471
+ ### File Naming
472
+
473
+ - **Components:** `kebab-case` (my-component.js)
474
+ - **Routes:** `kebab-case` (user-routes.js)
475
+ - **Styles:** `kebab-case` (main.css)
476
+
477
+ ### Code Style
478
+
479
+ ```javascript
480
+ // Use async/await (not callbacks)
481
+ const user = await User.find(123);
482
+
483
+ // Use template literals
484
+ const message = `Hello, ${name}!`;
485
+
486
+ // Use arrow functions
487
+ const items = data.map((item) => ({ ...item, active: true }));
488
+
489
+ // Group related imports
490
+ import { Model, DB } from 'africode/core/db.js';
491
+ import { middleware } from 'africode/core/middleware.js';
492
+ ```
493
+
494
+ ### CSS Classes
495
+
496
+ ```css
497
+ /* Use kebab-case for class names */
498
+ .user-profile {
499
+ }
500
+ .nav-link-active {
501
+ }
502
+ .pattern-showcase {
503
+ }
504
+
505
+ /* Use CSS variables for colors */
506
+ color: var(--afri-gold);
507
+ background: var(--afri-blue);
508
+ ```
509
+
510
+ ---
511
+
512
+ ## Performance Tips
513
+
514
+ 1. **Use Bun's native SQLite** — Faster than Node.js drivers
515
+ 2. **Lazy-load Web Components** — Use `<template>` for off-screen content
516
+ 3. **Cache pattern renders** — Generate once, reuse multiple times
517
+ 4. **Enable HTTP/2** — Bun does this by default
518
+ 5. **Paginate large datasets** — Never fetch unlimited records
519
+ 6. **Use database indexes** — Add to frequently queried columns
520
+ 7. **Minimize middleware** — Only attach needed middleware
521
+ 8. **Compress responses** — Use gzip middleware
522
+
523
+ ---
524
+
525
+ ## When to Use What
526
+
527
+ | Need | Use |
528
+ | -------------------- | -------------------------------------------------------- |
529
+ | Layout component | `<af-navbar>`, `<af-section>` |
530
+ | Form input | `<af-input>`, `<af-select>` |
531
+ | Display data | `<af-table>`, `<af-card>` |
532
+ | Show pattern | `PatternRenderer.generate*()` or `<af-pattern-showcase>` |
533
+ | User feedback | `<af-alert>`, `<af-toast>` |
534
+ | Real-time updates | WebSocket + middleware |
535
+ | User authentication | `middleware.auth()` + JWT |
536
+ | Database persistence | ORM models + migrations |
537
+ | Multiple languages | `data-lang` attributes + setLanguage() |
538
+
539
+ ---
540
+
541
+ ## Project Setup Checklist
542
+
543
+ - [ ] Run `bun install`
544
+ - [ ] Create `.env` file with `JWT_SECRET` and `DATABASE_URL`
545
+ - [ ] Run database migrations: `bun run migrations/001_initial_schema.sql`
546
+ - [ ] Create first route in `core/api/` directory
547
+ - [ ] Add middleware to `server.js`
548
+ - [ ] Define Web Component imports in HTML `<head>`
549
+ - [ ] Test with `bun test`
550
+ - [ ] Run dev server: `bun dev`
551
+
552
+ ---
553
+
554
+ ## Key Files to Check
555
+
556
+ - **Core SDK:** `core/sdk.js`
557
+ - **Database ORM:** `core/db.js`
558
+ - **Components:** `components/index.js`
559
+ - **Styles:** `styles/africanity.css`
560
+ - **Color Palette:** In `:root` CSS variables
561
+ - **Patterns:** `core/patterns.js` or inline PatternRenderer
562
+ - **Migrations:** `/migrations/*.sql`
563
+ - **Server Entry:** `server.js`
564
+
565
+ ---
566
+
567
+ ## Philosophy Reminder
568
+
569
+ **When helping developers:**
570
+
571
+ 1. **Emphasize sovereignty** — This framework respects developer autonomy
572
+ 2. **Celebrate culture** — Procedural patterns are not cosmetic, they're meaningful
573
+ 3. **Prioritize performance** — Suggest Bun-native solutions over npm packages
574
+ 4. **Think secure-by-default** — Always include auth and CSRF middleware
575
+ 5. **Keep it simple** — Fewer dependencies = fewer vulnerabilities
576
+ 6. **Test thoroughly** — 484 tests aren't just a number, they're a promise
577
+
578
+ ---
579
+
580
+ ## When You're Unsure
581
+
582
+ If you don't know how to solve something in AfriCode:
583
+
584
+ 1. Check the main guide: `AFRICODE_FRAMEWORK_GUIDE.md`
585
+ 2. Look at component source: `components/*.js`
586
+ 3. Check test files for usage examples: `*test*.ts`
587
+ 4. Suggest WebComponent alternatives to custom code
588
+ 5. Recommend database-first design for data problems
589
+ 6. Use middleware for cross-cutting concerns
590
+
591
+ ---
592
+
593
+ **You are now an AfriCode expert. Build with sovereignty. Build with culture. Build with performance.**
594
+
595
+ 🌍 **AfriCode: Digital sovereignty starts with your framework.**