@gravito/core 1.0.0-beta.6 → 1.1.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.
@@ -0,0 +1,612 @@
1
+ /**
2
+ * @fileoverview Core HTTP Types for Gravito Framework
3
+ *
4
+ * These types provide a unified abstraction layer that decouples the framework
5
+ * from any specific HTTP engine (Photon, Express, custom, etc.).
6
+ *
7
+ * @module @gravito/core/http
8
+ * @since 2.0.0
9
+ */
10
+ declare global {
11
+ interface ExecutionContext {
12
+ waitUntil(promise: Promise<unknown>): void;
13
+ passThroughOnException(): void;
14
+ }
15
+ }
16
+ /**
17
+ * Standard HTTP methods supported by Gravito
18
+ */
19
+ type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head';
20
+
21
+ /**
22
+ * @fileoverview Gravito Core Engine Types
23
+ *
24
+ * Minimal, high-performance types for the standalone engine.
25
+ * These are intentionally simpler than the full framework types.
26
+ *
27
+ * @module @gravito/core/engine
28
+ */
29
+
30
+ /**
31
+ * FastContext - The pooled request context
32
+ */
33
+ interface FastContext$1 {
34
+ /** Request accessor */
35
+ readonly req: FastRequest;
36
+ /** Response helpers */
37
+ json<T>(data: T, status?: number): Response;
38
+ text(text: string, status?: number): Response;
39
+ html(html: string, status?: number): Response;
40
+ redirect(url: string, status?: 301 | 302 | 303 | 307 | 308): Response;
41
+ body(data: BodyInit | null, status?: number): Response;
42
+ /** Header management */
43
+ header(name: string, value: string): void;
44
+ status(code: number): void;
45
+ /** Internal reset for pooling */
46
+ reset(request: Request, params?: Record<string, string>): this;
47
+ }
48
+ /**
49
+ * FastRequest - Minimal request interface
50
+ */
51
+ interface FastRequest {
52
+ /** Full URL */
53
+ readonly url: string;
54
+ /** HTTP method */
55
+ readonly method: string;
56
+ /** Path without query */
57
+ readonly path: string;
58
+ /** Get route parameter */
59
+ param(name: string): string | undefined;
60
+ /** Get all route parameters */
61
+ params(): Record<string, string>;
62
+ /** Get query parameter */
63
+ query(name: string): string | undefined;
64
+ /** Get all query parameters */
65
+ queries(): Record<string, string | string[]>;
66
+ /** Get header */
67
+ header(name: string): string | undefined;
68
+ /** Get all headers */
69
+ headers(): Record<string, string>;
70
+ /** Parse JSON body */
71
+ json<T = unknown>(): Promise<T>;
72
+ /** Parse text body */
73
+ text(): Promise<string>;
74
+ /** Parse form data */
75
+ formData(): Promise<FormData>;
76
+ /** Raw Request object */
77
+ readonly raw: Request;
78
+ }
79
+ /**
80
+ * Route handler function
81
+ */
82
+ type Handler = (ctx: FastContext$1) => Response | Promise<Response>;
83
+ /**
84
+ * Middleware function
85
+ */
86
+ type Middleware = (ctx: FastContext$1, next: () => Promise<void>) => void | Promise<void>;
87
+ /**
88
+ * Error handler function
89
+ */
90
+ type ErrorHandler = (error: Error, ctx: FastContext$1) => Response | Promise<Response>;
91
+ /**
92
+ * Not found handler function
93
+ */
94
+ type NotFoundHandler = (ctx: FastContext$1) => Response | Promise<Response>;
95
+ /**
96
+ * Route match result from router
97
+ */
98
+ interface RouteMatch {
99
+ /** Matched handler */
100
+ handler: Handler | null;
101
+ /** Extracted route parameters */
102
+ params: Record<string, string>;
103
+ /** Middleware to execute */
104
+ middleware: Middleware[];
105
+ }
106
+ /**
107
+ * Engine configuration options
108
+ */
109
+ interface EngineOptions {
110
+ /** Context pool size (default: 256) */
111
+ poolSize?: number;
112
+ /** Enable route compilation optimization (default: true) */
113
+ enableAOT?: boolean;
114
+ /** Custom error handler */
115
+ onError?: ErrorHandler;
116
+ /** Custom 404 handler */
117
+ onNotFound?: NotFoundHandler;
118
+ }
119
+
120
+ /**
121
+ * @fileoverview Gravito - High-Performance Web Engine for Bun
122
+ *
123
+ * The standalone engine optimized exclusively for Bun runtime.
124
+ * 99% API-compatible with Hono, but faster through Bun-specific optimizations.
125
+ *
126
+ * Key optimizations:
127
+ * 1. Object pooling for zero-allocation request handling
128
+ * 2. AOT router with O(1) static route lookup
129
+ * 3. Lazy parsing - only parse what's accessed
130
+ * 4. Direct Bun.serve integration without wrapper layers
131
+ *
132
+ * @module @gravito/core/engine
133
+ */
134
+
135
+ /**
136
+ * Gravito - The High-Performance Web Engine
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * import { Gravito } from '@gravito/core/engine'
141
+ *
142
+ * const app = new Gravito()
143
+ *
144
+ * app.get('/', (c) => c.json({ message: 'Hello, World!' }))
145
+ * app.get('/users/:id', (c) => {
146
+ * const id = c.req.param('id')
147
+ * return c.json({ id })
148
+ * })
149
+ *
150
+ * export default app
151
+ * ```
152
+ */
153
+ declare class Gravito {
154
+ private router;
155
+ private contextPool;
156
+ private errorHandler?;
157
+ private notFoundHandler?;
158
+ private staticRoutes;
159
+ private isPureStaticApp;
160
+ /**
161
+ * Create a new Gravito instance
162
+ *
163
+ * @param options - Engine configuration options
164
+ */
165
+ constructor(options?: EngineOptions);
166
+ /**
167
+ * Register a GET route
168
+ *
169
+ * @param path - Route path (e.g., '/users/:id')
170
+ * @param handlers - Handler and optional middleware
171
+ * @returns This instance for chaining
172
+ */
173
+ get(path: string, ...handlers: Handler[]): this;
174
+ /**
175
+ * Register a POST route
176
+ */
177
+ post(path: string, ...handlers: Handler[]): this;
178
+ /**
179
+ * Register a PUT route
180
+ */
181
+ put(path: string, ...handlers: Handler[]): this;
182
+ /**
183
+ * Register a DELETE route
184
+ */
185
+ delete(path: string, ...handlers: Handler[]): this;
186
+ /**
187
+ * Register a PATCH route
188
+ */
189
+ patch(path: string, ...handlers: Handler[]): this;
190
+ /**
191
+ * Register an OPTIONS route
192
+ */
193
+ options(path: string, ...handlers: Handler[]): this;
194
+ /**
195
+ * Register a HEAD route
196
+ */
197
+ head(path: string, ...handlers: Handler[]): this;
198
+ /**
199
+ * Register a route for all HTTP methods
200
+ */
201
+ all(path: string, ...handlers: Handler[]): this;
202
+ /**
203
+ * Register global or path-based middleware
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * // Global middleware
208
+ * app.use(async (c, next) => {
209
+ * console.log(`${c.req.method} ${c.req.path}`)
210
+ * await next()
211
+ * })
212
+ *
213
+ * // Path-based middleware
214
+ * app.use('/api/*', async (c, next) => {
215
+ * c.header('X-API-Version', '1.0')
216
+ * await next()
217
+ * })
218
+ * ```
219
+ */
220
+ use(path: string, ...middleware: Middleware[]): this;
221
+ use(...middleware: Middleware[]): this;
222
+ /**
223
+ * Mount a sub-application at a path prefix
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * const api = new Gravito()
228
+ * api.get('/users', (c) => c.json({ users: [] }))
229
+ *
230
+ * const app = new Gravito()
231
+ * app.route('/api', api)
232
+ * // Now accessible at /api/users
233
+ * ```
234
+ */
235
+ route(path: string, app: Gravito): this;
236
+ /**
237
+ * Set custom error handler
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * app.onError((err, c) => {
242
+ * console.error(err)
243
+ * return c.json({ error: err.message }, 500)
244
+ * })
245
+ * ```
246
+ */
247
+ onError(handler: ErrorHandler): this;
248
+ /**
249
+ * Set custom 404 handler
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * app.notFound((c) => {
254
+ * return c.json({ error: 'Not Found' }, 404)
255
+ * })
256
+ * ```
257
+ */
258
+ notFound(handler: NotFoundHandler): this;
259
+ /**
260
+ * Handle an incoming request
261
+ *
262
+ * Optimized for minimal allocations and maximum throughput.
263
+ * Uses sync/async dual-path strategy inspired by Hono.
264
+ *
265
+ * @param request - Incoming Request object
266
+ * @returns Response object (sync or async)
267
+ */
268
+ fetch: (request: Request) => Response | Promise<Response>;
269
+ /**
270
+ * Handle routes with middleware (async path)
271
+ */
272
+ private handleWithMiddleware;
273
+ /**
274
+ * Handle dynamic routes (Radix Tree lookup)
275
+ */
276
+ private handleDynamicRoute;
277
+ /**
278
+ * Sync error handler (for ultra-fast path)
279
+ */
280
+ private handleErrorSync;
281
+ /**
282
+ * Sync 404 handler (for ultra-fast path)
283
+ */
284
+ private handleNotFoundSync;
285
+ /**
286
+ * Collect middleware for a specific path
287
+ * (Simplified version - assumes we've already checked for pure static)
288
+ */
289
+ private collectMiddlewareForPath;
290
+ /**
291
+ * Compile routes for optimization
292
+ * Called once during initialization and when routes change
293
+ */
294
+ private compileRoutes;
295
+ /**
296
+ * Add a route to the router
297
+ */
298
+ private addRoute;
299
+ /**
300
+ * Execute middleware chain followed by handler
301
+ *
302
+ * Implements the standard middleware pattern:
303
+ * Each middleware can call next() to continue the chain.
304
+ */
305
+ private executeMiddleware;
306
+ /**
307
+ * Handle 404 Not Found (Async version for dynamic/middleware paths)
308
+ */
309
+ private handleNotFound;
310
+ /**
311
+ * Handle errors (Async version for dynamic/middleware paths)
312
+ */
313
+ private handleError;
314
+ }
315
+
316
+ /**
317
+ * @fileoverview AOT (Ahead-of-Time) Router
318
+ *
319
+ * Hybrid routing strategy:
320
+ * - Static routes: O(1) Map lookup
321
+ * - Dynamic routes: Optimized Radix Tree
322
+ *
323
+ * The key optimization is separating static from dynamic routes at registration time,
324
+ * not at match time. This eliminates unnecessary tree traversal for static paths.
325
+ *
326
+ * @module @gravito/core/engine
327
+ */
328
+
329
+ /**
330
+ * AOT Router - Optimized for Bun
331
+ *
332
+ * Performance characteristics:
333
+ * - Static routes: O(1) lookup via Map
334
+ * - Dynamic routes: O(log n) via Radix Tree
335
+ * - Middleware: O(m) where m = number of matching middleware
336
+ */
337
+ declare class AOTRouter {
338
+ private staticRoutes;
339
+ private dynamicRouter;
340
+ private globalMiddleware;
341
+ private pathMiddleware;
342
+ /**
343
+ * Register a route
344
+ *
345
+ * Automatically determines if route is static or dynamic.
346
+ * Static routes are stored in a Map for O(1) lookup.
347
+ * Dynamic routes use the Radix Tree.
348
+ *
349
+ * @param method - HTTP method
350
+ * @param path - Route path
351
+ * @param handler - Route handler
352
+ * @param middleware - Route-specific middleware
353
+ */
354
+ add(method: HttpMethod, path: string, handler: Handler, middleware?: Middleware[]): void;
355
+ /**
356
+ * Add global middleware
357
+ *
358
+ * These run for every request, before route-specific middleware.
359
+ *
360
+ * @param middleware - Middleware functions
361
+ */
362
+ use(...middleware: Middleware[]): void;
363
+ /**
364
+ * Add path-based middleware
365
+ *
366
+ * Supports wildcard patterns like '/api/*'
367
+ *
368
+ * @param pattern - Path pattern
369
+ * @param middleware - Middleware functions
370
+ */
371
+ usePattern(pattern: string, ...middleware: Middleware[]): void;
372
+ /**
373
+ * Match a request to a route
374
+ *
375
+ * Returns the handler, params, and all applicable middleware.
376
+ *
377
+ * @param method - HTTP method
378
+ * @param path - Request path
379
+ * @returns Route match or null if not found
380
+ */
381
+ match(method: string, path: string): RouteMatch;
382
+ /**
383
+ * Public wrapper for collectMiddleware (used by Gravito for optimization)
384
+ */
385
+ collectMiddlewarePublic(path: string, routeMiddleware: Middleware[]): Middleware[];
386
+ /**
387
+ * Collect all applicable middleware for a path
388
+ *
389
+ * Order: global -> pattern-based -> route-specific
390
+ *
391
+ * @param path - Request path
392
+ * @param routeMiddleware - Route-specific middleware
393
+ * @returns Combined middleware array
394
+ */
395
+ private collectMiddleware;
396
+ /**
397
+ * Check if a path is static (no parameters or wildcards)
398
+ */
399
+ private isStaticPath;
400
+ /**
401
+ * Match a pattern against a path
402
+ *
403
+ * Supports:
404
+ * - Exact match: '/api/users'
405
+ * - Wildcard suffix: '/api/*'
406
+ *
407
+ * @param pattern - Pattern to match
408
+ * @param path - Path to test
409
+ * @returns True if pattern matches
410
+ */
411
+ private matchPattern;
412
+ /**
413
+ * Find the original route key for a matched dynamic route
414
+ *
415
+ * This is needed to look up route-specific middleware.
416
+ * It's a bit of a hack, but avoids storing duplicate data.
417
+ *
418
+ * @param method - HTTP method
419
+ * @param path - Matched path
420
+ * @returns Route key or null
421
+ */
422
+ private findDynamicRouteKey;
423
+ /**
424
+ * Get all registered routes (for debugging)
425
+ */
426
+ getRoutes(): Array<{
427
+ method: string;
428
+ path: string;
429
+ type: 'static' | 'dynamic';
430
+ }>;
431
+ }
432
+
433
+ /**
434
+ * @fileoverview FastContext - Pooled Request Context
435
+ *
436
+ * Minimal, high-performance context implementation designed for object pooling.
437
+ * Lazy parsing strategy: only parse what's actually accessed.
438
+ *
439
+ * @module @gravito/core/engine
440
+ */
441
+
442
+ /**
443
+ * FastContext - Pooled request context
444
+ *
445
+ * Designed for minimal memory allocation and maximum reuse.
446
+ * All response helpers create Response objects directly without intermediate wrappers.
447
+ */
448
+ declare class FastContext implements FastContext$1 {
449
+ private _req;
450
+ private _statusCode;
451
+ private _headers;
452
+ /**
453
+ * Reset context for pooling
454
+ *
455
+ * This is called when acquiring from the pool.
456
+ * Must clear all state from previous request.
457
+ */
458
+ reset(request: Request, params?: Record<string, string>): this;
459
+ get req(): FastRequest;
460
+ json<T>(data: T, status?: number): Response;
461
+ text(text: string, status?: number): Response;
462
+ html(html: string, status?: number): Response;
463
+ redirect(url: string, status?: 301 | 302 | 303 | 307 | 308): Response;
464
+ body(data: BodyInit | null, status?: number): Response;
465
+ header(name: string, value: string): void;
466
+ status(code: number): void;
467
+ }
468
+
469
+ /**
470
+ * @fileoverview MinimalContext - Ultra-lightweight Request Context
471
+ *
472
+ * Designed for zero-middleware static routes where pool overhead
473
+ * exceeds the cost of creating a new object.
474
+ *
475
+ * Key difference from FastContext:
476
+ * - No object pooling (direct instantiation is faster for simple cases)
477
+ * - No Headers object reuse (creates inline)
478
+ * - Minimal memory footprint
479
+ *
480
+ * @module @gravito/core/engine
481
+ */
482
+
483
+ /**
484
+ * MinimalContext - Optimized for simple, fast responses
485
+ *
486
+ * Use when:
487
+ * - No middleware
488
+ * - Static routes
489
+ * - Simple JSON/text responses
490
+ * - No custom headers needed
491
+ */
492
+ declare class MinimalContext implements FastContext$1 {
493
+ private readonly _req;
494
+ constructor(request: Request, params: Record<string, string>, path: string);
495
+ get req(): FastRequest;
496
+ json<T>(data: T, status?: number): Response;
497
+ text(text: string, status?: number): Response;
498
+ html(html: string, status?: number): Response;
499
+ redirect(url: string, status?: 301 | 302 | 303 | 307 | 308): Response;
500
+ body(data: BodyInit | null, status?: number): Response;
501
+ header(_name: string, _value: string): void;
502
+ status(_code: number): void;
503
+ reset(_request: Request, _params?: Record<string, string>): this;
504
+ }
505
+
506
+ /**
507
+ * @fileoverview Lightweight Path Utilities
508
+ *
509
+ * High-performance path extraction without creating URL objects.
510
+ * Performance critical - every optimization matters.
511
+ *
512
+ * @module @gravito/core/engine
513
+ */
514
+ /**
515
+ * Extract pathname from URL string without creating URL object
516
+ *
517
+ * @param url - Full URL string (e.g., "http://localhost:3000/api/users?id=1")
518
+ * @returns pathname (e.g., "/api/users")
519
+ *
520
+ * @example
521
+ * ```typescript
522
+ * extractPath("http://localhost:3000/api/users?id=1") // "/api/users"
523
+ * extractPath("https://example.com/") // "/"
524
+ * ```
525
+ */
526
+ declare function extractPath(url: string): string;
527
+
528
+ /**
529
+ * @fileoverview Generic Object Pool Implementation
530
+ *
531
+ * High-performance object pooling to reduce GC pressure.
532
+ * Implements "fixed pool + overflow fallback" strategy.
533
+ *
534
+ * @module @gravito/core/engine
535
+ */
536
+ /**
537
+ * Generic object pool with fixed size and overflow handling
538
+ *
539
+ * @typeParam T - Type of objects to pool
540
+ *
541
+ * @example
542
+ * ```typescript
543
+ * const pool = new ObjectPool(
544
+ * () => new MyObject(),
545
+ * (obj) => obj.reset(),
546
+ * 256
547
+ * )
548
+ *
549
+ * const obj = pool.acquire()
550
+ * try {
551
+ * // Use object
552
+ * } finally {
553
+ * pool.release(obj)
554
+ * }
555
+ * ```
556
+ */
557
+ declare class ObjectPool<T> {
558
+ private pool;
559
+ private readonly factory;
560
+ private readonly reset;
561
+ private readonly maxSize;
562
+ /**
563
+ * Create a new object pool
564
+ *
565
+ * @param factory - Function to create new objects
566
+ * @param reset - Function to reset objects before reuse
567
+ * @param maxSize - Maximum pool size (default: 256)
568
+ */
569
+ constructor(factory: () => T, reset: (obj: T) => void, maxSize?: number);
570
+ /**
571
+ * Acquire an object from the pool
572
+ *
573
+ * If the pool is empty, creates a new object (overflow strategy).
574
+ * This ensures the pool never blocks under high load.
575
+ *
576
+ * @returns Object from pool or newly created
577
+ */
578
+ acquire(): T;
579
+ /**
580
+ * Release an object back to the pool
581
+ *
582
+ * If the pool is full, the object is discarded (will be GC'd).
583
+ * This prevents unbounded memory growth.
584
+ *
585
+ * @param obj - Object to release
586
+ */
587
+ release(obj: T): void;
588
+ /**
589
+ * Clear all objects from the pool
590
+ *
591
+ * Useful for testing or when you need to force a clean slate.
592
+ */
593
+ clear(): void;
594
+ /**
595
+ * Get current pool size
596
+ */
597
+ get size(): number;
598
+ /**
599
+ * Get maximum pool size
600
+ */
601
+ get capacity(): number;
602
+ /**
603
+ * Pre-warm the pool by creating objects in advance
604
+ *
605
+ * This can reduce latency for the first N requests.
606
+ *
607
+ * @param count - Number of objects to pre-create
608
+ */
609
+ prewarm(count: number): void;
610
+ }
611
+
612
+ export { AOTRouter, type EngineOptions, type ErrorHandler, type FastContext$1 as FastContext, FastContext as FastContextImpl, type FastRequest, Gravito, type Handler, type Middleware, MinimalContext, type NotFoundHandler, ObjectPool, type RouteMatch, extractPath };