@africode/core 5.0.0 → 5.0.2

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.
@@ -1,799 +1,282 @@
1
1
  /**
2
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.
3
+ * Phase 1: Runtime Stability - Clean and predictable server
7
4
  *
8
5
  * @module core/bun-runtime
9
6
  */
10
7
 
11
- import { createReactiveState } from './state.js';
12
- import { FileBasedRouter } from './file-router.js';
8
+ import { FileSystemRouter } from './router.js';
9
+ import { RawHtml } from './html.js';
10
+ import { getRequestIdentity } from './request-identity.js';
11
+ import { sessionStore } from './session-store.js';
12
+ import { actions } from './actions.js';
13
+ import { MiddlewareManager, loggerMiddleware } from './middleware.js';
13
14
  import { EnhancedHMRMiddleware } from './enhanced-hmr.js';
15
+ import { Database as BunSQLiteDatabase } from 'bun:sqlite';
16
+ import { extname, join } from 'path';
14
17
 
15
- /**
16
- * Bun Runtime Configuration
17
- */
18
18
  export const BUN_CONFIG = {
19
- startupTimeout: 5000, // 5ms target startup
20
- memoryLimit: '1gb',
21
- gcStrategy: 'generational',
22
- threadPoolSize: 4
19
+ startupTimeout: 5000,
20
+ memoryLimit: '1gb',
21
+ gcStrategy: 'generational',
22
+ threadPoolSize: 4
23
23
  };
24
24
 
25
- /**
26
- * Bun HTTP Server with File-Based Routing
27
- * Autonomous application lifecycle management
28
- */
29
25
  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
