balda 0.0.50 → 0.0.52

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/lib/index.d.cts CHANGED
@@ -95,12 +95,18 @@ type InferBodyType<T> = T extends RequestSchema ? ValidatedData<T> : unknown;
95
95
  type InferQueryType<T> = T extends RequestSchema ? ValidatedData<T> : Record<string, string>;
96
96
  /**
97
97
  * Extracts the body type for a specific HTTP status code from a response map.
98
- * When the status code has a schema defined, enforces exact type matching.
98
+ * When the status code has a schema defined, enforces type matching with widened
99
+ * literals (string literals → string, number literals → number, etc.) so that
100
+ * natural TypeScript return values like `{ status: "ok" }` are accepted without
101
+ * requiring `as const`.
99
102
  * Defaults to `any` when the status code is not present in the map.
100
103
  */
101
- type ResponseBodyForStatus<TMap, TStatus extends number> = TStatus extends keyof TMap ? 0 extends 1 & TMap[TStatus] ? any : {
104
+ type WidenLiterals<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends (infer U)[] ? WidenLiterals<U>[] : T extends object ? {
105
+ [K in keyof T]: WidenLiterals<T[K]>;
106
+ } : T;
107
+ type ResponseBodyForStatus<TMap, TStatus extends number> = TStatus extends keyof TMap ? 0 extends 1 & TMap[TStatus] ? any : WidenLiterals<{
102
108
  [K in keyof TMap[TStatus]]: TMap[TStatus][K];
103
- } : any;
109
+ }> : any;
104
110
 
105
111
  type SyncOrAsync<T = void> = T | Promise<T>;
106
112
 
@@ -322,14 +328,12 @@ declare class Request<Params extends Record<string, string> = any, TBody = unkno
322
328
  * @fileParser middleware is required
323
329
  */
324
330
  file(fieldName: string): FormFile | null;
325
- /**
326
- * The cookies of the request.
327
- * @cookie middleware is required
328
- */
329
- cookies: Record<string, string>;
331
+ get cookies(): Record<string, string>;
332
+ set cookies(value: Record<string, string>);
330
333
  /**
331
334
  * The cookie of the request.
332
335
  * @cookie middleware is required
336
+ * @throws Error if cookie middleware is not registered
333
337
  */
334
338
  cookie(name: string): string | undefined;
335
339
  /**
@@ -337,27 +341,26 @@ declare class Request<Params extends Record<string, string> = any, TBody = unkno
337
341
  * @timeout middleware is required
338
342
  */
339
343
  timeout?: boolean;
344
+ get session(): Record<string, any> | undefined;
345
+ set session(value: Record<string, any> | undefined);
340
346
  /**
341
- * The session of the request. Uses cookies to send the session id
342
- * @cookie middleware is required
343
- * @session middleware is required
344
- */
345
- session?: Record<string, any>;
346
- /**
347
- * Shared no-op async function to avoid per-instance closure allocation.
347
+ * Shared throwing functions to avoid per-instance closure allocation.
348
348
  * @internal
349
349
  */
350
- private static readonly _noopAsync;
350
+ private static readonly _throwSaveSession;
351
+ private static readonly _throwDestroySession;
351
352
  /**
352
- * The session of the request. Uses cookies to send the session id
353
+ * Save the current session data.
353
354
  * @cookie middleware is required
354
355
  * @session middleware is required
356
+ * @throws Error if session middleware is not registered
355
357
  */
356
358
  saveSession: () => Promise<void>;
357
359
  /**
358
- * The session of the request.
360
+ * Destroy the current session.
359
361
  * @cookie middleware is required
360
362
  * @session middleware is required
363
+ * @throws Error if session middleware is not registered
361
364
  */
362
365
  destroySession: () => Promise<void>;
363
366
  get ip(): string | undefined;
@@ -1590,6 +1593,103 @@ declare class NativeFs {
1590
1593
  }
1591
1594
  declare const nativeFs: NativeFs;
1592
1595
 
