yinzerflow 0.4.4 → 0.5.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.
- package/README.md +31 -26
- package/docs/configuration/configuration.md +815 -0
- package/docs/core/core-concepts.md +801 -0
- package/docs/core/error-handling.md +391 -153
- package/docs/core/logging.md +426 -68
- package/docs/modules/body-parsing.md +561 -0
- package/docs/modules/cors.md +369 -0
- package/docs/modules/index.md +125 -0
- package/docs/modules/ip-security.md +280 -0
- package/docs/modules/rate-limiting.md +795 -0
- package/index.d.ts +278 -76
- package/index.js +18 -18
- package/index.js.map +17 -8
- package/package.json +5 -3
- package/docs/configuration/advanced-configuration-options.md +0 -302
- package/docs/configuration/configuration-patterns.md +0 -500
- package/docs/core/context.md +0 -230
- package/docs/core/examples.md +0 -444
- package/docs/core/request.md +0 -161
- package/docs/core/response.md +0 -212
- package/docs/core/routes.md +0 -720
- package/docs/quick-reference.md +0 -346
- package/docs/security/body-parsing.md +0 -296
- package/docs/security/cors.md +0 -189
- package/docs/security/ip-security.md +0 -234
- package/docs/security/security-overview.md +0 -282
- package/docs/start-here.md +0 -184
package/index.d.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* Utility type for deep partial - makes all properties optional recursively
|
|
4
|
-
* Used internally to create public configuration types from internal shapes
|
|
5
|
-
*/
|
|
6
|
-
export type DeepPartial<T> = {
|
|
7
|
-
[P in keyof T]?: T[P] extends object ? T[P] extends Array<infer U> ? Array<U> // Keep arrays as-is, don't make array items partial
|
|
8
|
-
: DeepPartial<T[P]> : T[P];
|
|
9
|
-
};
|
|
1
|
+
import { createClient } from 'redis';
|
|
2
|
+
|
|
10
3
|
/**
|
|
11
4
|
* Generic types for handler callbacks that define the structure of request data
|
|
12
5
|
*
|
|
@@ -24,7 +17,7 @@ export type DeepPartial<T> = {
|
|
|
24
17
|
* };
|
|
25
18
|
*
|
|
26
19
|
* // Custom types for specific endpoints
|
|
27
|
-
* interface UserCreateContext extends
|
|
20
|
+
* interface UserCreateContext extends HandlerCallbackGenerics {
|
|
28
21
|
* body: { name: string; email: string; age: number };
|
|
29
22
|
* response: { id: string; name: string; email: string };
|
|
30
23
|
* state: { requestId: string; userAgent: string };
|
|
@@ -41,7 +34,7 @@ export type DeepPartial<T> = {
|
|
|
41
34
|
* };
|
|
42
35
|
* ```
|
|
43
36
|
*/
|
|
44
|
-
export interface
|
|
37
|
+
export interface HandlerCallbackGenerics {
|
|
45
38
|
/**
|
|
46
39
|
* The expected type of the request body
|
|
47
40
|
*
|
|
@@ -50,7 +43,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
50
43
|
*
|
|
51
44
|
* @example
|
|
52
45
|
* ```typescript
|
|
53
|
-
* interface LoginContext extends
|
|
46
|
+
* interface LoginContext extends HandlerCallbackGenerics {
|
|
54
47
|
* body: { username: string; password: string };
|
|
55
48
|
* }
|
|
56
49
|
*
|
|
@@ -69,7 +62,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
69
62
|
*
|
|
70
63
|
* @example
|
|
71
64
|
* ```typescript
|
|
72
|
-
* interface UserListContext extends
|
|
65
|
+
* interface UserListContext extends HandlerCallbackGenerics {
|
|
73
66
|
* response: { users: Array<{ id: string; name: string }>; total: number };
|
|
74
67
|
* }
|
|
75
68
|
*
|
|
@@ -93,7 +86,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
93
86
|
*
|
|
94
87
|
* @example
|
|
95
88
|
* ```typescript
|
|
96
|
-
* interface SearchContext extends
|
|
89
|
+
* interface SearchContext extends HandlerCallbackGenerics {
|
|
97
90
|
* query: { q: string; limit?: string; page?: string };
|
|
98
91
|
* }
|
|
99
92
|
*
|
|
@@ -106,7 +99,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
106
99
|
* };
|
|
107
100
|
* ```
|
|
108
101
|
*/
|
|
109
|
-
query?: Record<string,
|
|
102
|
+
query?: Record<string, unknown>;
|
|
110
103
|
/**
|
|
111
104
|
* The expected type of route parameters
|
|
112
105
|
*
|
|
@@ -115,7 +108,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
115
108
|
*
|
|
116
109
|
* @example
|
|
117
110
|
* ```typescript
|
|
118
|
-
* interface UserDetailContext extends
|
|
111
|
+
* interface UserDetailContext extends HandlerCallbackGenerics {
|
|
119
112
|
* params: { id: string; tab?: string };
|
|
120
113
|
* }
|
|
121
114
|
*
|
|
@@ -138,7 +131,7 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
138
131
|
*
|
|
139
132
|
* @example
|
|
140
133
|
* ```typescript
|
|
141
|
-
* interface AuthContext extends
|
|
134
|
+
* interface AuthContext extends HandlerCallbackGenerics {
|
|
142
135
|
* state: {
|
|
143
136
|
* user: User;
|
|
144
137
|
* permissions: string[];
|
|
@@ -160,6 +153,15 @@ export interface InternalHandlerCallbackGenerics {
|
|
|
160
153
|
*/
|
|
161
154
|
state?: Record<string, unknown>;
|
|
162
155
|
}
|
|
156
|
+
export type CreateEnum<T> = T[keyof T];
|
|
157
|
+
/**
|
|
158
|
+
* Utility type for deep partial - makes all properties optional recursively
|
|
159
|
+
* Used internally to create public configuration types from internal shapes
|
|
160
|
+
*/
|
|
161
|
+
export type DeepPartial<T> = {
|
|
162
|
+
[P in keyof T]?: T[P] extends object ? T[P] extends Array<infer U> ? Array<U> // Keep arrays as-is, don't make array items partial
|
|
163
|
+
: DeepPartial<T[P]> : T[P];
|
|
164
|
+
};
|
|
163
165
|
export declare const httpStatus: {
|
|
164
166
|
readonly ok: "OK";
|
|
165
167
|
readonly created: "Created";
|
|
@@ -464,7 +466,7 @@ export type InternalHttpMethod = CreateEnum<typeof httpMethod>;
|
|
|
464
466
|
* @see {@link Response} for setting headers in responses
|
|
465
467
|
*/
|
|
466
468
|
export type InternalHttpHeaders = Lowercase<CreateEnum<typeof httpHeaders>> | string;
|
|
467
|
-
interface Request$1<T extends
|
|
469
|
+
interface Request$1<T extends HandlerCallbackGenerics = HandlerCallbackGenerics> {
|
|
468
470
|
/**
|
|
469
471
|
* The HTTP protocol version (e.g., "HTTP/1.1").
|
|
470
472
|
*
|
|
@@ -591,7 +593,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
591
593
|
* };
|
|
592
594
|
*
|
|
593
595
|
* // Typed body with generics
|
|
594
|
-
* interface CreateUserRequest extends
|
|
596
|
+
* interface CreateUserRequest extends HandlerCallbackGenerics {
|
|
595
597
|
* body: { name: string; email: string; age: number };
|
|
596
598
|
* }
|
|
597
599
|
*
|
|
@@ -608,7 +610,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
608
610
|
* };
|
|
609
611
|
* ```
|
|
610
612
|
*
|
|
611
|
-
* @see {@link
|
|
613
|
+
* @see {@link HandlerCallbackGenerics} for custom body typing
|
|
612
614
|
*/
|
|
613
615
|
body: T["body"];
|
|
614
616
|
/**
|
|
@@ -637,7 +639,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
637
639
|
* };
|
|
638
640
|
*
|
|
639
641
|
* // Typed query parameters with generics
|
|
640
|
-
* interface UserListRequest extends
|
|
642
|
+
* interface UserListRequest extends HandlerCallbackGenerics {
|
|
641
643
|
* query: { page: string; limit: string; search?: string; sort?: string };
|
|
642
644
|
* }
|
|
643
645
|
*
|
|
@@ -658,7 +660,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
658
660
|
* };
|
|
659
661
|
* ```
|
|
660
662
|
*
|
|
661
|
-
* @see {@link
|
|
663
|
+
* @see {@link HandlerCallbackGenerics} for custom query typing
|
|
662
664
|
*/
|
|
663
665
|
query: T["query"];
|
|
664
666
|
/**
|
|
@@ -688,7 +690,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
688
690
|
* };
|
|
689
691
|
*
|
|
690
692
|
* // Typed route parameters with generics
|
|
691
|
-
* interface UserDetailRequest extends
|
|
693
|
+
* interface UserDetailRequest extends HandlerCallbackGenerics {
|
|
692
694
|
* params: { id: string; tab?: string };
|
|
693
695
|
* }
|
|
694
696
|
*
|
|
@@ -712,7 +714,7 @@ interface Request$1<T extends InternalHandlerCallbackGenerics = InternalHandlerC
|
|
|
712
714
|
* };
|
|
713
715
|
* ```
|
|
714
716
|
*
|
|
715
|
-
* @see {@link
|
|
717
|
+
* @see {@link HandlerCallbackGenerics} for custom params typing
|
|
716
718
|
*/
|
|
717
719
|
params: T["params"];
|
|
718
720
|
/**
|
|
@@ -945,7 +947,7 @@ interface Response$1 {
|
|
|
945
947
|
* It contains the request and response objects, plus any custom state data
|
|
946
948
|
* defined by the user through generics.
|
|
947
949
|
*
|
|
948
|
-
* @template T - Extends
|
|
950
|
+
* @template T - Extends HandlerCallbackGenerics to provide custom typing
|
|
949
951
|
*
|
|
950
952
|
* @example
|
|
951
953
|
* ```typescript
|
|
@@ -968,7 +970,7 @@ interface Response$1 {
|
|
|
968
970
|
* };
|
|
969
971
|
*
|
|
970
972
|
* // Advanced usage with custom state typing
|
|
971
|
-
* interface AuthContext extends
|
|
973
|
+
* interface AuthContext extends HandlerCallbackGenerics {
|
|
972
974
|
* state: {
|
|
973
975
|
* user: User;
|
|
974
976
|
* permissions: string[];
|
|
@@ -991,7 +993,7 @@ interface Response$1 {
|
|
|
991
993
|
* };
|
|
992
994
|
* ```
|
|
993
995
|
*/
|
|
994
|
-
export interface Context<T extends
|
|
996
|
+
export interface Context<T extends HandlerCallbackGenerics = HandlerCallbackGenerics> {
|
|
995
997
|
/**
|
|
996
998
|
* The incoming request object containing all request data and metadata
|
|
997
999
|
*
|
|
@@ -1086,7 +1088,7 @@ export interface Context<T extends InternalHandlerCallbackGenerics = InternalHan
|
|
|
1086
1088
|
* - **Void**: No response body (useful for middleware)
|
|
1087
1089
|
* - **Error**: Thrown errors are caught by error handlers
|
|
1088
1090
|
*
|
|
1089
|
-
* @template T - Extends
|
|
1091
|
+
* @template T - Extends HandlerCallbackGenerics for custom typing
|
|
1090
1092
|
* @param ctx - The request context containing request, response, and state objects
|
|
1091
1093
|
* @param error - Optional error object (only provided to error handlers)
|
|
1092
1094
|
* @returns Response data, promise, or void
|
|
@@ -1102,7 +1104,7 @@ export interface Context<T extends InternalHandlerCallbackGenerics = InternalHan
|
|
|
1102
1104
|
* };
|
|
1103
1105
|
*
|
|
1104
1106
|
* // Typed route handler with custom state
|
|
1105
|
-
* interface UserContext extends
|
|
1107
|
+
* interface UserContext extends HandlerCallbackGenerics {
|
|
1106
1108
|
* body: { name: string; email: string };
|
|
1107
1109
|
* response: { id: string; name: string; email: string };
|
|
1108
1110
|
* state: { user: User; permissions: string[] };
|
|
@@ -1145,9 +1147,9 @@ export interface Context<T extends InternalHandlerCallbackGenerics = InternalHan
|
|
|
1145
1147
|
* ```
|
|
1146
1148
|
*
|
|
1147
1149
|
* @see {@link Context} for context interface details
|
|
1148
|
-
* @see {@link
|
|
1150
|
+
* @see {@link HandlerCallbackGenerics} for custom typing options
|
|
1149
1151
|
*/
|
|
1150
|
-
export type HandlerCallback<T extends
|
|
1152
|
+
export type HandlerCallback<T extends HandlerCallbackGenerics = HandlerCallbackGenerics> = (ctx: Context<T>, error?: unknown) => Promise<T["response"] | void> | T["response"] | void;
|
|
1151
1153
|
export type InternalGlobalHookOptions = {
|
|
1152
1154
|
routesToExclude: Array<string>;
|
|
1153
1155
|
} & {
|
|
@@ -1603,6 +1605,231 @@ export interface LoggerConfig {
|
|
|
1603
1605
|
error: (...args: Array<unknown>) => void;
|
|
1604
1606
|
} | undefined;
|
|
1605
1607
|
}
|
|
1608
|
+
/**
|
|
1609
|
+
Time duration string format
|
|
1610
|
+
|
|
1611
|
+
Format: number followed by unit (s, m, h, d)
|
|
1612
|
+
|
|
1613
|
+
Units:
|
|
1614
|
+
- s: seconds
|
|
1615
|
+
- m: minutes
|
|
1616
|
+
- h: hours
|
|
1617
|
+
- d: days
|
|
1618
|
+
|
|
1619
|
+
@example
|
|
1620
|
+
```typescript
|
|
1621
|
+
'30s' // 30 seconds
|
|
1622
|
+
'15m' // 15 minutes
|
|
1623
|
+
'2h' // 2 hours
|
|
1624
|
+
'1d' // 1 day
|
|
1625
|
+
```
|
|
1626
|
+
*/
|
|
1627
|
+
export type TimeString = `${number}${"d" | "h" | "m" | "s"}`;
|
|
1628
|
+
export declare const rateLimitAlgorithm: {
|
|
1629
|
+
readonly slidingWindowCounter: "sliding-window-counter";
|
|
1630
|
+
};
|
|
1631
|
+
export declare const rateLimitStoreType: {
|
|
1632
|
+
readonly memory: "memory";
|
|
1633
|
+
readonly redis: "redis";
|
|
1634
|
+
};
|
|
1635
|
+
/**
|
|
1636
|
+
* Internal type for rate limit algorithm enum
|
|
1637
|
+
* Generated from rateLimitAlgorithm constant
|
|
1638
|
+
*/
|
|
1639
|
+
export type RateLimitAlgorithm = CreateEnum<typeof rateLimitAlgorithm>;
|
|
1640
|
+
/**
|
|
1641
|
+
* Internal type for rate limit store type enum
|
|
1642
|
+
* Generated from rateLimitStoreType constant
|
|
1643
|
+
*/
|
|
1644
|
+
export type RateLimitStoreType = CreateEnum<typeof rateLimitStoreType>;
|
|
1645
|
+
export interface BaseStoreConfig {
|
|
1646
|
+
/** Type of the store @default 'memory' */
|
|
1647
|
+
type: RateLimitStoreType;
|
|
1648
|
+
}
|
|
1649
|
+
export interface MemoryStoreConfig extends BaseStoreConfig {
|
|
1650
|
+
type: "memory";
|
|
1651
|
+
}
|
|
1652
|
+
/**
|
|
1653
|
+
* Redis store configuration
|
|
1654
|
+
*/
|
|
1655
|
+
export interface RedisStoreConfig extends BaseStoreConfig {
|
|
1656
|
+
type: "redis";
|
|
1657
|
+
/** Redis client instance of ioredis or redis */
|
|
1658
|
+
client: ReturnType<typeof createClient>;
|
|
1659
|
+
/** Key prefix for the rate limit keys @default 'rate_limit:' */
|
|
1660
|
+
keyPrefix?: string;
|
|
1661
|
+
/** Maximum number of connection retry attempts @default 3 */
|
|
1662
|
+
maxRetries?: number;
|
|
1663
|
+
/** Delay between retry attempts in milliseconds @default 1000 */
|
|
1664
|
+
retryDelay?: number;
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Configuration for rate limit store
|
|
1668
|
+
* This is a union type to future proof the code for other store types
|
|
1669
|
+
*/
|
|
1670
|
+
export type StoreConfig = MemoryStoreConfig | RedisStoreConfig;
|
|
1671
|
+
/**
|
|
1672
|
+
* Options for per-route rate limiting
|
|
1673
|
+
*
|
|
1674
|
+
* Allows overriding global rate limit settings for specific routes.
|
|
1675
|
+
* Use with the `rateLimit()` hook function in route options.
|
|
1676
|
+
*
|
|
1677
|
+
* @example
|
|
1678
|
+
* ```typescript
|
|
1679
|
+
* import { rateLimit } from 'yinzerflow';
|
|
1680
|
+
* import type { RateLimitOptions } from 'yinzerflow';
|
|
1681
|
+
*
|
|
1682
|
+
* // Using friendly time format
|
|
1683
|
+
* const options: RateLimitOptions = {
|
|
1684
|
+
* max: 5,
|
|
1685
|
+
* windowMs: '1m' // 1 minute
|
|
1686
|
+
* };
|
|
1687
|
+
*
|
|
1688
|
+
* // Or using milliseconds directly
|
|
1689
|
+
* const optionsMs: RateLimitOptions = {
|
|
1690
|
+
* max: 5,
|
|
1691
|
+
* windowMs: 60000 // 1 minute
|
|
1692
|
+
* };
|
|
1693
|
+
*
|
|
1694
|
+
* app.post('/api/auth/login',
|
|
1695
|
+
* { beforeRoute: [rateLimit(options)] },
|
|
1696
|
+
* async (ctx) => {
|
|
1697
|
+
* // Login logic
|
|
1698
|
+
* }
|
|
1699
|
+
* );
|
|
1700
|
+
* ```
|
|
1701
|
+
*/
|
|
1702
|
+
export interface RateLimitOptions {
|
|
1703
|
+
/**
|
|
1704
|
+
* Enable or disable rate limiting
|
|
1705
|
+
* @default true
|
|
1706
|
+
* @example
|
|
1707
|
+
* ```typescript
|
|
1708
|
+
* enabled: true
|
|
1709
|
+
* ```
|
|
1710
|
+
*/
|
|
1711
|
+
enabled?: boolean;
|
|
1712
|
+
/**
|
|
1713
|
+
* Rate limiting algorithm to use
|
|
1714
|
+
* @default 'sliding-window-counter'
|
|
1715
|
+
*
|
|
1716
|
+
* Available algorithms:
|
|
1717
|
+
* - 'sliding-window-counter': Memory efficient, Redis-ready, 99%+ accurate (recommended)
|
|
1718
|
+
* - 'token-bucket': (Future) Allows smooth traffic patterns with continuous refill
|
|
1719
|
+
*
|
|
1720
|
+
* @example
|
|
1721
|
+
* ```typescript
|
|
1722
|
+
* import { rateLimitAlgorithm } from 'yinzerflow';
|
|
1723
|
+
*
|
|
1724
|
+
* algorithm: rateLimitAlgorithm.slidingWindowCounter
|
|
1725
|
+
* ```
|
|
1726
|
+
*/
|
|
1727
|
+
algorithm?: RateLimitAlgorithm;
|
|
1728
|
+
/**
|
|
1729
|
+
* Rate limiting store configuration
|
|
1730
|
+
*
|
|
1731
|
+
* Configure the storage backend for rate limiting data.
|
|
1732
|
+
* If not provided, defaults to in-memory storage.
|
|
1733
|
+
*
|
|
1734
|
+
* @example
|
|
1735
|
+
* ```typescript
|
|
1736
|
+
* // In-memory store (default)
|
|
1737
|
+
* const config = { algorithm: 'sliding-window-counter', window: '15m', max: 100 };
|
|
1738
|
+
*
|
|
1739
|
+
* // Redis store
|
|
1740
|
+
* const config = {
|
|
1741
|
+
* algorithm: 'sliding-window-counter',
|
|
1742
|
+
* window: '15m',
|
|
1743
|
+
* max: 100,
|
|
1744
|
+
* store: {
|
|
1745
|
+
* type: 'redis',
|
|
1746
|
+
* client: redisClient,
|
|
1747
|
+
* keyPrefix: 'myapp:rate_limit:'
|
|
1748
|
+
* }
|
|
1749
|
+
* };
|
|
1750
|
+
* ```
|
|
1751
|
+
*/
|
|
1752
|
+
store?: StoreConfig;
|
|
1753
|
+
/**
|
|
1754
|
+
* Time window for rate limiting
|
|
1755
|
+
*
|
|
1756
|
+
* Accepts either:
|
|
1757
|
+
* - Friendly format: '30s', '15m', '2h', '1d'
|
|
1758
|
+
* - Milliseconds: 900000
|
|
1759
|
+
*
|
|
1760
|
+
* @default '15m' (15 minutes / 900000ms)
|
|
1761
|
+
*
|
|
1762
|
+
* @example
|
|
1763
|
+
* ```typescript
|
|
1764
|
+
* window: '30s' // 30 seconds
|
|
1765
|
+
* window: '15m' // 15 minutes
|
|
1766
|
+
* window: '2h' // 2 hours
|
|
1767
|
+
* window: '1d' // 1 day
|
|
1768
|
+
* ```
|
|
1769
|
+
*/
|
|
1770
|
+
window?: TimeString | number;
|
|
1771
|
+
/**
|
|
1772
|
+
* Maximum requests per window
|
|
1773
|
+
* @default 100
|
|
1774
|
+
*/
|
|
1775
|
+
max?: number;
|
|
1776
|
+
/**
|
|
1777
|
+
* Include standard rate limit headers in responses
|
|
1778
|
+
* @default true
|
|
1779
|
+
*/
|
|
1780
|
+
standardHeaders?: boolean;
|
|
1781
|
+
/**
|
|
1782
|
+
* Skip counting successful requests (status < 400)
|
|
1783
|
+
* @default false
|
|
1784
|
+
*/
|
|
1785
|
+
skipSuccessfulRequests?: boolean;
|
|
1786
|
+
/**
|
|
1787
|
+
* Skip counting failed requests (status >= 400)
|
|
1788
|
+
* @default false
|
|
1789
|
+
*/
|
|
1790
|
+
skipFailedRequests?: boolean;
|
|
1791
|
+
/**
|
|
1792
|
+
* Store configuration
|
|
1793
|
+
* @default { type: 'memory' }
|
|
1794
|
+
*/
|
|
1795
|
+
store?: StoreConfig;
|
|
1796
|
+
/**
|
|
1797
|
+
* Custom key generator function for identifying clients
|
|
1798
|
+
* @default (ctx) => ctx.request.ipAddress
|
|
1799
|
+
*
|
|
1800
|
+
* @example
|
|
1801
|
+
* ```typescript
|
|
1802
|
+
* // Rate limit by user ID instead of IP
|
|
1803
|
+
* keyGenerator: (ctx) => ctx.state.userId || ctx.request.ipAddress
|
|
1804
|
+
* ```
|
|
1805
|
+
*/
|
|
1806
|
+
keyGenerator?: (context: Context<any>) => string;
|
|
1807
|
+
/**
|
|
1808
|
+
* Custom handler function called when rate limit is exceeded
|
|
1809
|
+
*
|
|
1810
|
+
* @param context - Request context
|
|
1811
|
+
* @param retryAfter - Seconds until the client can retry
|
|
1812
|
+
* @returns Response to send to client
|
|
1813
|
+
*
|
|
1814
|
+
* @example
|
|
1815
|
+
* ```typescript
|
|
1816
|
+
* handler: (ctx, retryAfter) => {
|
|
1817
|
+
* ctx.response.setStatusCode(429);
|
|
1818
|
+
* return {
|
|
1819
|
+
* error: 'Too many requests',
|
|
1820
|
+
* retryAfter,
|
|
1821
|
+
* message: 'Please slow down'
|
|
1822
|
+
* };
|
|
1823
|
+
* }
|
|
1824
|
+
* ```
|
|
1825
|
+
*/
|
|
1826
|
+
handler?: HandlerCallback<{
|
|
1827
|
+
response: {
|
|
1828
|
+
success: false;
|
|
1829
|
+
message: string;
|
|
1830
|
+
};
|
|
1831
|
+
}>;
|
|
1832
|
+
}
|
|
1606
1833
|
/**
|
|
1607
1834
|
* Internal CORS Configuration Options
|
|
1608
1835
|
* Provides fine-grained control over Cross-Origin Resource Sharing
|
|
@@ -1682,45 +1909,6 @@ export interface InternalCorsEnabledConfiguration {
|
|
|
1682
1909
|
*/
|
|
1683
1910
|
optionsSuccessStatus: InternalHttpStatusCode;
|
|
1684
1911
|
}
|
|
1685
|
-
/**
|
|
1686
|
-
* Internal Connection Options
|
|
1687
|
-
*/
|
|
1688
|
-
export interface InternalConnectionOptions {
|
|
1689
|
-
/**
|
|
1690
|
-
* Default socket timeout in milliseconds (30 seconds)
|
|
1691
|
-
*
|
|
1692
|
-
* Standard timeout for most socket connections.
|
|
1693
|
-
* It is long enough for slow clients but short enough to prevent idle connections from staying open indefinitely.
|
|
1694
|
-
*/
|
|
1695
|
-
socketTimeout: number;
|
|
1696
|
-
/**
|
|
1697
|
-
* Default graceful shutdown timeout in milliseconds (30 seconds)
|
|
1698
|
-
*
|
|
1699
|
-
* This is the maximum time to wait for a connection to complete before the server will close it.
|
|
1700
|
-
*/
|
|
1701
|
-
gracefulShutdownTimeout: number;
|
|
1702
|
-
/**
|
|
1703
|
-
* Default keep-alive timeout in milliseconds (65 seconds)
|
|
1704
|
-
*
|
|
1705
|
-
* This is the maximum time a connection can be idle before the server will close it.
|
|
1706
|
-
* This is to allow for a connection to stay open for a period of time so subsequent requests can be handled without a new connection.
|
|
1707
|
-
* This is also to prevent a connection from staying open indefinitely.
|
|
1708
|
-
* This is also useful for load balancing and preventing a single server from being overwhelmed by a large number of connections.
|
|
1709
|
-
* AWS recommends a keep-alive timeout of 65 seconds because there idle timeout is 60 seconds.
|
|
1710
|
-
*/
|
|
1711
|
-
keepAliveTimeout: number;
|
|
1712
|
-
/**
|
|
1713
|
-
* Default headers timeout in milliseconds (66 seconds)
|
|
1714
|
-
*
|
|
1715
|
-
* This is the maximum time to wait for a header from the client.
|
|
1716
|
-
* This is to allow for a connection to stay open for a period of time so subsequent requests can be handled without a new connection.
|
|
1717
|
-
* This is also to prevent a connection from staying open indefinitely.
|
|
1718
|
-
* This is also useful for load balancing and preventing a single server from being overwhelmed by a large number of connections.
|
|
1719
|
-
* It is recommended to set this value to be greater than the keep-alive timeout to prevent the server from closing the connection prematurely
|
|
1720
|
-
* before the keep-alive timeout has expired.
|
|
1721
|
-
*/
|
|
1722
|
-
headersTimeout: number;
|
|
1723
|
-
}
|
|
1724
1912
|
/**
|
|
1725
1913
|
* Internal Body Parser Security Configuration
|
|
1726
1914
|
* Protects against DoS attacks, prototype pollution, and memory exhaustion
|
|
@@ -1946,15 +2134,22 @@ export interface InternalServerConfiguration {
|
|
|
1946
2134
|
*/
|
|
1947
2135
|
ipSecurity: InternalIpValidationConfig;
|
|
1948
2136
|
/**
|
|
1949
|
-
*
|
|
2137
|
+
* Rate limiting configuration
|
|
2138
|
+
* Protects against DoS attacks and API abuse by limiting requests per IP
|
|
2139
|
+
* @default enabled with 100 requests per 15 minutes
|
|
1950
2140
|
*/
|
|
1951
|
-
|
|
2141
|
+
rateLimit?: RateLimitOptions;
|
|
1952
2142
|
/**
|
|
1953
|
-
*
|
|
1954
|
-
* When
|
|
2143
|
+
* Graceful shutdown timeout configuration
|
|
2144
|
+
* When set to a value greater than 0, YinzerFlow automatically sets up signal handlers for SIGTERM and SIGINT
|
|
2145
|
+
* and waits for all requests to complete before shutting down.
|
|
2146
|
+
* If the value is 0 (disabled), you must manually handle graceful shutdown by calling `app.close()` and `process.exit(0)`.
|
|
2147
|
+
* Note: If using container orchestrations, your container configuration should be at least 1 second more
|
|
2148
|
+
* than the graceful shutdown timeout to ensure all requests are completed, otherwise the container will be
|
|
2149
|
+
* killed before all requests are completed.
|
|
1955
2150
|
* @default true
|
|
1956
2151
|
*/
|
|
1957
|
-
|
|
2152
|
+
gracefulShutdownTimeout: TimeString | number;
|
|
1958
2153
|
}
|
|
1959
2154
|
export type HttpMethodHandlers = Record<Lowercase<keyof typeof httpMethod>, InternalSetupMethod>;
|
|
1960
2155
|
export type RouteGroupMethod = (prefix: string, callback: (group: RouteGroup) => void, options?: InternalRouteRegistryOptions) => RouteGroup;
|
|
@@ -2292,7 +2487,7 @@ declare class HookRegistryImpl implements InternalHookRegistryImpl {
|
|
|
2292
2487
|
*
|
|
2293
2488
|
* // Full configuration example
|
|
2294
2489
|
* const app = new YinzerFlow({
|
|
2295
|
-
* port:
|
|
2490
|
+
* port: 3000,
|
|
2296
2491
|
* host: '0.0.0.0',
|
|
2297
2492
|
* logLevel: 'debug',
|
|
2298
2493
|
* networkLogs: true,
|
|
@@ -2349,6 +2544,7 @@ declare class SetupImpl implements InternalSetupImpl {
|
|
|
2349
2544
|
export declare class YinzerFlow extends SetupImpl {
|
|
2350
2545
|
private _isListening;
|
|
2351
2546
|
private _server?;
|
|
2547
|
+
private _globalRateLimiter?;
|
|
2352
2548
|
constructor(configuration?: ServerConfiguration);
|
|
2353
2549
|
private _setupServer;
|
|
2354
2550
|
private _processRequest;
|
|
@@ -2382,6 +2578,12 @@ export declare const log: {
|
|
|
2382
2578
|
table: (data: unknown, ...additionalArgs: Array<unknown>) => void;
|
|
2383
2579
|
levels: typeof LOG_LEVELS;
|
|
2384
2580
|
};
|
|
2581
|
+
export declare const rateLimitHook: (rateLimitOptions: RateLimitOptions) => HandlerCallback<{
|
|
2582
|
+
response: {
|
|
2583
|
+
success: false;
|
|
2584
|
+
message: string;
|
|
2585
|
+
};
|
|
2586
|
+
}>;
|
|
2385
2587
|
export declare const colors: {
|
|
2386
2588
|
readonly reset: "\u001B[0m";
|
|
2387
2589
|
readonly cyan: "\u001B[96m";
|