qhttpx 2.3.1 → 2.3.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.
package/dist/index.d.mts CHANGED
@@ -87,7 +87,7 @@ interface RouteOptions {
87
87
  priority?: 'critical' | 'interactive' | 'background';
88
88
  sloTarget?: number;
89
89
  }
90
- interface Route {
90
+ interface Route$1 {
91
91
  method: string;
92
92
  path: string;
93
93
  handler?: Handler;
@@ -161,6 +161,7 @@ interface FluentBuilder$1 {
161
161
  expiresIn?: string;
162
162
  }): this;
163
163
  respond(status?: number): void;
164
+ respond(handler: Handler): void;
164
165
  secure(): this;
165
166
  autoFilter(table: string, allow: string[], options?: {
166
167
  sort?: string[];
@@ -208,18 +209,23 @@ interface App$1 {
208
209
  auth: {
209
210
  setJwtSecret(secret: string): void;
210
211
  };
211
- get(path: string, config: RouteConfig): RouteBuilder;
212
- get(path: string, handler: Handler): RouteBuilder;
213
- get(path: string): RouteBuilder;
214
- post(path: string, config: RouteConfig): RouteBuilder;
215
- post(path: string, handler: Handler): RouteBuilder;
216
- post(path: string): RouteBuilder;
217
- put(path: string, config: RouteConfig): RouteBuilder;
218
- put(path: string, handler: Handler): RouteBuilder;
219
- put(path: string): RouteBuilder;
220
- delete(path: string, config: RouteConfig): RouteBuilder;
221
- delete(path: string, handler: Handler): RouteBuilder;
222
- delete(path: string): RouteBuilder;
212
+ get(path: string, config: RouteConfig): Route$1;
213
+ get(path: string, handler: Handler): Route$1;
214
+ get(path: string, options: RouteOptions, handler: Handler): Route$1;
215
+ get(path: string): FluentBuilder$1;
216
+ post(path: string, config: RouteConfig): Route$1;
217
+ post(path: string, handler: Handler): Route$1;
218
+ post(path: string, options: RouteOptions, handler: Handler): Route$1;
219
+ post(path: string): FluentBuilder$1;
220
+ put(path: string, config: RouteConfig): Route$1;
221
+ put(path: string, handler: Handler): Route$1;
222
+ put(path: string, options: RouteOptions, handler: Handler): Route$1;
223
+ put(path: string): FluentBuilder$1;
224
+ delete(path: string, config: RouteConfig): Route$1;
225
+ delete(path: string, handler: Handler): Route$1;
226
+ delete(path: string, options: RouteOptions, handler: Handler): Route$1;
227
+ delete(path: string): FluentBuilder$1;
228
+ addRoute(method: string, path: string): Route$1;
223
229
  listen(port: number, callback?: () => void): void;
224
230
  listen(options: ListenOptions): void;
225
231
  stop(): void;
@@ -260,6 +266,8 @@ declare class FluentBuilder {
260
266
  private requestSchema?;
261
267
  private responseSchemaDef?;
262
268
  private queryBuilder?;
269
+ private rateLimitOptions?;
270
+ private cacheOptions?;
263
271
  constructor(app: App$1, method: string, path: string);
264
272
  desc(description: string): this;
265
273
  auth(strategy?: string): this;
@@ -408,26 +416,56 @@ declare class App implements App$1 {
408
416
  headers?: string[];
409
417
  credentials?: boolean;
410
418
  }): this;
411
- get(path: string, config: RouteConfig): FluentBuilder;
412
- get(path: string, handler: Handler): FluentBuilder;
413
- get(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
419
+ get(path: string, config: RouteConfig): Route;
420
+ get(path: string, handler: Handler): Route;
421
+ get(path: string, options: RouteOptions, handler: Handler): Route;
414
422
  get(path: string): FluentBuilder;
415
- post(path: string, config: RouteConfig): FluentBuilder;
416
- post(path: string, handler: Handler): FluentBuilder;
417
- post(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
423
+ post(path: string, config: RouteConfig): Route;
424
+ post(path: string, handler: Handler): Route;
425
+ post(path: string, options: RouteOptions, handler: Handler): Route;
418
426
  post(path: string): FluentBuilder;
419
- put(path: string, config: RouteConfig): FluentBuilder;
420
- put(path: string, handler: Handler): FluentBuilder;
421
- put(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
427
+ put(path: string, config: RouteConfig): Route;
428
+ put(path: string, handler: Handler): Route;
429
+ put(path: string, options: RouteOptions, handler: Handler): Route;
422
430
  put(path: string): FluentBuilder;
423
- delete(path: string, config: RouteConfig): FluentBuilder;
424
- delete(path: string, handler: Handler): FluentBuilder;
425
- delete(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
431
+ delete(path: string, config: RouteConfig): Route;
432
+ delete(path: string, handler: Handler): Route;
433
+ delete(path: string, options: RouteOptions, handler: Handler): Route;
426
434
  delete(path: string): FluentBuilder;
427
- private addRoute;
435
+ addRoute(method: string, path: string): Route;
428
436
  registerHandler(handler: Handler, serializer?: (doc: any) => string): number;
429
437
  listen(portOrOptions: number | ListenOptions, cb?: () => void): void;
430
438
  stop(): void;
431
439
  }
440
+ declare class Route implements RouteBuilder {
441
+ path: string;
442
+ method: string;
443
+ private app;
444
+ handlerId: number | null;
445
+ routeConfig: RouteConfig | undefined;
446
+ options: any;
447
+ description: string | undefined;
448
+ middlewares: Middleware[];
449
+ handler?: Handler;
450
+ private serializer;
451
+ constructor(path: string, method: string, app: App);
452
+ desc(description: string): this;
453
+ auth(strategy?: string): this;
454
+ jwt(): this;
455
+ cache(options: {
456
+ ttl: number;
457
+ key?: string;
458
+ }): this;
459
+ rateLimit(options: {
460
+ limit: number;
461
+ window: number;
462
+ }): this;
463
+ query(schemaBuilder: (q: QueryBuilder) => void): this;
464
+ schema(def: any): this;
465
+ priority(level: 'critical' | 'interactive' | 'background'): this;
466
+ slo(targetMs: number): this;
467
+ responseSchema(def: any): this;
468
+ respond(handler: Handler): void;
469
+ }
432
470
 
433
- export { App, type DatabaseContext, type EnvContext, FluentBuilder, type Handler, type ListenOptions, type Middleware, type NextFunction, Q, type QueryBuilder, type QueryField, type RequestContext, type RequestMetrics, type RequestSnapshot, type Route, type RouteBuilder, type RouteConfig, type RouteOptions, TestClient, type UploadConfig, type WebSocket, type WsHandler, createTestClient };
471
+ export { App, type DatabaseContext, type EnvContext, FluentBuilder, type Handler, type ListenOptions, type Middleware, type NextFunction, Q, type QueryBuilder, type QueryField, type RequestContext, type RequestMetrics, type RequestSnapshot, type Route$1 as Route, type RouteBuilder, type RouteConfig, type RouteOptions, TestClient, type UploadConfig, type WebSocket, type WsHandler, createTestClient };
package/dist/index.d.ts CHANGED
@@ -87,7 +87,7 @@ interface RouteOptions {
87
87
  priority?: 'critical' | 'interactive' | 'background';
88
88
  sloTarget?: number;
89
89
  }
90
- interface Route {
90
+ interface Route$1 {
91
91
  method: string;
92
92
  path: string;
93
93
  handler?: Handler;
@@ -161,6 +161,7 @@ interface FluentBuilder$1 {
161
161
  expiresIn?: string;
162
162
  }): this;
163
163
  respond(status?: number): void;
164
+ respond(handler: Handler): void;
164
165
  secure(): this;
165
166
  autoFilter(table: string, allow: string[], options?: {
166
167
  sort?: string[];
@@ -208,18 +209,23 @@ interface App$1 {
208
209
  auth: {
209
210
  setJwtSecret(secret: string): void;
210
211
  };
211
- get(path: string, config: RouteConfig): RouteBuilder;
212
- get(path: string, handler: Handler): RouteBuilder;
213
- get(path: string): RouteBuilder;
214
- post(path: string, config: RouteConfig): RouteBuilder;
215
- post(path: string, handler: Handler): RouteBuilder;
216
- post(path: string): RouteBuilder;
217
- put(path: string, config: RouteConfig): RouteBuilder;
218
- put(path: string, handler: Handler): RouteBuilder;
219
- put(path: string): RouteBuilder;
220
- delete(path: string, config: RouteConfig): RouteBuilder;
221
- delete(path: string, handler: Handler): RouteBuilder;
222
- delete(path: string): RouteBuilder;
212
+ get(path: string, config: RouteConfig): Route$1;
213
+ get(path: string, handler: Handler): Route$1;
214
+ get(path: string, options: RouteOptions, handler: Handler): Route$1;
215
+ get(path: string): FluentBuilder$1;
216
+ post(path: string, config: RouteConfig): Route$1;
217
+ post(path: string, handler: Handler): Route$1;
218
+ post(path: string, options: RouteOptions, handler: Handler): Route$1;
219
+ post(path: string): FluentBuilder$1;
220
+ put(path: string, config: RouteConfig): Route$1;
221
+ put(path: string, handler: Handler): Route$1;
222
+ put(path: string, options: RouteOptions, handler: Handler): Route$1;
223
+ put(path: string): FluentBuilder$1;
224
+ delete(path: string, config: RouteConfig): Route$1;
225
+ delete(path: string, handler: Handler): Route$1;
226
+ delete(path: string, options: RouteOptions, handler: Handler): Route$1;
227
+ delete(path: string): FluentBuilder$1;
228
+ addRoute(method: string, path: string): Route$1;
223
229
  listen(port: number, callback?: () => void): void;
224
230
  listen(options: ListenOptions): void;
225
231
  stop(): void;
@@ -260,6 +266,8 @@ declare class FluentBuilder {
260
266
  private requestSchema?;
261
267
  private responseSchemaDef?;
262
268
  private queryBuilder?;
269
+ private rateLimitOptions?;
270
+ private cacheOptions?;
263
271
  constructor(app: App$1, method: string, path: string);
264
272
  desc(description: string): this;
265
273
  auth(strategy?: string): this;
@@ -408,26 +416,56 @@ declare class App implements App$1 {
408
416
  headers?: string[];
409
417
  credentials?: boolean;
410
418
  }): this;
411
- get(path: string, config: RouteConfig): FluentBuilder;
412
- get(path: string, handler: Handler): FluentBuilder;
413
- get(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
419
+ get(path: string, config: RouteConfig): Route;
420
+ get(path: string, handler: Handler): Route;
421
+ get(path: string, options: RouteOptions, handler: Handler): Route;
414
422
  get(path: string): FluentBuilder;
415
- post(path: string, config: RouteConfig): FluentBuilder;
416
- post(path: string, handler: Handler): FluentBuilder;
417
- post(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
423
+ post(path: string, config: RouteConfig): Route;
424
+ post(path: string, handler: Handler): Route;
425
+ post(path: string, options: RouteOptions, handler: Handler): Route;
418
426
  post(path: string): FluentBuilder;
419
- put(path: string, config: RouteConfig): FluentBuilder;
420
- put(path: string, handler: Handler): FluentBuilder;
421
- put(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
427
+ put(path: string, config: RouteConfig): Route;
428
+ put(path: string, handler: Handler): Route;
429
+ put(path: string, options: RouteOptions, handler: Handler): Route;
422
430
  put(path: string): FluentBuilder;
423
- delete(path: string, config: RouteConfig): FluentBuilder;
424
- delete(path: string, handler: Handler): FluentBuilder;
425
- delete(path: string, options: RouteOptions, handler: Handler): FluentBuilder;
431
+ delete(path: string, config: RouteConfig): Route;
432
+ delete(path: string, handler: Handler): Route;
433
+ delete(path: string, options: RouteOptions, handler: Handler): Route;
426
434
  delete(path: string): FluentBuilder;
427
- private addRoute;
435
+ addRoute(method: string, path: string): Route;
428
436
  registerHandler(handler: Handler, serializer?: (doc: any) => string): number;
429
437
  listen(portOrOptions: number | ListenOptions, cb?: () => void): void;
430
438
  stop(): void;
431
439
  }
440
+ declare class Route implements RouteBuilder {
441
+ path: string;
442
+ method: string;
443
+ private app;
444
+ handlerId: number | null;
445
+ routeConfig: RouteConfig | undefined;
446
+ options: any;
447
+ description: string | undefined;
448
+ middlewares: Middleware[];
449
+ handler?: Handler;
450
+ private serializer;
451
+ constructor(path: string, method: string, app: App);
452
+ desc(description: string): this;
453
+ auth(strategy?: string): this;
454
+ jwt(): this;
455
+ cache(options: {
456
+ ttl: number;
457
+ key?: string;
458
+ }): this;
459
+ rateLimit(options: {
460
+ limit: number;
461
+ window: number;
462
+ }): this;
463
+ query(schemaBuilder: (q: QueryBuilder) => void): this;
464
+ schema(def: any): this;
465
+ priority(level: 'critical' | 'interactive' | 'background'): this;
466
+ slo(targetMs: number): this;
467
+ responseSchema(def: any): this;
468
+ respond(handler: Handler): void;
469
+ }
432
470
 
433
- export { App, type DatabaseContext, type EnvContext, FluentBuilder, type Handler, type ListenOptions, type Middleware, type NextFunction, Q, type QueryBuilder, type QueryField, type RequestContext, type RequestMetrics, type RequestSnapshot, type Route, type RouteBuilder, type RouteConfig, type RouteOptions, TestClient, type UploadConfig, type WebSocket, type WsHandler, createTestClient };
471
+ export { App, type DatabaseContext, type EnvContext, FluentBuilder, type Handler, type ListenOptions, type Middleware, type NextFunction, Q, type QueryBuilder, type QueryField, type RequestContext, type RequestMetrics, type RequestSnapshot, type Route$1 as Route, type RouteBuilder, type RouteConfig, type RouteOptions, TestClient, type UploadConfig, type WebSocket, type WsHandler, createTestClient };
package/dist/index.js CHANGED
@@ -557,6 +557,8 @@ var FluentBuilder = class {
557
557
  requestSchema;
558
558
  responseSchemaDef;
559
559
  queryBuilder;
560
+ rateLimitOptions;
561
+ cacheOptions;
560
562
  // RouteBuilder compatibility methods
561
563
  desc(description) {
562
564
  this.steps.push({
@@ -577,6 +579,7 @@ var FluentBuilder = class {
577
579
  return this;
578
580
  }
579
581
  cache(options) {
582
+ this.cacheOptions = options;
580
583
  this.steps.push({
581
584
  name: "cache",
582
585
  fn: (ctx, state) => {
@@ -586,6 +589,7 @@ var FluentBuilder = class {
586
589
  return this;
587
590
  }
588
591
  rateLimit(options) {
592
+ this.rateLimitOptions = options;
589
593
  this.steps.push({
590
594
  name: "rateLimit",
591
595
  fn: (ctx, state) => {
@@ -827,7 +831,10 @@ var FluentBuilder = class {
827
831
  }
828
832
  const status = handlerOrStatus;
829
833
  const handler = async (ctx) => {
830
- let state = {};
834
+ let state = {
835
+ params: ctx.params || {},
836
+ query: ctx.query || {}
837
+ };
831
838
  let finalStatus = status;
832
839
  try {
833
840
  for (const step of this.steps) {
@@ -848,7 +855,8 @@ var FluentBuilder = class {
848
855
  ctx.json({ error: message }, status2);
849
856
  }
850
857
  };
851
- const route = this.app[this.method.toLowerCase()](this.path, handler);
858
+ const route = this.app.addRoute(this.method, this.path);
859
+ route.handler = handler;
852
860
  this.applyOptionsToRoute(route);
853
861
  }
854
862
  applyOptionsToRoute(route) {
@@ -861,6 +869,12 @@ var FluentBuilder = class {
861
869
  if (this.queryBuilder) {
862
870
  route.query(this.queryBuilder);
863
871
  }
872
+ if (this.rateLimitOptions) {
873
+ route.rateLimit(this.rateLimitOptions);
874
+ }
875
+ if (this.cacheOptions) {
876
+ route.cache(this.cacheOptions);
877
+ }
864
878
  if (this.useJwt) {
865
879
  route.jwt();
866
880
  }
@@ -1634,76 +1648,88 @@ var App = class {
1634
1648
  return this;
1635
1649
  }
1636
1650
  get(path2, arg2, arg3) {
1637
- const fluentBuilder = new FluentBuilder(this, "GET", path2);
1638
1651
  if (arg3) {
1639
1652
  const route = this.addRoute("GET", path2);
1640
1653
  route.options = arg2;
1641
1654
  route.handler = arg3;
1655
+ return route;
1642
1656
  } else if (arg2) {
1643
1657
  const route = this.addRoute("GET", path2);
1644
1658
  if (typeof arg2 === "function") {
1645
1659
  route.handler = arg2;
1660
+ return route;
1646
1661
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1647
1662
  route.routeConfig = arg2;
1663
+ return route;
1648
1664
  } else {
1649
1665
  route.options = arg2;
1666
+ return route;
1650
1667
  }
1651
1668
  }
1652
- return fluentBuilder;
1669
+ return new FluentBuilder(this, "GET", path2);
1653
1670
  }
1654
1671
  post(path2, arg2, arg3) {
1655
- const fluentBuilder = new FluentBuilder(this, "POST", path2);
1656
1672
  if (arg3) {
1657
1673
  const route = this.addRoute("POST", path2);
1658
1674
  route.options = arg2;
1659
1675
  route.handler = arg3;
1676
+ return route;
1660
1677
  } else if (arg2) {
1661
1678
  const route = this.addRoute("POST", path2);
1662
1679
  if (typeof arg2 === "function") {
1663
1680
  route.handler = arg2;
1681
+ return route;
1664
1682
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1665
1683
  route.routeConfig = arg2;
1684
+ return route;
1666
1685
  } else {
1667
1686
  route.options = arg2;
1687
+ return route;
1668
1688
  }
1669
1689
  }
1670
- return fluentBuilder;
1690
+ return new FluentBuilder(this, "POST", path2);
1671
1691
  }
1672
1692
  put(path2, arg2, arg3) {
1673
- const fluentBuilder = new FluentBuilder(this, "PUT", path2);
1674
1693
  if (arg3) {
1675
1694
  const route = this.addRoute("PUT", path2);
1676
1695
  route.options = arg2;
1677
1696
  route.handler = arg3;
1697
+ return route;
1678
1698
  } else if (arg2) {
1679
1699
  const route = this.addRoute("PUT", path2);
1680
1700
  if (typeof arg2 === "function") {
1681
1701
  route.handler = arg2;
1702
+ return route;
1682
1703
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1683
1704
  route.routeConfig = arg2;
1705
+ return route;
1684
1706
  } else {
1685
1707
  route.options = arg2;
1708
+ return route;
1686
1709
  }
1687
1710
  }
1688
- return fluentBuilder;
1711
+ return new FluentBuilder(this, "PUT", path2);
1689
1712
  }
1690
1713
  delete(path2, arg2, arg3) {
1691
- const fluentBuilder = new FluentBuilder(this, "DELETE", path2);
1692
1714
  if (arg3) {
1693
1715
  const route = this.addRoute("DELETE", path2);
1694
1716
  route.options = arg2;
1695
1717
  route.handler = arg3;
1718
+ return route;
1696
1719
  } else if (arg2) {
1697
1720
  const route = this.addRoute("DELETE", path2);
1698
1721
  if (typeof arg2 === "function") {
1699
1722
  route.handler = arg2;
1723
+ return route;
1700
1724
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1701
1725
  route.routeConfig = arg2;
1726
+ return route;
1702
1727
  } else {
1703
1728
  route.options = arg2;
1729
+ return route;
1704
1730
  }
1705
1731
  }
1706
- return fluentBuilder;
1732
+ return new FluentBuilder(this, "DELETE", path2);
1707
1733
  }
1708
1734
  addRoute(method, path2) {
1709
1735
  const route = new Route(path2, method, this);
@@ -1840,9 +1866,14 @@ var App = class {
1840
1866
  options
1841
1867
  );
1842
1868
  }
1843
- } else if (route.handlerId) {
1869
+ } else if (route.handlerId || route.handler) {
1844
1870
  try {
1845
- this.engine.registerRoute(route.method, enginePath, route.handlerId, options);
1871
+ if (!route.handlerId && route.handler) {
1872
+ route.handlerId = this.registerHandler(route.handler);
1873
+ }
1874
+ if (route.handlerId) {
1875
+ this.engine.registerRoute(route.method, enginePath, route.handlerId, options);
1876
+ }
1846
1877
  } catch (e) {
1847
1878
  console.error(`Failed to register route ${route.method} ${route.path}:`, e);
1848
1879
  }
package/dist/index.mjs CHANGED
@@ -466,6 +466,8 @@ var FluentBuilder = class {
466
466
  requestSchema;
467
467
  responseSchemaDef;
468
468
  queryBuilder;
469
+ rateLimitOptions;
470
+ cacheOptions;
469
471
  // RouteBuilder compatibility methods
470
472
  desc(description) {
471
473
  this.steps.push({
@@ -486,6 +488,7 @@ var FluentBuilder = class {
486
488
  return this;
487
489
  }
488
490
  cache(options) {
491
+ this.cacheOptions = options;
489
492
  this.steps.push({
490
493
  name: "cache",
491
494
  fn: (ctx, state) => {
@@ -495,6 +498,7 @@ var FluentBuilder = class {
495
498
  return this;
496
499
  }
497
500
  rateLimit(options) {
501
+ this.rateLimitOptions = options;
498
502
  this.steps.push({
499
503
  name: "rateLimit",
500
504
  fn: (ctx, state) => {
@@ -736,7 +740,10 @@ var FluentBuilder = class {
736
740
  }
737
741
  const status = handlerOrStatus;
738
742
  const handler = async (ctx) => {
739
- let state = {};
743
+ let state = {
744
+ params: ctx.params || {},
745
+ query: ctx.query || {}
746
+ };
740
747
  let finalStatus = status;
741
748
  try {
742
749
  for (const step of this.steps) {
@@ -757,7 +764,8 @@ var FluentBuilder = class {
757
764
  ctx.json({ error: message }, status2);
758
765
  }
759
766
  };
760
- const route = this.app[this.method.toLowerCase()](this.path, handler);
767
+ const route = this.app.addRoute(this.method, this.path);
768
+ route.handler = handler;
761
769
  this.applyOptionsToRoute(route);
762
770
  }
763
771
  applyOptionsToRoute(route) {
@@ -770,6 +778,12 @@ var FluentBuilder = class {
770
778
  if (this.queryBuilder) {
771
779
  route.query(this.queryBuilder);
772
780
  }
781
+ if (this.rateLimitOptions) {
782
+ route.rateLimit(this.rateLimitOptions);
783
+ }
784
+ if (this.cacheOptions) {
785
+ route.cache(this.cacheOptions);
786
+ }
773
787
  if (this.useJwt) {
774
788
  route.jwt();
775
789
  }
@@ -1543,76 +1557,88 @@ var App = class {
1543
1557
  return this;
1544
1558
  }
1545
1559
  get(path, arg2, arg3) {
1546
- const fluentBuilder = new FluentBuilder(this, "GET", path);
1547
1560
  if (arg3) {
1548
1561
  const route = this.addRoute("GET", path);
1549
1562
  route.options = arg2;
1550
1563
  route.handler = arg3;
1564
+ return route;
1551
1565
  } else if (arg2) {
1552
1566
  const route = this.addRoute("GET", path);
1553
1567
  if (typeof arg2 === "function") {
1554
1568
  route.handler = arg2;
1569
+ return route;
1555
1570
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1556
1571
  route.routeConfig = arg2;
1572
+ return route;
1557
1573
  } else {
1558
1574
  route.options = arg2;
1575
+ return route;
1559
1576
  }
1560
1577
  }
1561
- return fluentBuilder;
1578
+ return new FluentBuilder(this, "GET", path);
1562
1579
  }
1563
1580
  post(path, arg2, arg3) {
1564
- const fluentBuilder = new FluentBuilder(this, "POST", path);
1565
1581
  if (arg3) {
1566
1582
  const route = this.addRoute("POST", path);
1567
1583
  route.options = arg2;
1568
1584
  route.handler = arg3;
1585
+ return route;
1569
1586
  } else if (arg2) {
1570
1587
  const route = this.addRoute("POST", path);
1571
1588
  if (typeof arg2 === "function") {
1572
1589
  route.handler = arg2;
1590
+ return route;
1573
1591
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1574
1592
  route.routeConfig = arg2;
1593
+ return route;
1575
1594
  } else {
1576
1595
  route.options = arg2;
1596
+ return route;
1577
1597
  }
1578
1598
  }
1579
- return fluentBuilder;
1599
+ return new FluentBuilder(this, "POST", path);
1580
1600
  }
1581
1601
  put(path, arg2, arg3) {
1582
- const fluentBuilder = new FluentBuilder(this, "PUT", path);
1583
1602
  if (arg3) {
1584
1603
  const route = this.addRoute("PUT", path);
1585
1604
  route.options = arg2;
1586
1605
  route.handler = arg3;
1606
+ return route;
1587
1607
  } else if (arg2) {
1588
1608
  const route = this.addRoute("PUT", path);
1589
1609
  if (typeof arg2 === "function") {
1590
1610
  route.handler = arg2;
1611
+ return route;
1591
1612
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1592
1613
  route.routeConfig = arg2;
1614
+ return route;
1593
1615
  } else {
1594
1616
  route.options = arg2;
1617
+ return route;
1595
1618
  }
1596
1619
  }
1597
- return fluentBuilder;
1620
+ return new FluentBuilder(this, "PUT", path);
1598
1621
  }
1599
1622
  delete(path, arg2, arg3) {
1600
- const fluentBuilder = new FluentBuilder(this, "DELETE", path);
1601
1623
  if (arg3) {
1602
1624
  const route = this.addRoute("DELETE", path);
1603
1625
  route.options = arg2;
1604
1626
  route.handler = arg3;
1627
+ return route;
1605
1628
  } else if (arg2) {
1606
1629
  const route = this.addRoute("DELETE", path);
1607
1630
  if (typeof arg2 === "function") {
1608
1631
  route.handler = arg2;
1632
+ return route;
1609
1633
  } else if ("json" in arg2 || "text" in arg2 || "upload" in arg2) {
1610
1634
  route.routeConfig = arg2;
1635
+ return route;
1611
1636
  } else {
1612
1637
  route.options = arg2;
1638
+ return route;
1613
1639
  }
1614
1640
  }
1615
- return fluentBuilder;
1641
+ return new FluentBuilder(this, "DELETE", path);
1616
1642
  }
1617
1643
  addRoute(method, path) {
1618
1644
  const route = new Route(path, method, this);
@@ -1749,9 +1775,14 @@ var App = class {
1749
1775
  options
1750
1776
  );
1751
1777
  }
1752
- } else if (route.handlerId) {
1778
+ } else if (route.handlerId || route.handler) {
1753
1779
  try {
1754
- this.engine.registerRoute(route.method, enginePath, route.handlerId, options);
1780
+ if (!route.handlerId && route.handler) {
1781
+ route.handlerId = this.registerHandler(route.handler);
1782
+ }
1783
+ if (route.handlerId) {
1784
+ this.engine.registerRoute(route.method, enginePath, route.handlerId, options);
1785
+ }
1755
1786
  } catch (e) {
1756
1787
  console.error(`Failed to register route ${route.method} ${route.path}:`, e);
1757
1788
  }
Binary file
@@ -7,18 +7,20 @@ const app = Q.app();
7
7
  // Just by connecting Redis, all rate limits become distributed!
8
8
  // app.db.connectRedis("redis://127.0.0.1:6379");
9
9
 
10
- app.get('/expensive', (c) => {
11
- return c.send({ data: "Expensive computation" });
12
- })
13
- .rateLimit({ limit: 10, window: 60 }); // 10 reqs / min shared across ALL instances
10
+ app.get('/expensive')
11
+ .rateLimit({ limit: 10, window: 60 })
12
+ .use(() => ({ data: "Expensive computation" }))
13
+ .respond();
14
14
 
15
15
  // 2. Native Redis Access
16
16
  // Use the shared Redis connection for your own data
17
- app.get('/cache', async (c) => {
18
- await app.db.redis.set("my_key", "hello from rust", 300);
19
- const val = await app.db.redis.get("my_key");
20
- return c.send({ val });
21
- });
17
+ app.get('/cache')
18
+ .use(async () => {
19
+ await app.db.redis.set("my_key", "hello from rust", 300);
20
+ const val = await app.db.redis.get("my_key");
21
+ return { val };
22
+ })
23
+ .respond();
22
24
 
23
25
  app.listen(3000, () => {
24
26
  console.log('Server running on http://localhost:3000');
@@ -10,13 +10,13 @@ app.cors({
10
10
  credentials: true
11
11
  });
12
12
 
13
- app.get('/', (c) => {
14
- return c.send({ message: 'Hello with CORS!' });
15
- });
13
+ app.get('/')
14
+ .use(() => ({ message: 'Hello with CORS!' }))
15
+ .respond();
16
16
 
17
- app.post('/data', (c) => {
18
- return c.send({ status: 'received' });
19
- });
17
+ app.post('/data')
18
+ .use(() => ({ status: 'received' }))
19
+ .respond();
20
20
 
21
21
  const PORT = 4000;
22
22
  app.listen(PORT, () => {
@@ -19,35 +19,40 @@ const SECRET = 'native-super-secret-key-123';
19
19
  // the connection might fail, but the architecture is valid.
20
20
  const PG_URL = "postgres://user:pass@localhost:5432/mydb";
21
21
 
22
- app.get('/public', (c) => {
23
- return c.send({ message: "Public Access OK" });
24
- });
22
+ app.get('/public')
23
+ .use(() => ({ message: "Public Access OK" }))
24
+ .respond();
25
25
 
26
26
  // Protected Route (Native JWT Check)
27
27
  // If the token is invalid, Rust rejects it. Node.js never sees the request.
28
- app.get('/protected', (c) => {
29
- return c.send({ message: "You have valid Native JWT!" });
30
- })
31
- .jwt(); // Enable Native JWT Policy
28
+ app.get('/protected')
29
+ .jwt() // Enable Native JWT Policy
30
+ .use(() => ({ message: "You have valid Native JWT!" }))
31
+ .respond();
32
32
 
33
33
  // Database Route
34
- app.get('/users', async (c) => {
35
- // This executes SQL in Rust and returns JSON string directly
36
- // Zero serialization overhead in Node.js!
37
- try {
38
- const result = await app.db.query("SELECT * FROM users");
39
- // Result is a JSON string string from Rust
40
- return c.send(JSON.parse(result));
41
- } catch (e: any) {
42
- return c.send({ error: e.message });
43
- }
44
- });
34
+ app.get('/users')
35
+ .use(async (ctx) => {
36
+ // This executes SQL in Rust and returns JSON string directly
37
+ // Zero serialization overhead in Node.js!
38
+ try {
39
+ const result = await app.db.query("SELECT * FROM users");
40
+ // Result is a JSON string string from Rust
41
+ return JSON.parse(result);
42
+ } catch (e: any) {
43
+ // Fluent API handles errors if we throw with status
44
+ throw { status: 500, message: e.message };
45
+ }
46
+ })
47
+ .respond();
45
48
 
46
49
  // Helper to generate token for testing
47
- app.get('/login', (c) => {
48
- const token = jsonwebtoken.sign({ sub: 'user123' }, SECRET, { expiresIn: '1h' });
49
- return c.send({ token });
50
- });
50
+ app.get('/login')
51
+ .use(() => {
52
+ const token = jsonwebtoken.sign({ sub: 'user123' }, SECRET, { expiresIn: '1h' });
53
+ return { token };
54
+ })
55
+ .respond();
51
56
 
52
57
  app.listen(3000, () => {
53
58
  console.log('Server running on http://localhost:3000');
package/examples/hello.ts CHANGED
@@ -2,6 +2,10 @@ import { Q } from '../src';
2
2
 
3
3
  const app = Q.app();
4
4
 
5
+ app.get('/')
6
+ .use(() => ({ message: 'Hello World' }))
7
+ .respond();
8
+
5
9
  app.listen(3000, () => {
6
10
  console.log("Server started on port 3000");
7
11
  });
@@ -5,9 +5,9 @@ import http from 'http';
5
5
 
6
6
  const app = Q.app();
7
7
 
8
- app.get('/h2', (c) => {
9
- c.send('Hello from QHTTPX!');
10
- });
8
+ app.get('/h2')
9
+ .use(() => 'Hello from QHTTPX!')
10
+ .respond();
11
11
 
12
12
  app.listen(3003, async () => {
13
13
  console.log('Server listening on port 3003');
@@ -3,12 +3,12 @@ import { Q } from '../src';
3
3
 
4
4
  const app = Q.app();
5
5
 
6
- app.get('/', () => {
7
- return {
8
- message: "Hello from Magic Dev Mode! ✨",
9
- timestamp: new Date().toISOString()
10
- };
11
- });
6
+ app.get('/')
7
+ .use(() => ({
8
+ message: "Hello from Magic Dev Mode! ✨",
9
+ timestamp: new Date().toISOString()
10
+ }))
11
+ .respond();
12
12
 
13
13
  app.listen(3000, () => {
14
14
  console.log("Server running on http://localhost:3000");
@@ -4,28 +4,30 @@ const app = Q.app();
4
4
 
5
5
  // 1. Rate Limited Route
6
6
  // Limit: 5 requests per 10 seconds
7
- app.get('/limited', (ctx) => {
8
- return ctx.send({ message: "I am rate limited!" });
9
- })
10
- .rateLimit({ limit: 5, window: 10 });
7
+ app.get('/limited')
8
+ .rateLimit({ limit: 5, window: 10 })
9
+ .use(() => ({ message: "I am rate limited!" }))
10
+ .respond();
11
11
 
12
12
  // 2. Cached Route
13
13
  // TTL: 10 seconds
14
14
  // The handler sleeps for 2 seconds to simulate slow work
15
- app.get('/cached', async (ctx) => {
16
- // Simulate slow DB call
17
- await new Promise(resolve => setTimeout(resolve, 2000));
18
- return ctx.send({
19
- message: "I am cached!",
20
- timestamp: Date.now()
21
- });
22
- })
23
- .cache({ ttl: 10 });
15
+ app.get('/cached')
16
+ .cache({ ttl: 10 })
17
+ .use(async () => {
18
+ // Simulate slow DB call
19
+ await new Promise(resolve => setTimeout(resolve, 2000));
20
+ return {
21
+ message: "I am cached!",
22
+ timestamp: Date.now()
23
+ };
24
+ })
25
+ .respond();
24
26
 
25
27
  // 3. Normal Route
26
- app.get('/normal', (ctx) => {
27
- return ctx.send({ message: "I am normal" });
28
- });
28
+ app.get('/normal')
29
+ .use(() => ({ message: "I am normal" }))
30
+ .respond();
29
31
 
30
32
  app.listen(3000, () => {
31
33
  console.log('Middleware Demo running on http://localhost:3000');
@@ -6,30 +6,34 @@ const app = Q.app();
6
6
  // 1. Native Query Caching
7
7
  // SQL executed in Rust, result cached in Rust memory (DashMap)
8
8
  // Second request returns instantly without DB roundtrip!
9
- app.get('/users/cached', async (c) => {
10
- try {
11
- // Query with 60 second TTL
12
- const json = await app.db.query("SELECT * FROM users", 60);
13
- return c.send(JSON.parse(json));
14
- } catch (e: any) {
15
- return c.send({ error: e.message });
16
- }
17
- });
9
+ app.get('/users/cached')
10
+ .use(async (ctx) => {
11
+ try {
12
+ // Query with 60 second TTL
13
+ const json = await app.db.query("SELECT * FROM users", 60);
14
+ return JSON.parse(json);
15
+ } catch (e: any) {
16
+ return { error: e.message };
17
+ }
18
+ })
19
+ .respond();
18
20
 
19
21
  // 2. Native MongoDB Support
20
22
  // Query executed in Rust via mongodb crate
21
23
  // BSON -> JSON conversion happens in Rust
22
- app.get('/logs', async (c) => {
23
- try {
24
- const logs = await app.db.mongo("my_db", "logs").find({
25
- level: "error",
26
- timestamp: { $gt: 1700000000 }
27
- });
28
- return c.send(logs);
29
- } catch (e: any) {
30
- return c.send({ error: e.message });
31
- }
32
- });
24
+ app.get('/logs')
25
+ .use(async (ctx) => {
26
+ try {
27
+ const logs = await app.db.mongo("my_db", "logs").find({
28
+ level: "error",
29
+ timestamp: { $gt: 1700000000 }
30
+ });
31
+ return logs;
32
+ } catch (e: any) {
33
+ return { error: e.message };
34
+ }
35
+ })
36
+ .respond();
33
37
 
34
38
  app.listen(3000, () => {
35
39
  console.log('Server running on http://localhost:3000');
@@ -7,13 +7,15 @@ const app = Q.app();
7
7
  // Run with RUST_LOG=info node observability_demo.js
8
8
  app.enableLogging();
9
9
 
10
- app.get('/', (c) => {
11
- return c.send({ message: "Hello Observability" });
12
- });
10
+ app.get('/')
11
+ .use(() => ({ message: "Hello Observability" }))
12
+ .respond();
13
13
 
14
- app.get('/error', (c) => {
15
- throw new Error("Something went wrong");
16
- });
14
+ app.get('/error')
15
+ .use(() => {
16
+ throw new Error("Something went wrong");
17
+ })
18
+ .respond();
17
19
 
18
20
  // 2. Metrics are automatically exposed at /metrics
19
21
  // Try: curl http://localhost:3000/metrics
@@ -19,9 +19,9 @@ fs.writeFileSync(path.join(publicDir, '1mb.dat'), buffer);
19
19
  // Serve static files
20
20
  app.static('/public', './examples/public');
21
21
 
22
- app.get('/', (c: any) => {
23
- return c.send({ hello: 'world' });
24
- });
22
+ app.get('/')
23
+ .use(() => ({ hello: 'world' }))
24
+ .respond();
25
25
 
26
26
  app.listen(PORT, () => {
27
27
  console.log(`Static File Server running on port ${PORT}`);
@@ -16,9 +16,9 @@ if (!fs.existsSync(certPath) || !fs.existsSync(keyPath)) {
16
16
  process.exit(1);
17
17
  }
18
18
 
19
- app.get('/', (c) => {
20
- return c.send({ message: "Secure Hello from Native HTTP/2!" });
21
- });
19
+ app.get('/')
20
+ .use(() => ({ message: "Secure Hello from Native HTTP/2!" }))
21
+ .respond();
22
22
 
23
23
  app.listen({
24
24
  port: 3000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qhttpx",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "The AI-Native High-Performance Web Engine",
5
5
  "bin": {
6
6
  "qhttpx": "./dist/cli.js"