1596
+ /**
1597
+ * The next function.
1598
+ * This is the function that is passed to the handler function.
1599
+ * It has a pointer to the next middleware or handler function of the middleware chain.
1600
+ */
1601
+ type NextFunction = () => SyncOrAsync;
1602
+
1603
+ /**
1604
+ * A middleware that carries type information about the properties it adds to the request.
1605
+ * Uses a phantom branded property to flow type info through the type system without runtime cost.
1606
+ *
1607
+ * @template TExtension - The properties this middleware adds to the request object
1608
+ *
1609
+ * @example
1610
+ * ```typescript
1611
+ * const auth = defineMiddleware<{ userId: number }>((req, res, next) => {
1612
+ * req.userId = getUserIdFromToken(req.headers);
1613
+ * return next();
1614
+ * });
1615
+ *
1616
+ * router.get("/profile", { middlewares: [auth] }, (req, res) => {
1617
+ * req.userId; // number — inferred from middleware!
1618
+ * });
1619
+ * ```
1620
+ */
1621
+ type TypedMiddleware<TExtension extends Record<string, any> = Record<string, never>> = ((req: Request & TExtension, res: Response$1, next: NextFunction) => SyncOrAsync) & {
1622
+ readonly __middlewareExtension?: TExtension;
1623
+ };
1624
+ /**
1625
+ * Helper to create a typed middleware with correct request typing inside the middleware body.
1626
+ * The returned function is branded with the extension type so the router can infer it.
1627
+ *
1628
+ * @template TExtension - The properties this middleware adds to the request
1629
+ * @param fn - The middleware function with typed `req` parameter
1630
+ * @returns A branded middleware carrying the extension type
1631
+ *
1632
+ * @example
1633
+ * ```typescript
1634
+ * const auth = defineMiddleware<{ userId: number }>((req, res, next) => {
1635
+ * req.userId = 123;
1636
+ * return next();
1637
+ * });
1638
+ * ```
1639
+ */
1640
+ declare function defineMiddleware<TExtension extends Record<string, any>>(fn: (req: Request & TExtension, res: Response$1, next: NextFunction) => SyncOrAsync): TypedMiddleware<TExtension>;
1641
+ /**
1642
+ * Extracts the extension type from a single middleware.
1643
+ * Returns `{}` for unbranded middlewares (backward compatibility).
1644
+ */
1645
+ type InferMiddlewareExtension<T> = T extends TypedMiddleware<infer E> ? E : {};
1646
+ /**
1647
+ * Combines extension types from a tuple of middlewares into a single intersection type.
1648
+ *
1649
+ * @example
1650
+ * ```typescript
1651
+ * type Ext = InferMiddlewareExtensions<[TypedMiddleware<{ userId: number }>, TypedMiddleware<{ role: string }>]>;
1652
+ * // { userId: number } & { role: string }
1653
+ * ```
1654
+ */
1655
+ type InferMiddlewareExtensions<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? InferMiddlewareExtension<First> & InferMiddlewareExtensions<Rest> : {};
1656
+
1657
+ /**
1658
+ * A type-level overlay for Router that carries group-level middleware extensions.
1659
+ * Every route handler defined on a GroupRouter automatically receives `TGroupExt`
1660
+ * merged into its `req` parameter, composed with any route-level TypedMiddleware extensions.
1661
+ *
1662
+ * @template TGroupExt - The accumulated middleware extensions from enclosing group(s)
1663
+ *
1664
+ * @example
1665
+ * ```typescript
1666
+ * router.group("/api", [auth], (r) => {
1667
+ * // r is GroupRouter<{ userId: number }>
1668
+ * r.get("/profile", (req, res) => {
1669
+ * req.userId; // number — inferred from group middleware
1670
+ * });
1671
+ * });
1672
+ * ```
1673
+ */
1674
+ interface GroupRouter<TGroupExt extends Record<string, any> = Record<string, never>> {
1675
+ get<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1676
+ get<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1677
+ post<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1678
+ post<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1679
+ patch<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1680
+ patch<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1681
+ put<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1682
+ put<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1683
+ delete<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1684
+ delete<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1685
+ options<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1686
+ options<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1687
+ head<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath, Record<number, RequestSchema>, unknown, unknown, unknown, TGroupExt>): void;
1688
+ head<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, TGroupExt & InferMiddlewareExtensions<TMiddlewares>>): void;
1689
+ group<const TMiddlewares extends readonly (ServerRouteMiddleware | TypedMiddleware<any>)[] = readonly (ServerRouteMiddleware | TypedMiddleware<any>)[]>(path: string, middleware: TMiddlewares, cb: (router: GroupRouter<TGroupExt & InferMiddlewareExtensions<TMiddlewares>>) => void): void;
1690
+ group(path: string, cb: (router: GroupRouter<TGroupExt>) => void): void;
1691
+ }
1692
+
1593
1693
  /**
1594
1694
  * Singleton that handles the routing of requests to the appropriate handler(s).
1595
1695
  */