- }
26
+ constructor(options = {}) {
27
+ this.router = new FileSystemRouter(join(process.cwd(), options.pagesDir || 'pages'));
100
28
 
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;
29
+ this.middleware = new MiddlewareManager();
30
+ this.port = options.port || 3000;
31
+ this.server = null;
32
+ }
108
33
 
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
- }
34
+ async start() {
35
+ // Register middlewares
36
+ this.middleware.use(loggerMiddleware());
133
37
 
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
- }
38
+ this.server = Bun.serve({
39
+ port: this.port,
159
40
 
160
- /**
161
- * Handle page route rendering
162
- */
163
- async _handlePageRoute(component, request, routeMatch) {
41
+ fetch: async (req) => {
164
42
  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
- }
43
+ return await this.handleRequest(req);
44
+ } catch (err) {
45
+ console.error('Server Error:', err);
192
46
 
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
- }
47
+ return new Response('Internal Server Error', {
48
+ status: 500,
49
+ });
205
50
  }
51
+ },
52
+ });
53
+
54
+ console.log('AfriCode running on http://localhost:' + this.port);
55
+ }
56
+
57
+ async handleRequest(req) {
58
+ const url = new URL(req.url);
59
+ const pathname = url.pathname;
60
+ const sessionId = getRequestIdentity(req);
61
+ const session = sessionStore.get(sessionId);
62
+
63
+ if (pathname.startsWith('/public')) {
64
+ const response = await this.serveStatic(pathname);
65
+ return this.attachSessionCookie(response, sessionId);
66
+ }
67
+
68
+ let context = {
69
+ req,
70
+ url,
71
+ pathname,
72
+ params: {},
73
+ sessionId,
74
+ state: session,
75
+ actions,
76
+ sessionStore
77
+ };
206
78
 
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();
79
+ const mwResult = await this.middleware.run(context);
80
+ if (mwResult) {
81
+ return this.attachSessionCookie(mwResult, sessionId);
259
82
  }
260
83
 
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;
84
+ const route = this.router.resolve(pathname);
85
+ if (!route) {
86
+ return this.attachSessionCookie(new Response('Not Found', { status: 404 }), sessionId);
278
87
  }
279
88
 
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;
89
+ try {
90
+ context = {
91
+ ...context,
92
+ params: route.params || {},
93
+ route: {
94
+ pathname,
95
+ filePath: route.filePath,
96
+ isApi: route.isApi,
97
+ isDynamic: route.isDynamic
292
98
  }
99
+ };
293
100
 
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
- }
101
+ if (!route.isApi && extname(route.filePath) === '.html') {
102
+ const html = await Bun.file(route.filePath).text();
103
+ const response = new Response(html, {
104
+ headers: { 'Content-Type': 'text/html; charset=utf-8' }
105
+ });
106
+ return this.attachSessionCookie(response, sessionId);
107
+ }
307
108
 
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;
109
+ const pageModule = await import(route.filePath);
315
110
 
316
- // Preserve current state
317
- const oldState = module.instance?.state || {};
111
+ if (route.isApi) {
112
+ const method = req.method.toUpperCase();
113
+ const handler = pageModule[method];
318
114
 
319
- // Dispose old instance
320
- if (module.instance?.dispose) {
321
- module.instance.dispose();
115
+ if (!handler) {
116
+ throw new Error("No " + method + " handler in API route");
322
117
  }
323
118
 
324
- // Reload module
325
- try {
326
- // Clear module cache if possible
327
- if (typeof require !== 'undefined' && require.cache) {
328
- delete require.cache[moduleId];
329
- }
119
+ const result = await handler(context);
120
+ const response = this.normalizeResponse(result);
121
+ return this.attachSessionCookie(response, sessionId);
122
+ }
330
123
 
331
- await this._instantiateModule(module);
124
+ const handler = pageModule.default;
125
+ if (!handler) {
126
+ throw new Error('No default export in page');
127
+ }
332
128
 
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
- }
129
+ const result = await handler(context);
130
+ const response = this.normalizeResponse(result);
131
+ return this.attachSessionCookie(response, sessionId);
132
+ } catch (err) {
133
+ console.error('Route Error:', err);
134
+ return this.attachSessionCookie(new Response('Route Error', { status: 500 }), sessionId);
342
135
  }
136
+ }
137
+ attachSessionCookie(response, sessionId) {
138
+ const cookie = 'afri_session=' + sessionId + '; Path=/; HttpOnly; SameSite=Strict';
343
139
 
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;
140
+ if (response.headers.has('Set-Cookie')) {
141
+ response.headers.append('Set-Cookie', cookie);
142
+ } else {
143
+ response.headers.set('Set-Cookie', cookie);
357
144
  }
358
145
 
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
- }
146
+ return response;
147
+ }
367
148
 
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
- }
149
+ normalizeResponse(result) {
150
+ // Already a Response
151
+ if (result instanceof Response) return result;
390
152
 
391
- // Import join function for static file serving
392
- import { join } from 'path';
393
- this.connections = new Set();
153
+ // RawHtml (PRIMARY)
154
+ if (result instanceof RawHtml) {
155
+ return new Response(result.toString(), {
156
+ headers: { 'Content-Type': 'text/html' },
157
+ });
394
158
  }
395
159
 
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;
160
+ // ✅ String fallback
161
+ if (typeof result === 'string') {
162
+ return new Response(result, {
163
+ headers: { 'Content-Type': 'text/html' },
164
+ });
414
165
  }
415
166
 
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 || {};
167
+ // ❌ Invalid return type
168
+ console.error('Invalid render output:', result);
450
169
 
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
- }
170
+ return new Response('Invalid response type', { status: 500 });
171
+ }
464
172
 
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
- }
173
+ async serveStatic(pathname) {
174
+ // Basic path traversal protection
175
+ if (pathname.includes('..') || pathname.includes('\\')) {
176
+ return new Response('Forbidden', { status: 403 });
487
177
  }
488
178
 
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
- }
179
+ const filePath = join(process.cwd(), pathname);
508
180
 
509
- /**
510
- * Add WebSocket connection for hot reload notifications
511
- * @param {WebSocket} ws - WebSocket connection
512
- */
513
- addConnection(ws) {
514
- this.connections.add(ws);
181
+ try {
182
+ const file = Bun.file(filePath);
515
183
 
516
- ws.on('close', () => {
517
- this.connections.delete(ws);
518
- });
519
- }
184
+ if (!(await file.exists())) {
185
+ return new Response('Not Found', { status: 404 });
186
+ }
520
187
 
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\//, '');
188
+ return new Response(file);
189
+ } catch (err) {
190
+ console.error('Static Error:', err);
191
+ return new Response('Static File Error', { status: 500 });
527
192
  }
193
+ }
528
194
  }
529
195
 
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
- }
196
+ export class HotReloadEngine extends EnhancedHMRMiddleware {}
638
197
 
