@gravito/core 1.2.1 → 1.6.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,702 @@
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
+ stream(stream: ReadableStream, status?: number): Response;
43
+ notFound(message?: string): Response;
44
+ forbidden(message?: string): Response;
45
+ unauthorized(message?: string): Response;
46
+ badRequest(message?: string): Response;
47
+ forward(target: string, options?: any): Promise<Response>;
48
+ /** Header management */
49
+ header(name: string): string | undefined;
50
+ header(name: string, value: string): void;
51
+ status(code: number): void;
52
+ /** Context Variables */
53
+ get<T>(key: string): T;
54
+ set(key: string, value: any): void;
55
+ /** Lifecycle helpers */
56
+ route: (name: string, params?: any, query?: any) => string;
57
+ readonly native: any;
58
+ /** Internal initialization for pooling */
59
+ init(request: Request, params?: Record<string, string>, path?: string, routePattern?: string): this;
60
+ /** Internal cleanup for pooling */
61
+ reset(): void;
62
+ }
63
+ /**
64
+ * FastRequest - Minimal request interface
65
+ */
66
+ interface FastRequest {
67
+ /** Full URL */
68
+ readonly url: string;
69
+ /** HTTP method */
70
+ readonly method: string;
71
+ /** Path without query */
72
+ readonly path: string;
73
+ /**
74
+ * Route pattern (e.g., /users/:id) for metrics labeling
75
+ * Prevents high cardinality issues in monitoring systems
76
+ */
77
+ readonly routePattern?: string;
78
+ /** Get route parameter */
79
+ param(name: string): string | undefined;
80
+ /** Get all route parameters */
81
+ params(): Record<string, string>;
82
+ /** Get query parameter */
83
+ query(name: string): string | undefined;
84
+ /** Get all query parameters */
85
+ queries(): Record<string, string | string[]>;
86
+ /** Get header */
87
+ header(name: string): string | undefined;
88
+ /** Get all headers */
89
+ headers(): Record<string, string>;
90
+ /** Parse JSON body */
91
+ json<T = unknown>(): Promise<T>;
92
+ /** Parse text body */
93
+ text(): Promise<string>;
94
+ /** Parse form data */
95
+ formData(): Promise<FormData>;
96
+ /** Raw Request object */
97
+ readonly raw: Request;
98
+ }
99
+ /**
100
+ * Route handler function
101
+ */
102
+ type Handler = (ctx: FastContext$1) => Response | Promise<Response>;
103
+ /**
104
+ * Middleware function
105
+ */
106
+ type Middleware = (ctx: FastContext$1, next: () => Promise<Response | undefined>) => Response | undefined | Promise<Response | undefined>;
107
+ /**
108
+ * Error handler function
109
+ */
110
+ type ErrorHandler = (error: Error, ctx: FastContext$1) => Response | Promise<Response>;
111
+ /**
112
+ * Not found handler function
113
+ */
114
+ type NotFoundHandler = (ctx: FastContext$1) => Response | Promise<Response>;
115
+ /**
116
+ * Route metadata for middleware management
117
+ */
118
+ interface RouteMetadata {
119
+ handler: Handler;
120
+ middleware: Middleware[];
121
+ compiled?: CompiledHandler;
122
+ useMinimal?: boolean;
123
+ compiledVersion?: number;
124
+ }
125
+ /**
126
+ * Compiled handler function
127
+ */
128
+ type CompiledHandler = (ctx: FastContext$1) => Promise<Response>;
129
+ /**
130
+ * Route match result from router
131
+ */
132
+ interface RouteMatch {
133
+ /** Matched handler */
134
+ handler: Handler | null;
135
+ /** Extracted route parameters */
136
+ params: Record<string, string>;
137
+ /** Middleware to execute */
138
+ middleware: Middleware[];
139
+ /** Optional stable route pattern for caching */
140
+ routePattern?: string;
141
+ }
142
+ /**
143
+ * Engine configuration options
144
+ */
145
+ interface EngineOptions {
146
+ /** Context pool size (default: 256) */
147
+ poolSize?: number;
148
+ /** Enable route compilation optimization (default: true) */
149
+ enableAOT?: boolean;
150
+ /** Custom error handler */
151
+ onError?: ErrorHandler;
152
+ /** Custom 404 handler */
153
+ onNotFound?: NotFoundHandler;
154
+ }
155
+
156
+ /**
157
+ * @fileoverview Gravito - High-Performance Web Engine for Bun
158
+ *
159
+ * The standalone engine optimized exclusively for Bun runtime.
160
+ * 99% API-compatible with Hono, but faster through Bun-specific optimizations.
161
+ *
162
+ * Key optimizations:
163
+ * 1. Object pooling for zero-allocation request handling
164
+ * 2. AOT router with O(1) static route lookup
165
+ * 3. Lazy parsing - only parse what's accessed
166
+ * 4. Direct Bun.serve integration without wrapper layers
167
+ *
168
+ * @module @gravito/core/engine
169
+ */
170
+
171
+ /**
172
+ * Gravito - The High-Performance Web Engine
173
+ */
174
+ declare class Gravito {
175
+ private router;
176
+ private contextPool;
177
+ private errorHandler?;
178
+ private notFoundHandler?;
179
+ /** @internal */
180
+ staticRoutes: Map<string, RouteMetadata>;
181
+ private isPureStaticApp;
182
+ private compiledDynamicRoutes;
183
+ private middlewareVersion;
184
+ /**
185
+ * Create a new Gravito instance
186
+ *
187
+ * @param options - Engine configuration options
188
+ */
189
+ constructor(options?: EngineOptions);
190
+ /**
191
+ * Register a GET route
192
+ *
193
+ * @param path - Route path (e.g., '/users/:id')
194
+ * @param handlers - Handler and optional middleware
195
+ * @returns This instance for chaining
196
+ */
197
+ get(path: string, ...handlers: Handler[]): this;
198
+ /**
199
+ * Register a POST route
200
+ */
201
+ post(path: string, ...handlers: Handler[]): this;
202
+ /**
203
+ * Register a PUT route
204
+ */
205
+ put(path: string, ...handlers: Handler[]): this;
206
+ /**
207
+ * Register a DELETE route
208
+ */
209
+ delete(path: string, ...handlers: Handler[]): this;
210
+ /**
211
+ * Register a PDF route
212
+ */
213
+ patch(path: string, ...handlers: Handler[]): this;
214
+ /**
215
+ * Register an OPTIONS route
216
+ */
217
+ options(path: string, ...handlers: Handler[]): this;
218
+ /**
219
+ * Register a HEAD route
220
+ */
221
+ head(path: string, ...handlers: Handler[]): this;
222
+ /**
223
+ * Register a route for all HTTP methods
224
+ */
225
+ all(path: string, ...handlers: Handler[]): this;
226
+ /**
227
+ * Register global or path-based middleware
228
+ */
229
+ use(path: string, ...middleware: Middleware[]): this;
230
+ use(...middleware: Middleware[]): this;
231
+ /**
232
+ * Mount a sub-application at a path prefix
233
+ */
234
+ route(path: string, app: Gravito): this;
235
+ /**
236
+ * Set custom error handler
237
+ */
238
+ onError(handler: ErrorHandler): this;
239
+ /**
240
+ * Set custom 404 handler
241
+ */
242
+ notFound(handler: NotFoundHandler): this;
243
+ /**
244
+ * Predictive Route Warming (JIT Optimization)
245
+ *
246
+ * Simulates requests to specified routes to trigger JIT compilation (FTL)
247
+ * before real traffic arrives.
248
+ *
249
+ * @param paths List of paths to warm up (e.g. ['/api/users', '/health'])
250
+ */
251
+ warmup(paths: string[]): Promise<void>;
252
+ /**
253
+ * Handle an incoming request
254
+ */
255
+ fetch: (request: Request) => Promise<Response>;
256
+ /**
257
+ * Handle routes with middleware (async path)
258
+ */
259
+ private handleWithMiddleware;
260
+ /**
261
+ * Handle dynamic routes (Radix Tree lookup)
262
+ */
263
+ private handleDynamicRoute;
264
+ /**
265
+ * Sync error handler (for ultra-fast path)
266
+ */
267
+ private handleErrorSync;
268
+ /**
269
+ * Sync 404 handler (for ultra-fast path)
270
+ */
271
+ private handleNotFoundSync;
272
+ /**
273
+ * Collect middleware for a specific path
274
+ */
275
+ private collectMiddlewareForPath;
276
+ /**
277
+ * Compile routes for optimization
278
+ */
279
+ private compileRoutes;
280
+ /**
281
+ * Add a route to the router
282
+ */
283
+ private addRoute;
284
+ /**
285
+ * Execute middleware chain followed by handler
286
+ */
287
+ private executeMiddleware;
288
+ /**
289
+ * Handle errors (Async version for dynamic/middleware paths)
290
+ */
291
+ private handleError;
292
+ }
293
+
294
+ /**
295
+ * @fileoverview AOT (Ahead-of-Time) Router
296
+ *
297
+ * Hybrid routing strategy:
298
+ * - Static routes: O(1) Map lookup
299
+ * - Dynamic routes: Optimized Radix Tree
300
+ *
301
+ * The key optimization is separating static from dynamic routes at registration time,
302
+ * not at match time. This eliminates unnecessary tree traversal for static paths.
303
+ *
304
+ * @module @gravito/core/engine
305
+ */
306
+
307
+ /**
308
+ * Route definition for re-playing routes (mounting)
309
+ */
310
+ interface RouteDefinition {
311
+ method: HttpMethod;
312
+ path: string;
313
+ handler: Handler;
314
+ middleware: Middleware[];
315
+ }
316
+ /**
317
+ * AOT Router - Optimized for Bun
318
+ */
319
+ declare class AOTRouter {
320
+ /** @internal */
321
+ readonly staticRoutes: Map<string, RouteMetadata>;
322
+ private dynamicRouter;
323
+ /** @internal */
324
+ readonly routeDefinitions: RouteDefinition[];
325
+ /** @internal */
326
+ readonly globalMiddleware: Middleware[];
327
+ /** @internal */
328
+ readonly pathMiddleware: Map<string, Middleware[]>;
329
+ private dynamicRoutePatterns;
330
+ private middlewareCache;
331
+ private cacheMaxSize;
332
+ private version;
333
+ /**
334
+ * Register a route
335
+ *
336
+ * Automatically determines if route is static or dynamic.
337
+ * Static routes are stored in a Map for O(1) lookup.
338
+ * Dynamic routes use the Radix Tree.
339
+ *
340
+ * @param method - HTTP method
341
+ * @param path - Route path
342
+ * @param handler - Route handler
343
+ * @param middleware - Route-specific middleware
344
+ */
345
+ add(method: HttpMethod, path: string, handler: Handler, middleware?: Middleware[]): void;
346
+ /**
347
+ * Mount another router at a prefix
348
+ */
349
+ mount(prefix: string, other: AOTRouter): void;
350
+ /**
351
+ * Add global middleware
352
+ *
353
+ * These run for every request, before route-specific middleware.
354
+ *
355
+ * @param middleware - Middleware functions
356
+ */
357
+ use(...middleware: Middleware[]): void;
358
+ /**
359
+ * Add path-based middleware
360
+ *
361
+ * Supports wildcard patterns like '/api/*'
362
+ *
363
+ * @param pattern - Path pattern
364
+ * @param middleware - Middleware functions
365
+ */
366
+ usePattern(pattern: string, ...middleware: Middleware[]): void;
367
+ /**
368
+ * Match a request to a route
369
+ *
370
+ * Returns the handler, params, and all applicable middleware.
371
+ *
372
+ * @param method - HTTP method
373
+ * @param path - Request path
374
+ * @returns Route match or null if not found
375
+ */
376
+ match(method: string, path: string): RouteMatch;
377
+ /**
378
+ * Public wrapper for collectMiddleware (used by Gravito for optimization)
379
+ */
380
+ collectMiddlewarePublic(path: string, routeMiddleware: Middleware[]): Middleware[];
381
+ /**
382
+ * Collect all applicable middleware for a path
383
+ *
384
+ * Order: global -> pattern-based -> route-specific
385
+ *
386
+ * @param path - Request path
387
+ * @param routeMiddleware - Route-specific middleware
388
+ * @returns Combined middleware array
389
+ */
390
+ private collectMiddleware;
391
+ /**
392
+ * Check if a path is static (no parameters or wildcards)
393
+ */
394
+ private isStaticPath;
395
+ /**
396
+ * Match a pattern against a path
397
+ *
398
+ * Supports:
399
+ * - Exact match: '/api/users'
400
+ * - Wildcard suffix: '/api/*'
401
+ *
402
+ * @param pattern - Pattern to match
403
+ * @param path - Path to test
404
+ * @returns True if pattern matches
405
+ */
406
+ private matchPattern;
407
+ /**
408
+ * Get all registered routes (for debugging)
409
+ */
410
+ getRoutes(): Array<{
411
+ method: string;
412
+ path: string;
413
+ type: 'static' | 'dynamic';
414
+ }>;
415
+ }
416
+
417
+ /**
418
+ * @fileoverview FastContext - Pooled Request Context
419
+ *
420
+ * Minimal, high-performance context implementation designed for object pooling.
421
+ * Lazy parsing strategy: only parse what's actually accessed.
422
+ *
423
+ * @module @gravito/core/engine
424
+ */
425
+
426
+ /**
427
+ * Lazy-parsed request wrapper
428
+ *
429
+ * Delays parsing of query params, headers, and body until accessed.
430
+ * This is a key optimization for requests that don't need all data.
431
+ */
432
+ declare class FastRequestImpl implements FastRequest {
433
+ private _request;
434
+ private _params;
435
+ private _path;
436
+ private _routePattern?;
437
+ private _url;
438
+ private _query;
439
+ private _headers;
440
+ private _cachedJson;
441
+ private _jsonParsed;
442
+ private _ctx;
443
+ constructor(ctx: FastContext);
444
+ /**
445
+ * Initialize for new request
446
+ */
447
+ init(request: Request, params?: Record<string, string>, path?: string, routePattern?: string): this;
448
+ /**
449
+ * Reset for pooling
450
+ */
451
+ reset(): void;
452
+ private checkReleased;
453
+ get url(): string;
454
+ get method(): string;
455
+ get path(): string;
456
+ get routePattern(): string | undefined;
457
+ param(name: string): string | undefined;
458
+ params(): Record<string, string>;
459
+ private getUrl;
460
+ query(name: string): string | undefined;
461
+ queries(): Record<string, string | string[]>;
462
+ header(name: string): string | undefined;
463
+ headers(): Record<string, string>;
464
+ json<T = unknown>(): Promise<T>;
465
+ text(): Promise<string>;
466
+ formData(): Promise<FormData>;
467
+ get raw(): Request;
468
+ }
469
+ /**
470
+ * FastContext - Pooled request context
471
+ *
472
+ * Designed for minimal memory allocation and maximum reuse.
473
+ * All response helpers create Response objects directly without intermediate wrappers.
474
+ */
475
+ declare class FastContext implements FastContext$1 {
476
+ readonly req: FastRequestImpl;
477
+ private _headers;
478
+ _isReleased: boolean;
479
+ /**
480
+ * Initialize context for a new request
481
+ *
482
+ * This is called when acquiring from the pool.
483
+ */
484
+ init(request: Request, params?: Record<string, string>, path?: string, routePattern?: string): this;
485
+ /**
486
+ * Reset context for pooling (Cleanup)
487
+ *
488
+ * This is called when releasing back to the pool.
489
+ * Implements "Deep-Reset Protocol" and "Release Guard".
490
+ */
491
+ reset(): void;
492
+ /**
493
+ * Check if context is released
494
+ */
495
+ private checkReleased;
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
+ stream(stream: ReadableStream, status?: number): Response;
502
+ notFound(message?: string): Response;
503
+ forbidden(message?: string): Response;
504
+ unauthorized(message?: string): Response;
505
+ badRequest(message?: string): Response;
506
+ forward(target: string, _options?: any): Promise<Response>;
507
+ header(name: string): string | undefined;
508
+ header(name: string, value: string): void;
509
+ status(_code: number): void;
510
+ private _store;
511
+ get<T>(key: string): T;
512
+ set(key: string, value: any): void;
513
+ route: (name: string, params?: any, query?: any) => string;
514
+ get native(): this;
515
+ }
516
+
517
+ /**
518
+ * @fileoverview MinimalContext - Ultra-lightweight Request Context
519
+ *
520
+ * Designed for zero-middleware static routes where pool overhead
521
+ * exceeds the cost of creating a new object.
522
+ *
523
+ * Key difference from FastContext:
524
+ * - No object pooling (direct instantiation is faster for simple cases)
525
+ * - No Headers object reuse (creates inline)
526
+ * - Minimal memory footprint
527
+ *
528
+ * @module @gravito/core/engine
529
+ */
530
+
531
+ /**
532
+ * Minimal request wrapper
533
+ */
534
+ declare class MinimalRequest implements FastRequest {
535
+ private readonly _request;
536
+ private readonly _params;
537
+ private readonly _path;
538
+ private readonly _routePattern?;
539
+ private _searchParams;
540
+ constructor(_request: Request, _params: Record<string, string>, _path: string, _routePattern?: string | undefined);
541
+ get url(): string;
542
+ get method(): string;
543
+ get path(): string;
544
+ get routePattern(): string | undefined;
545
+ param(name: string): string | undefined;
546
+ params(): Record<string, string>;
547
+ /**
548
+ * Lazy-initialize searchParams, only parse once
549
+ */
550
+ private getSearchParams;
551
+ query(name: string): string | undefined;
552
+ queries(): Record<string, string | string[]>;
553
+ header(name: string): string | undefined;
554
+ headers(): Record<string, string>;
555
+ json<T = unknown>(): Promise<T>;
556
+ text(): Promise<string>;
557
+ formData(): Promise<FormData>;
558
+ get raw(): Request;
559
+ }
560
+ /**
561
+ * MinimalContext - Optimized for simple, fast responses
562
+ *
563
+ * Use when:
564
+ * - No middleware
565
+ * - Static routes
566
+ * - Simple JSON/text responses
567
+ * - No custom headers needed
568
+ */
569
+ declare class MinimalContext implements FastContext$1 {
570
+ readonly req: MinimalRequest;
571
+ private _resHeaders;
572
+ constructor(request: Request, params: Record<string, string>, path: string, routePattern?: string);
573
+ private getHeaders;
574
+ json<T>(data: T, status?: number): Response;
575
+ text(text: string, status?: number): Response;
576
+ html(html: string, status?: number): Response;
577
+ redirect(url: string, status?: 301 | 302 | 303 | 307 | 308): Response;
578
+ body(data: BodyInit | null, status?: number): Response;
579
+ header(name: string): string | undefined;
580
+ header(name: string, value: string): void;
581
+ status(_code: number): void;
582
+ stream(stream: ReadableStream, status?: number): Response;
583
+ notFound(message?: string): Response;
584
+ forbidden(message?: string): Response;
585
+ unauthorized(message?: string): Response;
586
+ badRequest(message?: string): Response;
587
+ forward(target: string, _options?: any): Promise<Response>;
588
+ get<T>(_key: string): T;
589
+ set(_key: string, _value: any): void;
590
+ route: (name: string, params?: any, query?: any) => string;
591
+ get native(): this;
592
+ init(_request: Request, _params?: Record<string, string>, _path?: string): this;
593
+ reset(): void;
594
+ }
595
+
596
+ /**
597
+ * @fileoverview Lightweight Path Utilities
598
+ *
599
+ * High-performance path extraction without creating URL objects.
600
+ * Performance critical - every optimization matters.
601
+ *
602
+ * @module @gravito/core/engine
603
+ */
604
+ /**
605
+ * Extract pathname from URL string without creating URL object
606
+ *
607
+ * @param url - Full URL string (e.g., "http://localhost:3000/api/users?id=1")
608
+ * @returns pathname (e.g., "/api/users")
609
+ *
610
+ * @example
611
+ * ```typescript
612
+ * extractPath("http://localhost:3000/api/users?id=1") // "/api/users"
613
+ * extractPath("https://example.com/") // "/"
614
+ * ```
615
+ */
616
+ declare function extractPath(url: string): string;
617
+
618
+ /**
619
+ * @fileoverview Generic Object Pool Implementation
620
+ *
621
+ * High-performance object pooling to reduce GC pressure.
622
+ * Implements "fixed pool + overflow fallback" strategy.
623
+ *
624
+ * @module @gravito/core/engine
625
+ */
626
+ /**
627
+ * Generic object pool with fixed size and overflow handling
628
+ *
629
+ * @typeParam T - Type of objects to pool
630
+ *
631
+ * @example
632
+ * ```typescript
633
+ * const pool = new ObjectPool(
634
+ * () => new MyObject(),
635
+ * (obj) => obj.reset(),
636
+ * 256
637
+ * )
638
+ *
639
+ * const obj = pool.acquire()
640
+ * try {
641
+ * // Use object
642
+ * } finally {
643
+ * pool.release(obj)
644
+ * }
645
+ * ```
646
+ */
647
+ declare class ObjectPool<T> {
648
+ private pool;
649
+ private readonly factory;
650
+ private readonly reset;
651
+ private readonly maxSize;
652
+ /**
653
+ * Create a new object pool
654
+ *
655
+ * @param factory - Function to create new objects
656
+ * @param reset - Function to reset objects before reuse
657
+ * @param maxSize - Maximum pool size (default: 256)
658
+ */
659
+ constructor(factory: () => T, reset: (obj: T) => void, maxSize?: number);
660
+ /**
661
+ * Acquire an object from the pool
662
+ *
663
+ * If the pool is empty, creates a new object (overflow strategy).
664
+ * This ensures the pool never blocks under high load.
665
+ *
666
+ * @returns Object from pool or newly created
667
+ */
668
+ acquire(): T;
669
+ /**
670
+ * Release an object back to the pool
671
+ *
672
+ * If the pool is full, the object is discarded (will be GC'd).
673
+ * This prevents unbounded memory growth.
674
+ *
675
+ * @param obj - Object to release
676
+ */
677
+ release(obj: T): void;
678
+ /**
679
+ * Clear all objects from the pool
680
+ *
681
+ * Useful for testing or when you need to force a clean slate.
682
+ */
683
+ clear(): void;
684
+ /**
685
+ * Get current pool size
686
+ */
687
+ get size(): number;
688
+ /**
689
+ * Get maximum pool size
690
+ */
691
+ get capacity(): number;
692
+ /**
693
+ * Pre-warm the pool by creating objects in advance
694
+ *
695
+ * This can reduce latency for the first N requests.
696
+ *
697
+ * @param count - Number of objects to pre-create
698
+ */
699
+ prewarm(count: number): void;
700
+ }
701
+
702
+ 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 };