@@ -1607,14 +1707,14 @@ declare class Router {
1607
1707
  * @param middlewares - Default middlewares to apply to all routes
1608
1708
  * @param options - Router configuration options
1609
1709
  */
1610
- constructor(basePath?: string, middlewares?: ServerRouteMiddleware[]);
1710
+ constructor(basePath?: string, middlewares?: (ServerRouteMiddleware | TypedMiddleware<any>)[]);
1611
1711
  /** Returns a shallow copy of all registered routes. */
1612
1712
  getRoutes(): Route[];
1613
1713
  /**
1614
1714
  * Add or update a route
1615
1715
  * @internal
1616
1716
  */
1617
- addOrUpdate(method: HttpMethod, path: string, middleware: ServerRouteMiddleware[], handler: ServerRouteHandler, validationSchemas?: {
1717
+ addOrUpdate(method: HttpMethod, path: string, middleware: (ServerRouteMiddleware | TypedMiddleware<any>)[], handler: ServerRouteHandler, validationSchemas?: {
1618
1718
  body?: RequestSchema;
1619
1719
  query?: RequestSchema;
1620
1720
  all?: RequestSchema;
@@ -1625,7 +1725,7 @@ declare class Router {
1625
1725
  * Uses O(1) cache lookup for static routes, falls back to O(k) tree traversal for dynamic routes.
1626
1726
  */
1627
1727
  find(method: string, rawPath: string): {
1628
- middleware: ServerRouteMiddleware[];
1728
+ middleware: (ServerRouteMiddleware | TypedMiddleware<any>)[];
1629
1729
  handler: ServerRouteHandler;
1630
1730
  params: Params;
1631
1731
  responseSchemas?: RouteResponseSchemas;
@@ -1640,50 +1740,51 @@ declare class Router {
1640
1740
  * Register a GET route under this router's base path with type-safe path parameters.
1641
1741
  */
1642
1742
  get<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1643
- get<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1743
+ get<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1644
1744
  /**
1645
1745
  * Register a POST route under this router's base path with type-safe path parameters.
1646
1746
  */
1647
1747
  post<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1648
- post<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1748
+ post<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1649
1749
  /**
1650
1750
  * Register a PATCH route under this router's base path with type-safe path parameters.
1651
1751
  */
1652
1752
  patch<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1653
- patch<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1753
+ patch<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1654
1754
  /**
1655
1755
  * Register a PUT route under this router's base path with type-safe path parameters.
1656
1756
  */
1657
1757
  put<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1658
- put<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1758
+ put<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1659
1759
  /**
1660
1760
  * Register a DELETE route under this router's base path with type-safe path parameters.
1661
1761
  */
1662
1762
  delete<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1663
- delete<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1763
+ delete<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1664
1764
  /**
1665
1765
  * Register an OPTIONS route under this router's base path with type-safe path parameters.
1666
1766
  */
1667
1767
  options<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1668
- options<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1768
+ options<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1669
1769
  /**
1670
1770
  * Register an HEAD route under this router's base path with type-safe path parameters.
1671
1771
  */
1672
1772
  head<TPath extends string = string>(path: TPath, handler: ControllerHandler<TPath>): void;
1673
- head<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll>): void;
1773
+ head<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | undefined = undefined, TQuery extends RequestSchema | undefined = undefined, TAll extends RequestSchema | undefined = undefined, const TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]>(path: TPath, options: StandardMethodOptions<TResponses, TBody, TQuery, TPath, TAll, TMiddlewares>, handler: ControllerHandler<TPath, TResponses, TBody, TQuery, TAll, InferMiddlewareExtensions<TMiddlewares>>): void;
1674
1774
  /**
1675
1775
  * Create a grouped router that shares a base path and middlewares.
1676
- * The callback receives a child router where routes are defined; routes
1776
+ * The callback receives a typed child router where routes are defined; routes
1677
1777
  * are then merged back into the parent with the composed base path and middlewares.
1778
+ * TypedMiddleware extensions flow into the callback's router for full type inference.
1678
1779
  */
1679
- group(path: string, middleware: ServerRouteMiddleware[] | ServerRouteMiddleware, cb: (router: Router) => void): void;
1680
- group(path: string, cb: (router: Router) => void): void;
1780
+ group<const TMiddlewares extends readonly (ServerRouteMiddleware | TypedMiddleware<any>)[] = readonly (ServerRouteMiddleware | TypedMiddleware<any>)[]>(path: string, middleware: TMiddlewares, cb: (router: GroupRouter<InferMiddlewareExtensions<TMiddlewares>>) => void): void;
1781
+ group(path: string, cb: (router: GroupRouter<{}>) => void): void;
1681
1782
  /**
1682
1783
  * Apply global middlewares to all routes
1683
1784
  * @param middlewares - The middlewares to apply
1684
1785
  * @internal
1685
1786
  */
1686
- applyGlobalMiddlewaresToAllRoutes(middlewares: ServerRouteMiddleware[]): void;
1787
+ applyGlobalMiddlewaresToAllRoutes(middlewares: (ServerRouteMiddleware | TypedMiddleware<any>)[]): void;
1687
1788
  private normalizeBasePath;
1688
1789
  private joinPath;
1689
1790
  /**
@@ -1702,7 +1803,7 @@ type RouteResponseSchemas = Record<number, RequestSchema>;
1702
1803
  interface Route {
1703
1804
  method: string;
1704
1805
  path: string;
1705
- middleware: ServerRouteMiddleware[];
1806
+ middleware: (ServerRouteMiddleware | TypedMiddleware<any>)[];
1706
1807
  handler: ServerRouteHandler;
1707
1808
  swaggerOptions?: SwaggerRouteOptions;
1708
1809
  /**
@@ -1772,13 +1873,14 @@ declare class Server<H extends NodeHttpClient = NodeHttpClient> implements Serve
1772
1873
  on(event: string, cb: () => SyncOrAsync): void;
1773
1874
  once(event: SignalEvent, cb: () => SyncOrAsync): void;
1774
1875
  once(event: string, cb: () => SyncOrAsync): void;
1775
- use(...middlewares: ServerRouteMiddleware[]): void;
1876
+ use(...middlewares: (ServerRouteMiddleware | TypedMiddleware<any>)[]): void;
1776
1877
  useExpress(pathOrMiddleware: string | RequestHandler | Router$1, maybeMiddleware?: RequestHandler | Router$1): void;
1777
1878
  expressMiddleware(middleware: RequestHandler): ServerRouteMiddleware;
1778
1879
  mountExpressRouter(basePath: string, expressRouter: Router$1): void;
1779
1880
  setErrorHandler(errorHandler?: ServerErrorHandler): void;
1780
1881
  setNotFoundHandler(notFoundHandler?: ServerRouteHandler): void;
1781
1882
  beforeStart(hook: ServerHook): void;
1883
+ beforeClose(hook: ServerHook): void;
1782
1884
  listen(cb?: ServerListenCallback): void;
1783
1885
  waitUntilListening(): Promise<{
1784
1886
  port: number;
@@ -2283,13 +2385,6 @@ type TrustProxyOptions = {
2283
2385
  hop?: "first" | "last";
2284
2386
  };
2285
2387
 
2286
- /**
2287
- * The next function.
2288
- * This is the function that is passed to the handler function.
2289
- * It has a pointer to the next middleware or handler function of the middleware chain.
2290
- */
2291
- type NextFunction = () => SyncOrAsync;
2292
-
2293
2388
  type ServerHandlerReturnType<TResponseMap extends Record<number, any> = Record<number, any>> = void | Promise<void> | ResponseBodyForStatus<TResponseMap, 200> | Promise<ResponseBodyForStatus<TResponseMap, 200>>;
2294
2389
  type ServerPlugin = {
2295
2390
  bodyParser?: BodyParserOptions;
@@ -2526,7 +2621,7 @@ interface ServerInterface {
2526
2621
  /**
2527
2622
  * Register a global middleware to be applied to all routes after the listener is bound, the middleware is applied in the order it is registered
2528
2623
  */
2529
- use: (middleware: ServerRouteMiddleware) => void;
2624
+ use: (middleware: ServerRouteMiddleware | TypedMiddleware<any>) => void;
2530
2625
  /**
2531
2626
  * Set the error handler for the server
2532
2627
  * @param errorHandler - The error handler to be applied to all routes
@@ -2555,6 +2650,19 @@ interface ServerInterface {
2555
2650
  * ```
2556
2651
  */
2557
2652
  beforeStart: (hook: ServerHook) => void;
2653
+ /**
2654
+ * Register a hook to be called before the server closes (after it stops accepting requests).
2655
+ * Multiple hooks are called in the order they are registered.
2656
+ * Useful for cleanup tasks like disconnecting from databases or flushing logs.
2657
+ * @param hook - The hook function to call, can be sync or async
2658
+ * @example
2659
+ * ```ts
2660
+ * server.beforeClose(async () => {
2661
+ * await disconnectFromDatabase();
2662
+ * });
2663
+ * ```
2664
+ */
2665
+ beforeClose: (hook: ServerHook) => void;
2558
2666
  /**
2559
2667
  * Binds the server to the port and hostname defined in the serverOptions, meant to be called only once
2560
2668
  * It initializes the server without blocking the event loop, you can pass a callback to be called when the server is listening
@@ -2603,8 +2711,8 @@ interface ServerInterface {
2603
2711
  */
2604
2712
  exit: (code?: number) => void;
2605
2713
  }
2606
- type StandardMethodOptions<TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | unknown = unknown, TQuery extends RequestSchema | unknown = unknown, TPath extends string = string, TAll extends RequestSchema | unknown = unknown> = {
2607
- middlewares?: ServerRouteMiddleware[] | ServerRouteMiddleware;
2714
+ type StandardMethodOptions<TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | unknown = unknown, TQuery extends RequestSchema | unknown = unknown, TPath extends string = string, TAll extends RequestSchema | unknown = unknown, TMiddlewares extends readonly TypedMiddleware<any>[] = readonly TypedMiddleware<any>[]> = {
2715
+ middlewares?: TMiddlewares | TypedMiddleware<any>;
2608
2716
  body?: TBody;
2609
2717
  query?: TQuery;
2610
2718
  all?: TAll;
@@ -2615,7 +2723,7 @@ type StandardMethodOptions<TResponses extends Record<number, RequestSchema> = Re
2615
2723
  };
2616
2724
  type ServerHook = () => SyncOrAsync;
2617
2725
  type SignalEvent = Deno.Signal | NodeJS.Signals;
2618
- type ControllerHandler<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | unknown = unknown, TQuery extends RequestSchema | unknown = unknown, TAll extends RequestSchema | unknown = unknown> = (req: Request<ExtractParams<TPath>, TBody extends RequestSchema ? InferBodyType<TBody> : InferBodyType<TAll>, InferQueryType<TQuery> extends Record<string, any> ? InferQueryType<TQuery> : Record<string, unknown>>, res: Response$1<InferResponseMap<TResponses>>) => ServerHandlerReturnType<InferResponseMap<TResponses>>;
2726
+ type ControllerHandler<TPath extends string = string, TResponses extends Record<number, RequestSchema> = Record<number, RequestSchema>, TBody extends RequestSchema | unknown = unknown, TQuery extends RequestSchema | unknown = unknown, TAll extends RequestSchema | unknown = unknown, TMiddlewareExt extends Record<string, any> = Record<string, never>> = (req: Request<ExtractParams<TPath>, TBody extends RequestSchema ? InferBodyType<TBody> : InferBodyType<TAll>, InferQueryType<TQuery> extends Record<string, any> ? InferQueryType<TQuery> : Record<string, unknown>> & TMiddlewareExt, res: Response$1<InferResponseMap<TResponses>>) => ServerHandlerReturnType<InferResponseMap<TResponses>>;
2619
2727
 
2620
2728
  type RunTimeType = "bun" | "node" | "deno";
2621
2729
 
@@ -4198,7 +4306,9 @@ declare const compression: (options?: CompressionOptions) => ServerRouteMiddlewa
4198
4306
  *
4199
4307
  * @param options Cookie middleware options
4200
4308
  */
4201
- declare const cookie: (options?: CookieMiddlewareOptions) => ServerRouteMiddleware;
4309
+ declare const cookie: (options?: CookieMiddlewareOptions) => TypedMiddleware<{
4310
+ cookies: Record<string, string>;
4311
+ }>;
4202
4312
 
4203
4313
  /**
4204
4314
  * CORS plugin
@@ -4295,7 +4405,11 @@ declare const rateLimiter: (keyOptions?: RateLimiterKeyOptions, storageOptions?:
4295
4405
  * @param options.store The store to use for the session
4296
4406
  * @param options.cookie The cookie options
4297
4407
  */
4298
- declare const session: (options?: SessionOptions) => ServerRouteMiddleware;
4408
+ declare const session: (options?: SessionOptions) => TypedMiddleware<{
4409
+ session: Record<string, any>;
4410
+ saveSession: () => Promise<void>;
4411
+ destroySession: () => Promise<void>;
4412
+ }>;
4299
4413
 
4300
4414
  /**
4301
4415
  * Creates a static file serving middleware and registers all routes for the given path
@@ -4319,7 +4433,9 @@ declare const serveStatic: (options: StaticPluginOptions, swaggerOptions?: Swagg
4319
4433
  * @param options.status The status code to return if the request times out
4320
4434
  * @param options.message The message to return if the request times out
4321
4435
  */
4322
- declare const timeout: (options: TimeoutOptions) => ServerRouteMiddleware;
4436
+ declare const timeout: (options: TimeoutOptions) => TypedMiddleware<{
4437
+ timeout: boolean;
4438
+ }>;
4323
4439
 
4324
4440
  /**
4325
4441
  * Trust proxy plugin middleware, used to trust the proxy headers to get the client ip
@@ -4540,4 +4656,4 @@ declare enum CacheStatus {
4540
4656
  */
4541
4657
  declare const router: ClientRouter;
4542
4658
 
4543
- export { type AsyncLocalStorageContextSetters, AzureBlobStorageProvider, BaseCron, BasePlugin, type BaseStorageProviderOptions, type BlobStorageProviderOptions, BullMQConfiguration, type BullMQConfigurationOptions, BullMQPubSub, CACHE_STATUS_HEADER, type CacheKeyIncludes, type CacheMiddlewareOptions, type CachePluginOptions, type CacheProvider, type CacheRedisOptions, type CacheRouteConfig, CacheService, type CacheServiceInterface, type CacheStats, CacheStatus, Command, type CommandOptions, CommandRegistry, type CompressionOptions, type CookieMiddlewareOptions, type CorsOptions, type CronSchedule, type CronScheduleParams, CronService, type CronUIOptions, CustomAdapter, type CustomQueueConfiguration, type CustomStorageProviderOptions, CustomTypedQueue, type CustomValidationError, DEFAULT_CACHE_OPTIONS, EdgeAdapter, EjsAdapter, type ExtractParams, GraphQL, type GraphQLContext, type GraphQLOptions, type GraphQLResolverFunction, type GraphQLResolverMap, type GraphQLResolverType, type GraphQLResolvers, type GraphQLSchemaInput, type GraphQLTypeDef, HandlebarsAdapter, type HelmetOptions, type HttpMethod, type HttpsOptions, type InferResponseMap, type InferSchemaType, LocalStorageProvider, type LocalStorageProviderOptions, type LockBehavior, type LogOptions, type LoggerOptions, type MailOptions, MailOptionsBuilder, MailProvider, type MailProviderInterface, Mailer, type MailerInterface, type MailerOptions, type MailerProviderOptions, MemoryCacheProvider, MemoryPubSub, type MethodOverrideOptions, MockResponse, MockServer, type MockServerOptions, type MqttConnectionOptions, type MqttHandler, type MqttPublishOptions, MqttService, type MqttSubscribeOptions, type MqttSubscription, type MqttTopics, MustacheAdapter, type NextFunction, type NodeHttpClient, type NodeServer as NodeHttpServerClient, PGBossConfiguration, type PGBossConfigurationOptions, PGBossPubSub, type PolicyDecorator, PolicyManager, type PolicyProvider, type PublishTopic, QueueManager, QueueService, type RateLimiterKeyOptions, RedisCacheProvider, Request, type RequestSchema, Response$1 as Response, type ResponseBodyForStatus, type RuntimeServer, S3StorageProvider, type S3StorageProviderOptions, SQSConfiguration, type SQSConfigurationOptions, SQSPubSub, type CacheMetrics as SchemaCacheMetrics, type SerializeOptions, Server, type ServerConnectInput, type ServerErrorHandler, type ServerHook, type ServerInterface, type ServerListenCallback, type ServerOptions, type ServerRouteHandler, type ServerRouteMiddleware, type ServerTapOptions, type SessionOptions, type SignalEvent, type StaticPluginOptions, Storage, type StorageInterface, type StorageOptions, type StorageProviderOptions, type TemplateMailOptions, type TimeoutOptions, type TrustProxyOptions, type TypedCacheKeyIncludes, type TypedCacheRouteConfig, type TypedHandler, TypedQueue, type TypedRouteMetadata, type ValidatedData, type ValidationOptions, arg, asyncLocalStorage, asyncStorage, bullmqQueue, cache, cacheMiddleware, clearAllCaches as clearAllSchemaCaches, commandRegistry, compression, controller, cookie, cors, createExpressAdapter, createPolicyDecorator, createQueue, cron, cronUIInstance, cronUi, Server as default, defineQueueConfiguration, del, expressHandler, expressMiddleware, flag, get, getCacheService, getCacheMetrics as getSchemaCacheMetrics, hash, helmet, initCacheService, log, logCacheMetrics as logSchemaCacheMetrics, logger, memoryQueue, methodOverride, middleware, mountExpressRouter, mqtt, patch, pgbossQueue, post, put, rateLimiter, resetCacheService, router, serialize, serveStatic, session, setCronGlobalErrorHandler, setMqttGlobalErrorHandler, sqsQueue, timeout as timeoutMw, trustProxy, validate };
4659
+ export { type AsyncLocalStorageContextSetters, AzureBlobStorageProvider, BaseCron, BasePlugin, type BaseStorageProviderOptions, type BlobStorageProviderOptions, BullMQConfiguration, type BullMQConfigurationOptions, BullMQPubSub, CACHE_STATUS_HEADER, type CacheKeyIncludes, type CacheMiddlewareOptions, type CachePluginOptions, type CacheProvider, type CacheRedisOptions, type CacheRouteConfig, CacheService, type CacheServiceInterface, type CacheStats, CacheStatus, Command, type CommandOptions, CommandRegistry, type CompressionOptions, type CookieMiddlewareOptions, type CorsOptions, type CronSchedule, type CronScheduleParams, CronService, type CronUIOptions, CustomAdapter, type CustomQueueConfiguration, type CustomStorageProviderOptions, CustomTypedQueue, type CustomValidationError, DEFAULT_CACHE_OPTIONS, EdgeAdapter, EjsAdapter, type ExtractParams, GraphQL, type GraphQLContext, type GraphQLOptions, type GraphQLResolverFunction, type GraphQLResolverMap, type GraphQLResolverType, type GraphQLResolvers, type GraphQLSchemaInput, type GraphQLTypeDef, type GroupRouter, HandlebarsAdapter, type HelmetOptions, type HttpMethod, type HttpsOptions, type InferMiddlewareExtension, type InferMiddlewareExtensions, type InferResponseMap, type InferSchemaType, LocalStorageProvider, type LocalStorageProviderOptions, type LockBehavior, type LogOptions, type LoggerOptions, type MailOptions, MailOptionsBuilder, MailProvider, type MailProviderInterface, Mailer, type MailerInterface, type MailerOptions, type MailerProviderOptions, MemoryCacheProvider, MemoryPubSub, type MethodOverrideOptions, MockResponse, MockServer, type MockServerOptions, type MqttConnectionOptions, type MqttHandler, type MqttPublishOptions, MqttService, type MqttSubscribeOptions, type MqttSubscription, type MqttTopics, MustacheAdapter, type NextFunction, type NodeHttpClient, type NodeServer as NodeHttpServerClient, PGBossConfiguration, type PGBossConfigurationOptions, PGBossPubSub, type PolicyDecorator, PolicyManager, type PolicyProvider, type PublishTopic, QueueManager, QueueService, type RateLimiterKeyOptions, RedisCacheProvider, Request, type RequestSchema, Response$1 as Response, type ResponseBodyForStatus, type RuntimeServer, S3StorageProvider, type S3StorageProviderOptions, SQSConfiguration, type SQSConfigurationOptions, SQSPubSub, type CacheMetrics as SchemaCacheMetrics, type SerializeOptions, Server, type ServerConnectInput, type ServerErrorHandler, type ServerHook, type ServerInterface, type ServerListenCallback, type ServerOptions, type ServerRouteHandler, type ServerRouteMiddleware, type ServerTapOptions, type SessionOptions, type SignalEvent, type StaticPluginOptions, Storage, type StorageInterface, type StorageOptions, type StorageProviderOptions, type TemplateMailOptions, type TimeoutOptions, type TrustProxyOptions, type TypedCacheKeyIncludes, type TypedCacheRouteConfig, type TypedHandler, type TypedMiddleware, TypedQueue, type TypedRouteMetadata, type ValidatedData, type ValidationOptions, arg, asyncLocalStorage, asyncStorage, bullmqQueue, cache, cacheMiddleware, clearAllCaches as clearAllSchemaCaches, commandRegistry, compression, controller, cookie, cors, createExpressAdapter, createPolicyDecorator, createQueue, cron, cronUIInstance, cronUi, Server as default, defineMiddleware, defineQueueConfiguration, del, expressHandler, expressMiddleware, flag, get, getCacheService, getCacheMetrics as getSchemaCacheMetrics, hash, helmet, initCacheService, log, logCacheMetrics as logSchemaCacheMetrics, logger, memoryQueue, methodOverride, middleware, mountExpressRouter, mqtt, patch, pgbossQueue, post, put, rateLimiter, resetCacheService, router, serialize, serveStatic, session, setCronGlobalErrorHandler, setMqttGlobalErrorHandler, sqsQueue, timeout as timeoutMw, trustProxy, validate };