639
- /**
640
- * Bun-Native Database Connection
641
- * Leveraging Bun.sql for type-safe SQLite operations
642
- */
643
198
  export class BunDatabase {
644
- constructor(dbPath = './afriCode.db') {
645
- this.db = new Bun.sql(`${dbPath}`);
199
+ constructor(dbPath = './afriCode.db') {
200
+ this.db = new BunSQLiteDatabase(dbPath, { create: true });
201
+ }
646
202
 
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
- }
203
+ query(sql, params = []) {
204
+ return this.db.query(sql).all(...params);
205
+ }
671
206
 
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
- }
207
+ get(sql, params = []) {
208
+ return this.db.query(sql).get(...params);
209
+ }
685
210
 
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
- }
211
+ run(sql, params = []) {
212
+ return this.db.query(sql).run(...params);
213
+ }
699
214
 
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
- }
215
+ transaction(callback) {
216
+ return this.db.transaction(callback)();
217
+ }
707
218
 
708
- /**
709
- * Close database connection
710
- */
711
- close() {
712
- this.db.close();
713
- }
219
+ close() {
220
+ this.db.close();
221
+ }
714
222
  }
715
223
 
716
- /**
717
- * Performance Monitoring
718
- * Real-time performance metrics using Bun's high-resolution timers
719
- */
720
224
  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);
225
+ constructor() {
226
+ this.metrics = {
227
+ startupTime: 0,
228
+ requestCount: 0,
229
+ averageResponseTime: 0,
230
+ memoryUsage: 0,
231
+ activeConnections: 0
232
+ };
233
+ this.requestTimes = [];
234
+ this.startTime = performance.now();
235
+ }
740
236
 
741
- // Keep only last 1000 requests for averaging
742
- if (this.requestTimes.length > 1000) {
743
- this.requestTimes.shift();
744
- }
237
+ recordRequest(duration) {
238
+ this.requestTimes.push(duration);
745
239
 
746
- this.metrics.requestCount++;
747
- this.metrics.averageResponseTime =
748
- this.requestTimes.reduce((a, b) => a + b, 0) / this.requestTimes.length;
240
+ if (this.requestTimes.length > 1000) {
241
+ this.requestTimes.shift();
749
242
  }
750
243
 
751
- /**
752
- * Update memory usage
753
- */
754
- updateMemoryUsage() {
755
- if (typeof process !== 'undefined' && process.memoryUsage) {
756
- this.metrics.memoryUsage = process.memoryUsage().heapUsed;
757
- }
758
- }
244
+ this.metrics.requestCount++;
245
+ this.metrics.averageResponseTime =
246
+ this.requestTimes.reduce((a, b) => a + b, 0) / this.requestTimes.length;
247
+ }
759
248
 
760
- /**
761
- * Get current metrics
762
- */
763
- getMetrics() {
764
- this.updateMemoryUsage();
765
- return { ...this.metrics };
249
+ updateMemoryUsage() {
250
+ if (typeof process !== 'undefined' && process.memoryUsage) {
251
+ this.metrics.memoryUsage = process.memoryUsage().heapUsed;
766
252
  }
253
+ }
767
254
 
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
- }
255
+ getMetrics() {
256
+ this.updateMemoryUsage();
257
+ return { ...this.metrics };
258
+ }
259
+
260
+ startCollection(interval = 5000) {
261
+ setInterval(() => {
262
+ this.updateMemoryUsage();
263
+ }, interval);
264
+ }
777
265
  }
778
266
 
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
- };
267
+ export async function initBunRuntime(config = {}) {
268
+ const runtime = {
269
+ server: new BunHTTPServer(config.server),
270
+ database: config.database ? new BunDatabase(config.database.path) : null,
271
+ monitor: new PerformanceMonitor(),
272
+ hotReload: config.hotReload ? new HotReloadEngine(config.hotReload) : null
273
+ };
789
274
 
790
- // Start performance monitoring
791
- runtime.monitor.startCollection();
275
+ runtime.monitor.startCollection();
792
276
 
793
- // Enable hot reloading if in development
794
- if (config.hotReload) {
795
- runtime.server.enableHotReload(config.hotReload.watchPaths);
796
- }
277
+ if (runtime.hotReload && runtime.server) {
278
+ await runtime.hotReload.initialize(runtime.server);
279
+ }
797
280
 
798
- return runtime;
799
- }
281
+ return runtime;
282
+ }