@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
@@ -0,0 +1,799 @@
1
+ /**
2
+ * Bun-Native Runtime Engine
3
+ * Optimized runtime leveraging Bun's Zig-based architecture
4
+ *
5
+ * Provides ultra-fast startup, native APIs, and hot reloading
6
+ * capabilities for high-performance fintech applications.
7
+ *
8
+ * @module core/bun-runtime
9
+ */
10
+
11
+ import { createReactiveState } from './state.js';
12
+ import { FileBasedRouter } from './file-router.js';
13
+ import { EnhancedHMRMiddleware } from './enhanced-hmr.js';
14
+
15
+ /**
16
+ * Bun Runtime Configuration
17
+ */
18
+ export const BUN_CONFIG = {
19
+ startupTimeout: 5000, // 5ms target startup
20
+ memoryLimit: '1gb',
21
+ gcStrategy: 'generational',
22
+ threadPoolSize: 4
23
+ };
24
+
25
+ /**
26
+ * Bun HTTP Server with File-Based Routing
27
+ * Autonomous application lifecycle management
28
+ */
29
+ export class BunHTTPServer {
30
+ constructor(options = {}) {
31
+ this.options = {
32
+ port: options.port || 3000,
33
+ pagesDir: options.pagesDir || 'pages',
34
+ publicDir: options.publicDir || 'public',
35
+ middleware: options.middleware || [],
36
+ enableHMR: options.enableHMR !== false,
37
+ ...options
38
+ };
39
+
40
+ this.router = new FileBasedRouter({
41
+ pagesDir: this.options.pagesDir
42
+ });
43
+
44
+ this.server = null;
45
+ this.hmr = null;
46
+ }
47
+
48
+ /**
49
+ * Start the HTTP server
50
+ */
51
+ async start() {
52
+ console.log(`🚀 Starting Bun HTTP Server on port ${this.options.port}`);
53
+
54
+ // Initialize HMR if enabled
55
+ if (this.options.enableHMR) {
56
+ this.hmr = new EnhancedHMRMiddleware({
57
+ port: this.options.port + 1,
58
+ watchPaths: [this.options.pagesDir, 'components', 'core']
59
+ });
60
+ }
61
+
62
+ // Create Bun server with file-based routing
63
+ this.server = Bun.serve({
64
+ port: this.options.port,
65
+ async fetch(request) {
66
+ const url = new URL(request.url);
67
+ const pathname = url.pathname;
68
+
69
+ // Handle static files
70
+ if (pathname.startsWith('/public/') || pathname.startsWith('/static/')) {
71
+ return this._serveStaticFile(pathname);
72
+ }
73
+
74
+ // Handle HMR WebSocket upgrade
75
+ if (pathname === '/hmr' && this.hmr) {
76
+ const upgrade = this.hmr.handleUpgrade(request);
77
+ if (upgrade) return upgrade;
78
+ }
79
+
80
+ // Route to file-based handler
81
+ return this._handleRoute(request);
82
+ }.bind(this),
83
+
84
+ // WebSocket handling for HMR
85
+ websocket: this.hmr ? {
86
+ open: (ws) => this.hmr.handleClientConnect(ws),
87
+ message: (ws, message) => this.hmr.handleClientMessage(ws, message),
88
+ close: (ws) => this.hmr.handleClientDisconnect(ws)
89
+ } : undefined
90
+ });
91
+
92
+ // Start HMR watching
93
+ if (this.hmr) {
94
+ await this.hmr.initialize(this.server);
95
+ }
96
+
97
+ console.log(`📡 Server ready at http://localhost:${this.options.port}`);
98
+ console.log(`📊 Routes loaded:`, this.router.getRoutes());
99
+ }
100
+
101
+ /**
102
+ * Handle incoming requests with file-based routing
103
+ */
104
+ async _handleRoute(request) {
105
+ const url = new URL(request.url);
106
+ const pathname = url.pathname;
107
+ const method = request.method;
108
+
109
+ try {
110
+ // Match route
111
+ const routeMatch = this.router.matchRoute(pathname, method);
112
+
113
+ if (!routeMatch) {
114
+ return new Response('Not Found', { status: 404 });
115
+ }
116
+
117
+ // Load route handler/component
118
+ const handler = await this.router.loadRoute(routeMatch);
119
+
120
+ if (routeMatch.type === 'api') {
121
+ // Handle API route
122
+ return this._handleApiRoute(handler, request, routeMatch.params);
123
+ } else {
124
+ // Handle page route
125
+ return this._handlePageRoute(handler, request, routeMatch);
126
+ }
127
+
128
+ } catch (error) {
129
+ console.error('[Server] Route error:', error);
130
+ return new Response('Internal Server Error', { status: 500 });
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Handle API route execution
136
+ */
137
+ async _handleApiRoute(handler, request, params) {
138
+ try {
139
+ // Execute API handler
140
+ const result = await handler(request, { params });
141
+
142
+ if (result instanceof Response) {
143
+ return result;
144
+ }
145
+
146
+ // Convert to JSON response
147
+ return new Response(JSON.stringify(result), {
148
+ headers: { 'Content-Type': 'application/json' }
149
+ });
150
+
151
+ } catch (error) {
152
+ console.error('[Server] API error:', error);
153
+ return new Response(JSON.stringify({ error: error.message }), {
154
+ status: 500,
155
+ headers: { 'Content-Type': 'application/json' }
156
+ });
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Handle page route rendering
162
+ */
163
+ async _handlePageRoute(component, request, routeMatch) {
164
+ try {
165
+ // Render page component
166
+ const html = await this._renderPage(component, routeMatch);
167
+
168
+ return new Response(html, {
169
+ headers: { 'Content-Type': 'text/html' }
170
+ });
171
+
172
+ } catch (error) {
173
+ console.error('[Server] Page render error:', error);
174
+ return new Response('Render Error', { status: 500 });
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Render page with layout
180
+ */
181
+ async _renderPage(component, routeMatch) {
182
+ let content = '';
183
+
184
+ // Render component
185
+ if (typeof component === 'function') {
186
+ content = component(routeMatch.params || {});
187
+ } else if (component.render) {
188
+ content = component.render(routeMatch.params || {});
189
+ } else {
190
+ content = String(component);
191
+ }
192
+
193
+ // Apply layout if available
194
+ if (routeMatch.layout) {
195
+ try {
196
+ const layoutModule = await import(routeMatch.layout);
197
+ const layout = layoutModule.default || layoutModule;
198
+
199
+ if (typeof layout === 'function') {
200
+ content = layout({ children: content, params: routeMatch.params });
201
+ }
202
+ } catch (error) {
203
+ console.warn('[Server] Layout load error:', error.message);
204
+ }
205
+ }
206
+
207
+ // Wrap in basic HTML structure
208
+ return `<!DOCTYPE html>
209
+ <html lang="en">
210
+ <head>
211
+ <meta charset="UTF-8">
212
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
213
+ <title>AfriCode App</title>
214
+ <link rel="stylesheet" href="/public/styles.css">
215
+ </head>
216
+ <body>
217
+ ${content}
218
+ <script type="module" src="/public/app.js"></script>
219
+ </body>
220
+ </html>`;
221
+ }
222
+
223
+ /**
224
+ * Serve static files
225
+ */
226
+ _serveStaticFile(pathname) {
227
+ try {
228
+ const filePath = join(process.cwd(), pathname);
229
+ const file = Bun.file(filePath);
230
+ return new Response(file);
231
+ } catch {
232
+ return new Response('File Not Found', { status: 404 });
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Stop the server
238
+ */
239
+ async stop() {
240
+ if (this.server) {
241
+ this.server.stop();
242
+ }
243
+ if (this.hmr) {
244
+ await this.hmr.shutdown();
245
+ }
246
+ console.log('🛑 Server stopped');
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Hot Reloading Engine
252
+ * Enables zero-downtime updates with state preservation
253
+ */
254
+ export class HotReloadEngine {
255
+ constructor() {
256
+ this.modules = new Map();
257
+ this.state = createReactiveState({});
258
+ this.connections = new Set();
259
+ }
260
+
261
+ /**
262
+ * Initialize hot reloading for a module
263
+ * @param {string} moduleId - Module identifier
264
+ * @param {Function} moduleFactory - Module factory function
265
+ */
266
+ initModule(moduleId, moduleFactory) {
267
+ const module = {
268
+ id: moduleId,
269
+ factory: moduleFactory,
270
+ instance: null,
271
+ lastModified: Date.now(),
272
+ dependencies: new Set()
273
+ };
274
+
275
+ this.modules.set(moduleId, module);
276
+ this._instantiateModule(module);
277
+ return module;
278
+ }
279
+
280
+ /**
281
+ * Handle file change event
282
+ * @param {string} filePath - Changed file path
283
+ * @param {string} eventType - Change type (create, update, delete)
284
+ */
285
+ async handleFileChange(filePath, eventType) {
286
+ const moduleId = this._pathToModuleId(filePath);
287
+
288
+ if (eventType === 'delete') {
289
+ this.modules.delete(moduleId);
290
+ this._broadcastReload(moduleId, 'delete');
291
+ return;
292
+ }
293
+
294
+ // Check if module needs reloading
295
+ const module = this.modules.get(moduleId);
296
+ if (!module) return;
297
+
298
+ try {
299
+ const stats = await Bun.file(filePath).stat();
300
+ if (stats.mtime > module.lastModified) {
301
+ await this._reloadModule(moduleId);
302
+ }
303
+ } catch (error) {
304
+ console.warn('[HMR] File stat error:', error.message);
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Reload a module with state preservation
310
+ * @param {string} moduleId - Module to reload
311
+ */
312
+ async _reloadModule(moduleId) {
313
+ const module = this.modules.get(moduleId);
314
+ if (!module) return;
315
+
316
+ // Preserve current state
317
+ const oldState = module.instance?.state || {};
318
+
319
+ // Dispose old instance
320
+ if (module.instance?.dispose) {
321
+ module.instance.dispose();
322
+ }
323
+
324
+ // Reload module
325
+ try {
326
+ // Clear module cache if possible
327
+ if (typeof require !== 'undefined' && require.cache) {
328
+ delete require.cache[moduleId];
329
+ }
330
+
331
+ await this._instantiateModule(module);
332
+
333
+ // Restore state
334
+ if (module.instance?.restoreState) {
335
+ module.instance.restoreState(oldState);
336
+ }
337
+
338
+ this._broadcastReload(moduleId, 'update');
339
+ } catch (error) {
340
+ console.error('[HMR] Module reload error:', error.message);
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Instantiate a module
346
+ * @param {Object} module - Module object
347
+ */
348
+ async _instantiateModule(module) {
349
+ try {
350
+ module.instance = await module.factory();
351
+ module.lastModified = Date.now();
352
+ } catch (error) {
353
+ console.error('[HMR] Module instantiation error:', error.message);
354
+ module.instance = null;
355
+ }
356
+ return module;
357
+ }
358
+
359
+ /**
360
+ * Convert file path to module ID
361
+ * @param {string} filePath - File path
362
+ * @returns {string} Module ID
363
+ */
364
+ _pathToModuleId(filePath) {
365
+ return filePath.replace(/\\/g, '/').replace(process.cwd() + '/', '');
366
+ }
367
+
368
+ /**
369
+ * Broadcast reload event to connected clients
370
+ * @param {string} moduleId - Module ID
371
+ * @param {string} eventType - Event type
372
+ */
373
+ _broadcastReload(moduleId, eventType) {
374
+ const message = {
375
+ type: 'module-update',
376
+ moduleId,
377
+ eventType,
378
+ timestamp: Date.now()
379
+ };
380
+
381
+ for (const ws of this.connections) {
382
+ try {
383
+ ws.send(JSON.stringify(message));
384
+ } catch (error) {
385
+ this.connections.delete(ws);
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ // Import join function for static file serving
392
+ import { join } from 'path';
393
+ this.connections = new Set();
394
+ }
395
+
396
+ /**
397
+ * Initialize hot reloading for a module
398
+ * @param {string} moduleId - Module identifier
399
+ * @param {Function} moduleFactory - Module factory function
400
+ */
401
+ initModule(moduleId, moduleFactory) {
402
+ const module = {
403
+ id: moduleId,
404
+ factory: moduleFactory,
405
+ instance: null,
406
+ lastModified: Date.now(),
407
+ dependencies: new Set()
408
+ };
409
+
410
+ this.modules.set(moduleId, module);
411
+ this._instantiateModule(module);
412
+
413
+ return module;
414
+ }
415
+
416
+ /**
417
+ * Handle file change event
418
+ * @param {string} filePath - Changed file path
419
+ * @param {string} eventType - Change type (create, update, delete)
420
+ */
421
+ async handleFileChange(filePath, eventType) {
422
+ const moduleId = this._pathToModuleId(filePath);
423
+
424
+ if (eventType === 'delete') {
425
+ this.modules.delete(moduleId);
426
+ this._broadcastReload(moduleId, 'delete');
427
+ return;
428
+ }
429
+
430
+ // Check if module needs reloading
431
+ const module = this.modules.get(moduleId);
432
+ if (!module) return;
433
+
434
+ const stats = await Bun.file(filePath).stat();
435
+ if (stats.mtime > module.lastModified) {
436
+ await this._reloadModule(moduleId);
437
+ }
438
+ }
439
+
440
+ /**
441
+ * Reload a module with state preservation
442
+ * @param {string} moduleId - Module to reload
443
+ */
444
+ async _reloadModule(moduleId) {
445
+ const module = this.modules.get(moduleId);
446
+ if (!module) return;
447
+
448
+ // Preserve current state
449
+ const oldState = module.instance?.state || {};
450
+
451
+ // Dispose old instance
452
+ if (module.instance?.dispose) {
453
+ module.instance.dispose();
454
+ }
455
+
456
+ // Reload module
457
+ delete require.cache[moduleId]; // Clear Node.js cache if applicable
458
+ await this._instantiateModule(module);
459
+
460
+ // Restore state
461
+ if (module.instance?.restoreState) {
462
+ module.instance.restoreState(oldState);
463
+ }
464
+
465
+ // Update timestamp
466
+ module.lastModified = Date.now();
467
+
468
+ // Broadcast reload to clients
469
+ this._broadcastReload(moduleId, 'update');
470
+ }
471
+
472
+ /**
473
+ * Instantiate a module
474
+ * @param {Object} module - Module definition
475
+ */
476
+ async _instantiateModule(module) {
477
+ try {
478
+ module.instance = await module.factory();
479
+
480
+ // Store state for hot reload
481
+ if (module.instance) {
482
+ module.instance.state = this.state[module.id] || {};
483
+ }
484
+ } catch (error) {
485
+ console.error(`Failed to instantiate module ${module.id}:`, error);
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Broadcast reload event to connected clients
491
+ * @param {string} moduleId - Reloaded module
492
+ * @param {string} type - Reload type
493
+ */
494
+ _broadcastReload(moduleId, type) {
495
+ const message = {
496
+ type: 'hot-reload',
497
+ moduleId,
498
+ reloadType: type,
499
+ timestamp: Date.now()
500
+ };
501
+
502
+ for (const ws of this.connections) {
503
+ if (ws.readyState === WebSocket.OPEN) {
504
+ ws.send(JSON.stringify(message));
505
+ }
506
+ }
507
+ }
508
+
509
+ /**
510
+ * Add WebSocket connection for hot reload notifications
511
+ * @param {WebSocket} ws - WebSocket connection
512
+ */
513
+ addConnection(ws) {
514
+ this.connections.add(ws);
515
+
516
+ ws.on('close', () => {
517
+ this.connections.delete(ws);
518
+ });
519
+ }
520
+
521
+ /**
522
+ * Convert file path to module ID
523
+ * @param {string} filePath - File path
524
+ */
525
+ _pathToModuleId(filePath) {
526
+ return filePath.replace(/\\/g, '/').replace(/^.*\/src\//, '');
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Bun-Optimized HTTP Server
532
+ * Leveraging Bun.serve for maximum performance
533
+ */
534
+ export class BunHTTPServer {
535
+ constructor(config = {}) {
536
+ this.config = {
537
+ port: config.port || 3000,
538
+ hostname: config.hostname || 'localhost',
539
+ ...config
540
+ };
541
+
542
+ this.routes = new Map();
543
+ this.middlewares = [];
544
+ this.hotReload = new HotReloadEngine();
545
+ }
546
+
547
+ /**
548
+ * Register a route handler
549
+ * @param {string} method - HTTP method
550
+ * @param {string} path - Route path
551
+ * @param {Function} handler - Route handler
552
+ */
553
+ route(method, path, handler) {
554
+ const key = `${method}:${path}`;
555
+ this.routes.set(key, handler);
556
+ }
557
+
558
+ /**
559
+ * Add middleware
560
+ * @param {Function} middleware - Middleware function
561
+ */
562
+ use(middleware) {
563
+ this.middlewares.push(middleware);
564
+ }
565
+
566
+ /**
567
+ * Start the server
568
+ */
569
+ start() {
570
+ const server = Bun.serve({
571
+ port: this.config.port,
572
+ hostname: this.config.hostname,
573
+
574
+ async fetch(request) {
575
+ const url = new URL(request.url);
576
+ const method = request.method;
577
+ const path = url.pathname;
578
+
579
+ // Apply middlewares
580
+ let response = null;
581
+ for (const middleware of this.middlewares) {
582
+ response = await middleware(request, () => null);
583
+ if (response) break;
584
+ }
585
+
586
+ if (!response) {
587
+ // Find route handler
588
+ const key = `${method}:${path}`;
589
+ const handler = this.routes.get(key);
590
+
591
+ if (handler) {
592
+ response = await handler(request);
593
+ } else {
594
+ response = new Response('Not Found', { status: 404 });
595
+ }
596
+ }
597
+
598
+ return response;
599
+ },
600
+
601
+ websocket: {
602
+ open: (ws) => {
603
+ this.hotReload.addConnection(ws);
604
+ },
605
+
606
+ message: (ws, message) => {
607
+ // Handle WebSocket messages
608
+ console.log('WebSocket message:', message);
609
+ }
610
+ }
611
+ });
612
+
613
+ console.log(`🚀 Bun Server running on ${server.url}`);
614
+ return server;
615
+ }
616
+
617
+ /**
618
+ * Enable hot reloading
619
+ * @param {string[]} watchPaths - Paths to watch for changes
620
+ */
621
+ enableHotReload(watchPaths = ['./src']) {
622
+ // File watcher using Bun's native file watching
623
+ console.log('Hot reload not yet implemented for this Bun version');
624
+ // TODO: Implement when Bun.watch is available
625
+ /*
626
+ for (const watchPath of watchPaths) {
627
+ const watcher = Bun.watch(watchPath, {
628
+ persistent: true
629
+ });
630
+
631
+ watcher.on('change', async (event, filename) => {
632
+ await this.hotReload.handleFileChange(filename, event);
633
+ });
634
+ }
635
+ */
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Bun-Native Database Connection
641
+ * Leveraging Bun.sql for type-safe SQLite operations
642
+ */
643
+ export class BunDatabase {
644
+ constructor(dbPath = './afriCode.db') {
645
+ this.db = new Bun.sql(`${dbPath}`);
646
+
647
+ // Enable WAL mode for better concurrency
648
+ try {
649
+ this.db.query('PRAGMA journal_mode = WAL').run();
650
+ this.db.query('PRAGMA synchronous = NORMAL').run();
651
+ this.db.query('PRAGMA cache_size = 1000000').run();
652
+ } catch (e) {
653
+ // Ignore pragma errors in demo
654
+ console.warn('Database pragma setup failed:', e.message);
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Execute a query with parameters
660
+ * @param {string} sql - SQL query
661
+ * @param {Array} params - Query parameters
662
+ */
663
+ query(sql, params = []) {
664
+ try {
665
+ return this.db.query(sql).all(...params);
666
+ } catch (e) {
667
+ console.warn('Query failed:', sql, e.message);
668
+ return [];
669
+ }
670
+ }
671
+
672
+ /**
673
+ * Execute a query and get first result
674
+ * @param {string} sql - SQL query
675
+ * @param {Array} params - Query parameters
676
+ */
677
+ get(sql, params = []) {
678
+ try {
679
+ return this.db.query(sql).get(...params);
680
+ } catch (e) {
681
+ console.warn('Get query failed:', sql, e.message);
682
+ return null;
683
+ }
684
+ }
685
+
686
+ /**
687
+ * Execute a mutation query
688
+ * @param {string} sql - SQL query
689
+ * @param {Array} params - Query parameters
690
+ */
691
+ run(sql, params = []) {
692
+ try {
693
+ return this.db.query(sql).run(...params);
694
+ } catch (e) {
695
+ console.warn('Run query failed:', sql, e.message);
696
+ return null;
697
+ }
698
+ }
699
+
700
+ /**
701
+ * Execute multiple queries in a transaction
702
+ * @param {Function} callback - Transaction callback
703
+ */
704
+ transaction(callback) {
705
+ return this.db.transaction(callback)();
706
+ }
707
+
708
+ /**
709
+ * Close database connection
710
+ */
711
+ close() {
712
+ this.db.close();
713
+ }
714
+ }
715
+
716
+ /**
717
+ * Performance Monitoring
718
+ * Real-time performance metrics using Bun's high-resolution timers
719
+ */
720
+ export class PerformanceMonitor {
721
+ constructor() {
722
+ this.metrics = createReactiveState({
723
+ startupTime: 0,
724
+ requestCount: 0,
725
+ averageResponseTime: 0,
726
+ memoryUsage: 0,
727
+ activeConnections: 0
728
+ });
729
+
730
+ this.requestTimes = [];
731
+ this.startTime = performance.now();
732
+ }
733
+
734
+ /**
735
+ * Record request timing
736
+ * @param {number} duration - Request duration in ms
737
+ */
738
+ recordRequest(duration) {
739
+ this.requestTimes.push(duration);
740
+
741
+ // Keep only last 1000 requests for averaging
742
+ if (this.requestTimes.length > 1000) {
743
+ this.requestTimes.shift();
744
+ }
745
+
746
+ this.metrics.requestCount++;
747
+ this.metrics.averageResponseTime =
748
+ this.requestTimes.reduce((a, b) => a + b, 0) / this.requestTimes.length;
749
+ }
750
+
751
+ /**
752
+ * Update memory usage
753
+ */
754
+ updateMemoryUsage() {
755
+ if (typeof process !== 'undefined' && process.memoryUsage) {
756
+ this.metrics.memoryUsage = process.memoryUsage().heapUsed;
757
+ }
758
+ }
759
+
760
+ /**
761
+ * Get current metrics
762
+ */
763
+ getMetrics() {
764
+ this.updateMemoryUsage();
765
+ return { ...this.metrics };
766
+ }
767
+
768
+ /**
769
+ * Start periodic metrics collection
770
+ * @param {number} interval - Collection interval in ms
771
+ */
772
+ startCollection(interval = 5000) {
773
+ setInterval(() => {
774
+ this.updateMemoryUsage();
775
+ }, interval);
776
+ }
777
+ }
778
+
779
+ /**
780
+ * Initialize Bun-native runtime
781
+ */
782
+ export function initBunRuntime(config = {}) {
783
+ const runtime = {
784
+ server: new BunHTTPServer(config.server),
785
+ database: config.database ? new BunDatabase(config.database.path) : null,
786
+ monitor: new PerformanceMonitor(),
787
+ hotReload: new HotReloadEngine()
788
+ };
789
+
790
+ // Start performance monitoring
791
+ runtime.monitor.startCollection();
792
+
793
+ // Enable hot reloading if in development
794
+ if (config.hotReload) {
795
+ runtime.server.enableHotReload(config.hotReload.watchPaths);
796
+ }
797
+
798
+ return runtime;
799
+ }