qhttpx 1.9.4 → 2.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 (94) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +17 -12
  3. package/dist/examples/api-server.js +38 -35
  4. package/dist/examples/basic.js +3 -4
  5. package/dist/examples/compression.js +6 -8
  6. package/dist/examples/cors.js +5 -6
  7. package/dist/examples/errors.js +12 -11
  8. package/dist/examples/file-upload.js +4 -6
  9. package/dist/examples/fusion.js +6 -6
  10. package/dist/examples/rate-limiting.js +10 -10
  11. package/dist/examples/validation.js +5 -6
  12. package/dist/examples/websockets.js +3 -4
  13. package/dist/package.json +3 -8
  14. package/dist/src/benchmarks/quantam-users.js +2 -2
  15. package/dist/src/benchmarks/quick-bench.js +57 -0
  16. package/dist/src/benchmarks/simple-json.js +133 -22
  17. package/dist/src/benchmarks/ultra-mode.js +8 -38
  18. package/dist/src/core/context-pool.d.ts +12 -0
  19. package/dist/src/core/context-pool.js +34 -0
  20. package/dist/src/core/fusion.js +0 -2
  21. package/dist/src/core/metrics.d.ts +1 -0
  22. package/dist/src/core/metrics.js +3 -0
  23. package/dist/src/core/scheduler.d.ts +4 -0
  24. package/dist/src/core/scheduler.js +75 -34
  25. package/dist/src/core/scope.d.ts +23 -8
  26. package/dist/src/core/scope.js +53 -14
  27. package/dist/src/core/serializer.d.ts +1 -1
  28. package/dist/src/core/serializer.js +45 -7
  29. package/dist/src/core/server.d.ts +51 -10
  30. package/dist/src/core/server.js +695 -259
  31. package/dist/src/core/timer.d.ts +11 -0
  32. package/dist/src/core/timer.js +29 -0
  33. package/dist/src/core/types.d.ts +41 -13
  34. package/dist/src/core/types.js +6 -6
  35. package/dist/src/index.d.ts +6 -4
  36. package/dist/src/index.js +19 -20
  37. package/dist/src/middleware/security.js +6 -1
  38. package/dist/src/router/radix-tree.d.ts +5 -2
  39. package/dist/src/router/radix-tree.js +58 -14
  40. package/dist/src/router/router.d.ts +5 -2
  41. package/dist/src/router/router.js +80 -63
  42. package/dist/tests/fusion.test.js +4 -4
  43. package/dist/tests/rate-limit.test.js +2 -2
  44. package/dist/tests/schema-routes.test.js +3 -1
  45. package/docs/AEGIS.md +18 -28
  46. package/docs/BENCHMARKS.md +8 -6
  47. package/docs/DATABASE.md +4 -4
  48. package/docs/MIDDLEWARE.md +3 -3
  49. package/docs/ROUTING.md +21 -13
  50. package/docs/VALIDATION.md +9 -31
  51. package/package.json +3 -8
  52. package/binding.gyp +0 -18
  53. package/dist/src/benchmarks/compare-frameworks.js +0 -119
  54. package/dist/src/benchmarks/compare.js +0 -288
  55. package/dist/src/buffer-pool.js +0 -70
  56. package/dist/src/config.js +0 -50
  57. package/dist/src/cookies.js +0 -59
  58. package/dist/src/core/native-adapter.d.ts +0 -11
  59. package/dist/src/core/native-adapter.js +0 -211
  60. package/dist/src/cors.js +0 -66
  61. package/dist/src/logger.js +0 -45
  62. package/dist/src/metrics.js +0 -111
  63. package/dist/src/native/index.d.ts +0 -32
  64. package/dist/src/native/index.js +0 -141
  65. package/dist/src/presets.js +0 -33
  66. package/dist/src/radix-router.js +0 -89
  67. package/dist/src/radix-tree.js +0 -81
  68. package/dist/src/resources.js +0 -25
  69. package/dist/src/router.js +0 -138
  70. package/dist/src/scheduler.js +0 -85
  71. package/dist/src/security.js +0 -69
  72. package/dist/src/server.js +0 -685
  73. package/dist/src/signals.js +0 -31
  74. package/dist/src/static.js +0 -107
  75. package/dist/src/stream.js +0 -71
  76. package/dist/src/tasks.js +0 -87
  77. package/dist/src/testing.js +0 -40
  78. package/dist/src/types.js +0 -19
  79. package/dist/src/utils/testing.js +0 -40
  80. package/dist/src/worker-queue.js +0 -73
  81. package/dist/tests/native-adapter.test.d.ts +0 -1
  82. package/dist/tests/native-adapter.test.js +0 -71
  83. package/prebuilds/darwin-arm64/qhttpx.node +0 -0
  84. package/prebuilds/linux-x64/qhttpx.node +0 -0
  85. package/prebuilds/win32-x64/qhttpx.node +0 -0
  86. package/scripts/install-native.js +0 -26
  87. package/src/native/README.md +0 -31
  88. package/src/native/addon.cc +0 -8
  89. package/src/native/index.ts +0 -158
  90. package/src/native/picohttpparser.c +0 -608
  91. package/src/native/picohttpparser.h +0 -76
  92. package/src/native/server.cc +0 -264
  93. package/src/native/server.h +0 -30
  94. /package/dist/src/benchmarks/{compare.d.ts → quick-bench.d.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ export declare class RequestTimer {
2
+ private cachedTime;
3
+ private readonly perfStart;
4
+ private readonly updateInterval;
5
+ private lastUpdate;
6
+ private intervalId;
7
+ constructor();
8
+ now(): number;
9
+ preciseNow(): number;
10
+ }
11
+ export declare const globalTimer: RequestTimer;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.globalTimer = exports.RequestTimer = void 0;
4
+ class RequestTimer {
5
+ constructor() {
6
+ this.cachedTime = Date.now();
7
+ this.perfStart = performance.now();
8
+ this.updateInterval = 10; // Update every 10ms
9
+ this.lastUpdate = this.perfStart;
10
+ // Auto-update timer
11
+ this.intervalId = setInterval(() => {
12
+ this.cachedTime = Date.now();
13
+ this.lastUpdate = performance.now();
14
+ }, this.updateInterval);
15
+ // Ensure the timer doesn't keep the process alive
16
+ this.intervalId.unref();
17
+ }
18
+ now() {
19
+ // Use cached time for most calls
20
+ return this.cachedTime;
21
+ }
22
+ preciseNow() {
23
+ // For metrics that need precision, calculate offset
24
+ const elapsed = performance.now() - this.lastUpdate;
25
+ return this.cachedTime + Math.floor(elapsed);
26
+ }
27
+ }
28
+ exports.RequestTimer = RequestTimer;
29
+ exports.globalTimer = new RequestTimer();
@@ -5,14 +5,24 @@ import type { DatabaseManager } from '../database/manager';
5
5
  import type { RouteSchema, Validator } from '../validation/types';
6
6
  import type { ViewEngine } from '../views/types';
7
7
  import type { RequestFusionOptions } from './fusion';
8
+ export type { RequestFusionOptions };
8
9
  export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
9
- export declare enum RoutePriority {
10
- CRITICAL = "critical",
11
- STANDARD = "standard",
12
- BEST_EFFORT = "best-effort"
13
- }
10
+ export type RoutePriority = 'critical' | 'standard' | 'best-effort';
11
+ export declare const RoutePriority: {
12
+ CRITICAL: RoutePriority;
13
+ STANDARD: RoutePriority;
14
+ BEST_EFFORT: RoutePriority;
15
+ };
16
+ export type RouteMetadata = {
17
+ needsQuery?: boolean;
18
+ needsCookies?: boolean;
19
+ needsBody?: boolean;
20
+ pipeline?: QHTTPXHandler;
21
+ };
14
22
  export type RouteOptions = {
15
23
  priority?: RoutePriority;
24
+ metadata?: RouteMetadata;
25
+ staticResponse?: any;
16
26
  };
17
27
  export declare class HttpError extends Error {
18
28
  status: number;
@@ -39,7 +49,7 @@ export type QHTTPXFile = {
39
49
  data: Buffer;
40
50
  size: number;
41
51
  };
42
- export type QHTTPXContext = {
52
+ export interface QHTTPXContext {
43
53
  readonly req: IncomingMessage;
44
54
  readonly res: ServerResponse;
45
55
  readonly headers: IncomingHttpHeaders;
@@ -58,6 +68,7 @@ export type QHTTPXContext = {
58
68
  serializer?: (value: unknown) => string;
59
69
  readonly json: (body: unknown, status?: number) => void;
60
70
  readonly send: (body: string | Buffer, status?: number) => void;
71
+ readonly httpError: (status: number, message?: string, details?: unknown) => HttpError;
61
72
  readonly html: (html: string, status?: number) => void;
62
73
  readonly redirect: (url: string, status?: number) => void;
63
74
  readonly setCookie: (name: string, value: string, options?: CookieOptions) => void;
@@ -68,15 +79,26 @@ export type QHTTPXContext = {
68
79
  disableAutoEnd?: boolean;
69
80
  readonly path: string;
70
81
  readonly next?: () => Promise<void>;
71
- };
82
+ }
72
83
  export type QHTTPXOpHandler = (params: any, ctx: QHTTPXContext) => any | Promise<any>;
73
- export type QHTTPXHandler = (ctx: QHTTPXContext) => void | Promise<void>;
84
+ export type QHTTPXHandler<Result = any> = (ctx: QHTTPXContext) => Result | Promise<Result>;
74
85
  export type QHTTPXRouteOptions = {
75
86
  schema?: RouteSchema | Record<string, any>;
76
- handler: QHTTPXHandler;
87
+ body?: any;
88
+ params?: any;
89
+ query?: any;
90
+ headers?: any;
91
+ response?: any;
92
+ handler?: QHTTPXHandler;
77
93
  priority?: RoutePriority;
94
+ staticResponse?: any;
78
95
  };
79
96
  export type QHTTPXRouteConfig = Omit<QHTTPXRouteOptions, 'handler'>;
97
+ export interface QHTTPXRouteMethod {
98
+ (path: string, handler: QHTTPXHandler | QHTTPXRouteOptions): void;
99
+ (path: string, handler: QHTTPXHandler, config: QHTTPXRouteConfig): void;
100
+ (path: string, config: QHTTPXRouteConfig, handler: QHTTPXHandler): void;
101
+ }
80
102
  export type QHTTPXMiddleware = (ctx: QHTTPXContext, next: () => Promise<void>) => void | Promise<void>;
81
103
  export type QHTTPXErrorContext = QHTTPXContext & {
82
104
  error: unknown;
@@ -103,7 +125,7 @@ export type QHTTPXTaskOptions = {
103
125
  maxRetries?: number;
104
126
  backoffMs?: number;
105
127
  };
106
- export type PerformanceMode = 'balanced' | 'ultra';
128
+ export type PerformanceMode = 'default';
107
129
  export interface RateLimitStore {
108
130
  increment(key: string, windowMs: number): Promise<{
109
131
  total: number;
@@ -123,6 +145,11 @@ export interface RateLimitOptions {
123
145
  store?: RateLimitStore;
124
146
  trustProxy?: boolean;
125
147
  }
148
+ export interface RateLimitConfig {
149
+ windowMs: number;
150
+ max: number;
151
+ }
152
+ export type RateLimitPreset = 'strict' | 'relaxed' | 'standard';
126
153
  export type QHTTPXOptions = {
127
154
  name?: string;
128
155
  workers?: 'auto' | number;
@@ -173,8 +200,9 @@ export type SecurityHeadersOptions = {
173
200
  strictTransportSecurity?: string | null;
174
201
  };
175
202
  export type SecureDefaultsOptions = {
176
- cors?: CorsOptions;
203
+ cors?: CorsOptions | boolean;
177
204
  securityHeaders?: SecurityHeadersOptions;
205
+ rateLimit?: RateLimitOptions;
178
206
  };
179
207
  export type CorsOrigin = string | string[] | ((origin: string | undefined) => string | null | undefined);
180
208
  export type CorsOptions = {
@@ -189,8 +217,8 @@ export type CompressionOptions = {
189
217
  threshold?: number;
190
218
  level?: number;
191
219
  };
192
- export type QHTTPXPlugin<Options = any> = (app: any, // We use 'any' here to avoid circular dependency with QHTTPX class, or we could use an interface
193
- options: Options) => void | Promise<void>;
220
+ import type { QHTTPXScope } from './scope';
221
+ export type QHTTPXPlugin<Options = any> = (app: QHTTPXScope, options: Options) => void | Promise<void>;
194
222
  export type QHTTPXPluginOptions = {
195
223
  prefix?: string;
196
224
  [key: string]: any;
@@ -1,12 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HttpError = exports.RoutePriority = void 0;
4
- var RoutePriority;
5
- (function (RoutePriority) {
6
- RoutePriority["CRITICAL"] = "critical";
7
- RoutePriority["STANDARD"] = "standard";
8
- RoutePriority["BEST_EFFORT"] = "best-effort";
9
- })(RoutePriority || (exports.RoutePriority = RoutePriority = {}));
4
+ exports.RoutePriority = {
5
+ CRITICAL: 'critical',
6
+ STANDARD: 'standard',
7
+ BEST_EFFORT: 'best-effort',
8
+ };
10
9
  class HttpError extends Error {
11
10
  constructor(status, message, options = {}) {
12
11
  super(message ?? 'HTTP Error');
@@ -17,3 +16,4 @@ class HttpError extends Error {
17
16
  }
18
17
  }
19
18
  exports.HttpError = HttpError;
19
+ ;
@@ -1,7 +1,7 @@
1
1
  import { QHTTPX } from './core/server';
2
- import type { QHTTPXOptions } from './core/types';
3
- import { NativeAdapter } from './core/native-adapter';
2
+ import type { QHTTPXOptions, QHTTPXPlugin } from './core/types';
4
3
  export { QHTTPX } from './core/server';
4
+ export { QHTTPXScope } from './core/scope';
5
5
  export * from './core/types';
6
6
  export * from './core/errors';
7
7
  export * from './middleware/cors';
@@ -31,9 +31,11 @@ export * from './validation/types';
31
31
  export * from './validation/simple';
32
32
  export * from './openapi/generator';
33
33
  export * from './client';
34
- export { NativeAdapter } from './core/native-adapter';
35
34
  export declare function createHttpApp(options?: QHTTPXOptions): QHTTPX;
36
- export declare function createNativeApp(options?: QHTTPXOptions): NativeAdapter;
35
+ /**
36
+ * Type helper for defining plugins
37
+ */
38
+ export declare function plugin(fn: QHTTPXPlugin): QHTTPXPlugin;
37
39
  /**
38
40
  * Singleton instance for quick start
39
41
  * @example
package/dist/src/index.js CHANGED
@@ -14,14 +14,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.app = exports.NativeAdapter = exports.getStringifier = exports.fastJsonStringify = exports.BufferPool = exports.createSecureDefaults = exports.createSecurityHeadersMiddleware = exports.QHTTPX = void 0;
17
+ exports.app = exports.getStringifier = exports.fastJsonStringify = exports.BufferPool = exports.createSecureDefaults = exports.createSecurityHeadersMiddleware = exports.QHTTPXScope = exports.QHTTPX = void 0;
18
18
  exports.createHttpApp = createHttpApp;
19
- exports.createNativeApp = createNativeApp;
19
+ exports.plugin = plugin;
20
20
  const server_1 = require("./core/server");
21
21
  const presets_1 = require("./middleware/presets");
22
- const native_adapter_1 = require("./core/native-adapter");
23
22
  var server_2 = require("./core/server");
24
23
  Object.defineProperty(exports, "QHTTPX", { enumerable: true, get: function () { return server_2.QHTTPX; } });
24
+ var scope_1 = require("./core/scope");
25
+ Object.defineProperty(exports, "QHTTPXScope", { enumerable: true, get: function () { return scope_1.QHTTPXScope; } });
25
26
  __exportStar(require("./core/types"), exports);
26
27
  __exportStar(require("./core/errors"), exports);
27
28
  __exportStar(require("./middleware/cors"), exports);
@@ -56,26 +57,24 @@ __exportStar(require("./validation/types"), exports);
56
57
  __exportStar(require("./validation/simple"), exports);
57
58
  __exportStar(require("./openapi/generator"), exports);
58
59
  __exportStar(require("./client"), exports);
59
- var native_adapter_2 = require("./core/native-adapter");
60
- Object.defineProperty(exports, "NativeAdapter", { enumerable: true, get: function () { return native_adapter_2.NativeAdapter; } });
61
60
  function createHttpApp(options = {}) {
62
61
  const app = new server_1.QHTTPX(options);
63
- // Skip middleware in ultra mode for maximum performance
64
- if (options.performanceMode !== 'ultra') {
65
- const middlewares = (0, presets_1.createApiPreset)({
66
- rateLimit: options.rateLimit,
67
- cors: options.cors,
68
- compression: options.compression,
69
- logging: options.logging,
70
- security: options.security,
71
- });
72
- middlewares.forEach((mw) => app.use(mw));
73
- }
62
+ // Apply default middleware presets
63
+ const middlewares = (0, presets_1.createApiPreset)({
64
+ rateLimit: options.rateLimit,
65
+ cors: options.cors,
66
+ compression: options.compression,
67
+ logging: options.logging,
68
+ security: options.security,
69
+ });
70
+ middlewares.forEach((mw) => app.use(mw));
74
71
  return app;
75
72
  }
76
- function createNativeApp(options = {}) {
77
- const app = createHttpApp(options);
78
- return new native_adapter_1.NativeAdapter(app);
73
+ /**
74
+ * Type helper for defining plugins
75
+ */
76
+ function plugin(fn) {
77
+ return fn;
79
78
  }
80
79
  /**
81
80
  * Singleton instance for quick start
@@ -83,7 +82,7 @@ function createNativeApp(options = {}) {
83
82
  * import { app } from 'qhttpx';
84
83
  * app.get('/', ({ json }) => json({ hello: 'world' }));
85
84
  */
86
- exports.app = createHttpApp();
85
+ exports.app = new server_1.QHTTPX();
87
86
  /**
88
87
  * Default export for simplified usage
89
88
  * @example
@@ -30,7 +30,12 @@ function createSecurityHeadersMiddleware(options = {}) {
30
30
  }
31
31
  function createSecureDefaults(options = {}) {
32
32
  const middlewares = [];
33
- middlewares.push((0, cors_1.createCorsMiddleware)(options.cors));
33
+ const corsOpts = options.cors;
34
+ if (corsOpts !== false) {
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ const opts = (corsOpts === true || corsOpts === undefined) ? {} : corsOpts;
37
+ middlewares.push((0, cors_1.createCorsMiddleware)(opts));
38
+ }
34
39
  middlewares.push(createSecurityHeadersMiddleware(options.securityHeaders));
35
40
  return middlewares;
36
41
  }
@@ -1,18 +1,21 @@
1
- import { QHTTPXHandler, RoutePriority } from '../core/types';
1
+ import { QHTTPXHandler, RoutePriority, RouteMetadata } from '../core/types';
2
2
  export type RouteData = {
3
3
  handler: QHTTPXHandler;
4
4
  priority: RoutePriority;
5
+ metadata: RouteMetadata;
5
6
  };
6
7
  export type MatchResult = {
7
8
  handler: QHTTPXHandler;
8
9
  priority: RoutePriority;
9
10
  params: Record<string, string>;
11
+ metadata: RouteMetadata;
10
12
  };
11
13
  export declare class RadixTree {
12
14
  private root;
13
- insert(segments: string[], handler: QHTTPXHandler, priority: RoutePriority): void;
15
+ insert(segments: string[], handler: QHTTPXHandler, priority: RoutePriority, metadata: RouteMetadata): void;
14
16
  lookup(segments: string[]): MatchResult | null;
15
17
  lookupPath(path: string): MatchResult | null;
18
+ private toMatchResult;
16
19
  private findPath;
17
20
  private find;
18
21
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RadixTree = void 0;
4
+ const EMPTY_PARAMS = Object.freeze({});
4
5
  class Node {
5
6
  constructor() {
6
7
  // Map segment -> Node
@@ -18,7 +19,7 @@ class RadixTree {
18
19
  constructor() {
19
20
  this.root = new Node();
20
21
  }
21
- insert(segments, handler, priority) {
22
+ insert(segments, handler, priority, metadata) {
22
23
  let node = this.root;
23
24
  for (const segment of segments) {
24
25
  if (segment.startsWith(':')) {
@@ -39,11 +40,14 @@ class RadixTree {
39
40
  node = node.children.get(segment);
40
41
  }
41
42
  }
42
- node.data = { handler, priority };
43
- node.staticMatch = { handler, priority, params: {} };
43
+ node.data = { handler, priority, metadata };
44
+ node.staticMatch = { handler, priority, params: EMPTY_PARAMS, metadata };
44
45
  }
45
46
  lookup(segments) {
46
- return this.find(this.root, segments, 0);
47
+ const result = this.find(this.root, segments, 0);
48
+ if (!result)
49
+ return null;
50
+ return this.toMatchResult(result);
47
51
  }
48
52
  lookupPath(path) {
49
53
  if (path === '/' || path === '') {
@@ -53,13 +57,43 @@ class RadixTree {
53
57
  return null;
54
58
  }
55
59
  const start = path.charCodeAt(0) === 47 ? 1 : 0;
56
- return this.findPath(this.root, path, start);
60
+ const result = this.findPath(this.root, path, start);
61
+ if (!result)
62
+ return null;
63
+ if (!result.params) {
64
+ return {
65
+ handler: result.handler,
66
+ priority: result.priority,
67
+ params: EMPTY_PARAMS,
68
+ metadata: result.metadata
69
+ };
70
+ }
71
+ return this.toMatchResult(result);
72
+ }
73
+ toMatchResult(result) {
74
+ const params = {};
75
+ let node = result.params;
76
+ while (node) {
77
+ params[node.key] = node.value;
78
+ node = node.next;
79
+ }
80
+ return {
81
+ handler: result.handler,
82
+ priority: result.priority,
83
+ params,
84
+ metadata: result.metadata
85
+ };
57
86
  }
58
87
  findPath(node, path, start) {
59
88
  // Handle trailing slash or end of path
60
89
  if (start >= path.length) {
61
90
  if (node.staticMatch) {
62
- return node.staticMatch;
91
+ return {
92
+ handler: node.staticMatch.handler,
93
+ priority: node.staticMatch.priority,
94
+ params: null,
95
+ metadata: node.staticMatch.metadata
96
+ };
63
97
  }
64
98
  return null;
65
99
  }
@@ -84,13 +118,15 @@ class RadixTree {
84
118
  if (node.paramChild) {
85
119
  const result = this.findPath(node.paramChild, path, nextStart);
86
120
  if (result) {
87
- // Clone params to avoid modifying shared staticMatch
88
- const newParams = { ...result.params };
89
- newParams[node.paramChild.paramName] = segment;
90
121
  return {
91
122
  handler: result.handler,
92
123
  priority: result.priority,
93
- params: newParams
124
+ metadata: result.metadata,
125
+ params: {
126
+ key: node.paramChild.paramName,
127
+ value: segment,
128
+ next: result.params
129
+ }
94
130
  };
95
131
  }
96
132
  }
@@ -102,7 +138,8 @@ class RadixTree {
102
138
  return {
103
139
  handler: node.data.handler,
104
140
  priority: node.data.priority,
105
- params: {},
141
+ metadata: node.data.metadata,
142
+ params: null,
106
143
  };
107
144
  }
108
145
  return null;
@@ -120,9 +157,16 @@ class RadixTree {
120
157
  if (node.paramChild) {
121
158
  const result = this.find(node.paramChild, segments, index + 1);
122
159
  if (result) {
123
- // If match found down this path, add current param to it
124
- result.params[node.paramChild.paramName] = segment;
125
- return result;
160
+ return {
161
+ handler: result.handler,
162
+ priority: result.priority,
163
+ metadata: result.metadata,
164
+ params: {
165
+ key: node.paramChild.paramName,
166
+ value: segment,
167
+ next: result.params
168
+ }
169
+ };
126
170
  }
127
171
  }
128
172
  return null;
@@ -1,22 +1,25 @@
1
- import { HTTPMethod, QHTTPXHandler, RouteOptions, RoutePriority } from '../core/types';
1
+ import { HTTPMethod, QHTTPXHandler, RouteOptions, RoutePriority, RouteMetadata } from '../core/types';
2
2
  import { RouteSchema } from '../validation/types';
3
3
  type RouteDefinition = {
4
4
  path: string;
5
5
  segments: string[];
6
6
  handler: QHTTPXHandler;
7
7
  priority: RoutePriority;
8
+ metadata: RouteMetadata;
8
9
  schema?: RouteSchema | Record<string, unknown>;
9
10
  };
10
11
  export type RouteMatch = {
11
12
  handler: QHTTPXHandler;
12
13
  params: Record<string, string>;
13
14
  priority: RoutePriority;
15
+ metadata: RouteMetadata;
14
16
  };
15
17
  export declare class Router {
16
18
  private readonly methodBuckets;
17
- private readonly radixTrees;
18
19
  private readonly staticRoutes;
20
+ private readonly dynamicRoutes;
19
21
  private isFrozen;
22
+ private detectMetadata;
20
23
  register(method: HTTPMethod, path: string, handler: QHTTPXHandler, options?: RouteOptions & {
21
24
  schema?: RouteSchema | Record<string, unknown>;
22
25
  }): void;