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
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
# 📖 Overview
|
|
2
|
+
|
|
3
|
+
YinzerFlow provides flexible and secure configuration options for fine-tuning your API's behavior, security, and performance. All configuration options are <span style="color: #2ecc71">**optional with secure defaults**</span>, allowing you to start quickly while maintaining the ability to customize as needed.
|
|
4
|
+
|
|
5
|
+
<span style="color: #3498db">**💡 Tip:**</span> YinzerFlow uses a <span style="color: #2ecc71">**security-first**</span> approach with sensible defaults. You only need to configure what you want to change.
|
|
6
|
+
|
|
7
|
+
**When to configure:**
|
|
8
|
+
|
|
9
|
+
- 🌐 Deploying to different environments (dev, staging, production)
|
|
10
|
+
- 🔒 Adjusting security settings for your use case
|
|
11
|
+
- ⚡ Optimizing performance for specific workloads
|
|
12
|
+
- 🎨 Customizing behavior (CORS, logging, rate limiting)
|
|
13
|
+
- 🔑 Handling proxy infrastructure (load balancers, CDNs)
|
|
14
|
+
|
|
15
|
+
**Expected outcomes:**
|
|
16
|
+
|
|
17
|
+
- ✅ Environment-specific configurations
|
|
18
|
+
- 🔒 Enhanced security with minimal overhead
|
|
19
|
+
- 📊 Better observability with logging
|
|
20
|
+
- 🎯 Optimal performance for your use case
|
|
21
|
+
|
|
22
|
+
<span style="color: #3498db">🔗 For specific features, see: [Rate Limiting](../modules/rate-limiting.md), [CORS](../modules/cors.md), [IP Security](../modules/ip-security.md), [Logging](../core/logging.md)</span>
|
|
23
|
+
|
|
24
|
+
# ⚙️ Usage
|
|
25
|
+
|
|
26
|
+
## 🎛️ Settings
|
|
27
|
+
|
|
28
|
+
### port — @default <span style="color: #2ecc71">`5000`</span>
|
|
29
|
+
|
|
30
|
+
Port number for the server to listen on.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { YinzerFlow } from "yinzerflow";
|
|
34
|
+
|
|
35
|
+
const app = new YinzerFlow({
|
|
36
|
+
port: 3000,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
<aside>
|
|
41
|
+
|
|
42
|
+
Options: `number`
|
|
43
|
+
|
|
44
|
+
- 🚨 Minimum: `1`
|
|
45
|
+
- 🚨 Maximum: `65535`
|
|
46
|
+
- ✅ Recommended: `3000` for development, `443` for production HTTPS
|
|
47
|
+
- 🟢 Default: `5000`
|
|
48
|
+
|
|
49
|
+
</aside>
|
|
50
|
+
|
|
51
|
+
### host — @default <span style="color: #2ecc71">`'0.0.0.0'`</span>
|
|
52
|
+
|
|
53
|
+
Host address to bind the server to.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
const app = new YinzerFlow({
|
|
57
|
+
port: 3000,
|
|
58
|
+
host: "127.0.0.1", // Localhost only
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
<aside>
|
|
63
|
+
|
|
64
|
+
Options: `string`
|
|
65
|
+
|
|
66
|
+
- 🌐 `'0.0.0.0'`: All network interfaces (default, recommended)
|
|
67
|
+
- 🔒 `'127.0.0.1'`: Localhost only (testing)
|
|
68
|
+
- 🌐 `'::'`: All IPv6 interfaces
|
|
69
|
+
|
|
70
|
+
</aside>
|
|
71
|
+
|
|
72
|
+
### logger — @default <span style="color: #2ecc71">`undefined`</span>
|
|
73
|
+
|
|
74
|
+
Custom logger instance for application logs.
|
|
75
|
+
|
|
76
|
+
<span style="color: #3498db">**💡 Tip:**</span> Use `createLogger()` to create custom logger instances with different prefixes or log levels.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { YinzerFlow, createLogger } from "yinzerflow";
|
|
80
|
+
|
|
81
|
+
const customLogger = createLogger({
|
|
82
|
+
prefix: "MY-APP",
|
|
83
|
+
logLevel: "info"
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const app = new YinzerFlow({
|
|
87
|
+
port: 3000,
|
|
88
|
+
logger: customLogger,
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
<aside>
|
|
93
|
+
|
|
94
|
+
Options: `Logger | undefined`
|
|
95
|
+
|
|
96
|
+
- ✅ `undefined`: Uses built-in logger (default)
|
|
97
|
+
- 🎨 `Logger`: Custom logger instance via `createLogger()`
|
|
98
|
+
|
|
99
|
+
<span style="color: #3498db">🔗 See [Logging Documentation](../core/logging.md) for details</span>
|
|
100
|
+
|
|
101
|
+
</aside>
|
|
102
|
+
|
|
103
|
+
### networkLogs — @default <span style="color: #2ecc71">`false`</span>
|
|
104
|
+
|
|
105
|
+
Enable nginx-style network request/response logging.
|
|
106
|
+
|
|
107
|
+
<span style="color: #e74c3c">**⚠️ Warning:**</span> Network logs are separate from application logs and can generate significant output in high-traffic scenarios.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
const app = new YinzerFlow({
|
|
111
|
+
port: 3000,
|
|
112
|
+
networkLogs: true, // Enable network logging
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
<aside>
|
|
117
|
+
|
|
118
|
+
Options: `boolean`
|
|
119
|
+
|
|
120
|
+
- 🔴 `false`: Disabled (default, recommended for production)
|
|
121
|
+
- 🟢 `true`: Enabled (useful for debugging)
|
|
122
|
+
|
|
123
|
+
</aside>
|
|
124
|
+
|
|
125
|
+
### networkLogger — @default <span style="color: #2ecc71">`undefined`</span>
|
|
126
|
+
|
|
127
|
+
Custom logger for network logs (nginx-style request/response logging).
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { YinzerFlow, createLogger } from "yinzerflow";
|
|
131
|
+
|
|
132
|
+
const networkLogger = createLogger({ prefix: "NETWORK" });
|
|
133
|
+
|
|
134
|
+
const app = new YinzerFlow({
|
|
135
|
+
port: 3000,
|
|
136
|
+
networkLogs: true,
|
|
137
|
+
networkLogger, // Route network logs to custom logger
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
<aside>
|
|
142
|
+
|
|
143
|
+
Options: `Logger | undefined`
|
|
144
|
+
|
|
145
|
+
- ✅ `undefined`: Uses built-in network logging format (default)
|
|
146
|
+
- 🎨 `Logger`: Custom logger for network logs
|
|
147
|
+
|
|
148
|
+
</aside>
|
|
149
|
+
|
|
150
|
+
### cors — @default <span style="color: #2ecc71">`{ enabled: false }`</span>
|
|
151
|
+
|
|
152
|
+
Cross-Origin Resource Sharing configuration for browser security.
|
|
153
|
+
|
|
154
|
+
<span style="color: #e74c3c">**⚠️ Warning:**</span> Only enable CORS if your API is accessed from browser clients on different origins.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const app = new YinzerFlow({
|
|
158
|
+
port: 3000,
|
|
159
|
+
cors: {
|
|
160
|
+
enabled: true,
|
|
161
|
+
origin: ["https://yourdomain.com"],
|
|
162
|
+
credentials: true,
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
<aside>
|
|
168
|
+
|
|
169
|
+
Options: `{ enabled: false } | CorsConfiguration`
|
|
170
|
+
|
|
171
|
+
- 🔴 `{ enabled: false }`: CORS disabled (default, most secure)
|
|
172
|
+
- 🟢 `{ enabled: true, ... }`: CORS enabled with origin configuration
|
|
173
|
+
|
|
174
|
+
<span style="color: #3498db">🔗 See [CORS Documentation](../modules/cors.md) for all options</span>
|
|
175
|
+
|
|
176
|
+
</aside>
|
|
177
|
+
|
|
178
|
+
### rateLimit — @default <span style="color: #2ecc71">`{ enabled: true, window: '15m', max: 100 }`</span>
|
|
179
|
+
|
|
180
|
+
Rate limiting configuration to protect against DoS attacks and API abuse.
|
|
181
|
+
|
|
182
|
+
<span style="color: #2ecc71">**✅ Recommended:**</span> Keep rate limiting enabled in production for security.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const app = new YinzerFlow({
|
|
186
|
+
port: 3000,
|
|
187
|
+
rateLimit: {
|
|
188
|
+
enabled: true,
|
|
189
|
+
window: "15m",
|
|
190
|
+
max: 100,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
<aside>
|
|
196
|
+
|
|
197
|
+
Options: `RateLimitOptions`
|
|
198
|
+
|
|
199
|
+
- 🟢 `enabled: true`: Rate limiting enabled (default, recommended)
|
|
200
|
+
- ⏱️ `window`: Time window (`'15m'` default)
|
|
201
|
+
- 🔢 `max`: Maximum requests per window (`100` default)
|
|
202
|
+
|
|
203
|
+
<span style="color: #3498db">🔗 See [Rate Limiting Documentation](../modules/rate-limiting.md) for all options</span>
|
|
204
|
+
|
|
205
|
+
</aside>
|
|
206
|
+
|
|
207
|
+
### bodyParser — @default <span style="color: #2ecc71">Secure defaults</span>
|
|
208
|
+
|
|
209
|
+
Body parsing configuration with built-in security protections.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const app = new YinzerFlow({
|
|
213
|
+
port: 3000,
|
|
214
|
+
bodyParser: {
|
|
215
|
+
json: {
|
|
216
|
+
maxSize: 262144, // 256KB
|
|
217
|
+
maxDepth: 10,
|
|
218
|
+
allowPrototypeProperties: false, // Security protection
|
|
219
|
+
},
|
|
220
|
+
fileUploads: {
|
|
221
|
+
maxFileSize: 10485760, // 10MB
|
|
222
|
+
maxFiles: 10,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
<aside>
|
|
229
|
+
|
|
230
|
+
Options: `BodyParserConfiguration`
|
|
231
|
+
|
|
232
|
+
- 📄 `json`: JSON parsing limits (256KB max default)
|
|
233
|
+
- 📁 `fileUploads`: File upload limits (10MB max default)
|
|
234
|
+
- 📝 `urlEncoded`: Form data limits (1MB max default)
|
|
235
|
+
|
|
236
|
+
<span style="color: #3498db">🔗 See [Body Parsing Documentation](../modules/body-parsing.md) for all options</span>
|
|
237
|
+
|
|
238
|
+
</aside>
|
|
239
|
+
|
|
240
|
+
### ipSecurity — @default <span style="color: #2ecc71">Secure defaults</span>
|
|
241
|
+
|
|
242
|
+
IP address validation and spoofing protection.
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const app = new YinzerFlow({
|
|
246
|
+
port: 3000,
|
|
247
|
+
ipSecurity: {
|
|
248
|
+
trustedProxies: ["127.0.0.1", "192.168.1.10"],
|
|
249
|
+
detectSpoofing: true,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
<aside>
|
|
255
|
+
|
|
256
|
+
Options: `IpSecurityConfiguration`
|
|
257
|
+
|
|
258
|
+
- 🔑 `trustedProxies`: Allowed proxy IPs (`['127.0.0.1', '::1']` default)
|
|
259
|
+
- 🛡️ `detectSpoofing`: Enable spoofing detection (`true` default)
|
|
260
|
+
- 🌐 `allowPrivateIps`: Allow private IP addresses (`true` default)
|
|
261
|
+
|
|
262
|
+
<span style="color: #3498db">🔗 See [IP Security Documentation](../modules/ip-security.md) for all options</span>
|
|
263
|
+
|
|
264
|
+
</aside>
|
|
265
|
+
|
|
266
|
+
### gracefulShutdownTimeout — @default <span style="color: #2ecc71">`'15m'`</span>
|
|
267
|
+
|
|
268
|
+
Graceful shutdown timeout for completing in-flight requests before server shutdown.
|
|
269
|
+
|
|
270
|
+
<span style="color: #3498db">**💡 Tip:**</span> When set to a value greater than 0, YinzerFlow automatically sets up signal handlers for SIGTERM and SIGINT. Set to `0` or `'0s'` if you need custom shutdown logic.
|
|
271
|
+
|
|
272
|
+
<span style="color: #f39c12">**⚡ Performance:**</span> If using container orchestration, your container termination grace period should be at least 1 second longer than this value.
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
const app = new YinzerFlow({
|
|
276
|
+
port: 3000,
|
|
277
|
+
gracefulShutdownTimeout: "30s", // Wait 30 seconds for requests to complete
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
<aside>
|
|
282
|
+
|
|
283
|
+
Options: `TimeString | number`
|
|
284
|
+
|
|
285
|
+
- ⏱️ `TimeString`: Use time strings like `'15m'`, `'30s'`, `'1h'` (recommended)
|
|
286
|
+
- 🔢 `number`: Milliseconds as a number
|
|
287
|
+
- 🟢 Default: `'15m'` (15 minutes)
|
|
288
|
+
- 🔴 Disable: Set to `0` or `'0s'` for manual shutdown handling
|
|
289
|
+
|
|
290
|
+
</aside>
|
|
291
|
+
|
|
292
|
+
# ✨ Best Practices
|
|
293
|
+
|
|
294
|
+
- ✅ **Use environment variables**: Store configuration in environment variables for different environments
|
|
295
|
+
- 🔒 **Start secure**: Begin with strict limits and relax as needed
|
|
296
|
+
- 📊 **Enable logging**: Use `networkLogs: true` in development for debugging
|
|
297
|
+
- 🎯 **Validate configuration**: Test configuration before deploying to production
|
|
298
|
+
- 🔑 **Configure proxies**: Set `trustedProxies` for load balancers and CDNs
|
|
299
|
+
- ⚡ **Optimize for use case**: Adjust limits based on your specific workload
|
|
300
|
+
- 📝 **Document changes**: Comment configuration overrides for team clarity
|
|
301
|
+
|
|
302
|
+
# 💻 Examples
|
|
303
|
+
|
|
304
|
+
### Production API
|
|
305
|
+
|
|
306
|
+
**Use Case:** Secure production API with CORS and rate limiting
|
|
307
|
+
|
|
308
|
+
**Description:** Production-ready configuration with security best practices, rate limiting, CORS for specific origins, and optimized settings.
|
|
309
|
+
|
|
310
|
+
<span style="color: #f39c12">**⚡ Performance:**</span> This configuration balances security, performance, and reliability for production workloads.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { YinzerFlow } from "yinzerflow";
|
|
314
|
+
|
|
315
|
+
const app = new YinzerFlow({
|
|
316
|
+
port: 443,
|
|
317
|
+
host: "0.0.0.0",
|
|
318
|
+
cors: {
|
|
319
|
+
enabled: true,
|
|
320
|
+
origin: ["https://yourdomain.com", "https://app.yourdomain.com"],
|
|
321
|
+
credentials: true,
|
|
322
|
+
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
323
|
+
allowedHeaders: ["Content-Type", "Authorization"],
|
|
324
|
+
},
|
|
325
|
+
rateLimit: {
|
|
326
|
+
enabled: true,
|
|
327
|
+
window: "15m",
|
|
328
|
+
max: 100,
|
|
329
|
+
standardHeaders: true,
|
|
330
|
+
},
|
|
331
|
+
bodyParser: {
|
|
332
|
+
json: {
|
|
333
|
+
maxSize: 262144, // 256KB
|
|
334
|
+
maxDepth: 10,
|
|
335
|
+
allowPrototypeProperties: false,
|
|
336
|
+
},
|
|
337
|
+
fileUploads: {
|
|
338
|
+
maxFileSize: 10485760, // 10MB
|
|
339
|
+
maxFiles: 10,
|
|
340
|
+
allowedExtensions: [".jpg", ".png", ".pdf"],
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
ipSecurity: {
|
|
344
|
+
trustedProxies: ["192.168.1.10"], // Your load balancer
|
|
345
|
+
allowPrivateIps: false, // Only real client IPs
|
|
346
|
+
detectSpoofing: true,
|
|
347
|
+
},
|
|
348
|
+
gracefulShutdownTimeout: "30s", // 30 second graceful shutdown
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await app.listen();
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Dev API
|
|
355
|
+
|
|
356
|
+
**Use Case:** Development server with relaxed security and verbose logging
|
|
357
|
+
|
|
358
|
+
**Description:** Development configuration with permissive CORS, disabled rate limiting, larger limits, and verbose logging for easier debugging.
|
|
359
|
+
|
|
360
|
+
<span style="color: #e74c3c">**⚠️ Warning:**</span> Never use this configuration in production - it's insecure by design for development convenience.
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
import { YinzerFlow } from "yinzerflow";
|
|
364
|
+
|
|
365
|
+
const app = new YinzerFlow({
|
|
366
|
+
port: 3000,
|
|
367
|
+
networkLogs: true, // Verbose request logging
|
|
368
|
+
cors: {
|
|
369
|
+
enabled: true,
|
|
370
|
+
origin: "*", // Allow all origins (DEV ONLY!)
|
|
371
|
+
credentials: true,
|
|
372
|
+
},
|
|
373
|
+
rateLimit: {
|
|
374
|
+
enabled: false, // Disable for development
|
|
375
|
+
},
|
|
376
|
+
bodyParser: {
|
|
377
|
+
json: {
|
|
378
|
+
maxSize: 10485760, // 10MB for testing
|
|
379
|
+
maxDepth: 20,
|
|
380
|
+
},
|
|
381
|
+
fileUploads: {
|
|
382
|
+
maxFileSize: 104857600, // 100MB
|
|
383
|
+
maxFiles: 20,
|
|
384
|
+
allowedExtensions: [], // Allow all extensions
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
ipSecurity: {
|
|
388
|
+
allowPrivateIps: true,
|
|
389
|
+
detectSpoofing: false, // Disable for development
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
await app.listen();
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### High-Security API
|
|
397
|
+
|
|
398
|
+
**Use Case:** Maximum security for sensitive data APIs
|
|
399
|
+
|
|
400
|
+
**Description:** Strictest configuration with minimal limits, no file uploads, no CORS, and maximum security protections.
|
|
401
|
+
|
|
402
|
+
<span style="color: #2ecc71">**✅ Use when:**</span> Handling highly sensitive data (financial, healthcare, PII)
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { YinzerFlow } from "yinzerflow";
|
|
406
|
+
|
|
407
|
+
const app = new YinzerFlow({
|
|
408
|
+
port: 443,
|
|
409
|
+
cors: {
|
|
410
|
+
enabled: false, // No CORS for maximum security
|
|
411
|
+
},
|
|
412
|
+
rateLimit: {
|
|
413
|
+
enabled: true,
|
|
414
|
+
window: "5m",
|
|
415
|
+
max: 20, // Very strict limits
|
|
416
|
+
},
|
|
417
|
+
bodyParser: {
|
|
418
|
+
json: {
|
|
419
|
+
maxSize: 32768, // 32KB only
|
|
420
|
+
maxDepth: 3,
|
|
421
|
+
maxKeys: 50,
|
|
422
|
+
allowPrototypeProperties: false,
|
|
423
|
+
},
|
|
424
|
+
fileUploads: {
|
|
425
|
+
maxFileSize: 0, // No file uploads
|
|
426
|
+
maxFiles: 0,
|
|
427
|
+
},
|
|
428
|
+
urlEncoded: {
|
|
429
|
+
maxSize: 8192, // 8KB forms only
|
|
430
|
+
maxFields: 20,
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
ipSecurity: {
|
|
434
|
+
trustedProxies: [], // No proxies
|
|
435
|
+
allowPrivateIps: false,
|
|
436
|
+
detectSpoofing: true,
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
await app.listen();
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### File Upload Service
|
|
444
|
+
|
|
445
|
+
**Use Case:** Service optimized for large file uploads
|
|
446
|
+
|
|
447
|
+
**Description:** Configuration with large file upload limits, minimal JSON parsing, and appropriate security controls.
|
|
448
|
+
|
|
449
|
+
<span style="color: #f39c12">**⚡ Performance:**</span> Memory usage scales with concurrent uploads - monitor and adjust limits as needed.
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
import { YinzerFlow } from "yinzerflow";
|
|
453
|
+
|
|
454
|
+
const app = new YinzerFlow({
|
|
455
|
+
port: 3000,
|
|
456
|
+
bodyParser: {
|
|
457
|
+
json: {
|
|
458
|
+
maxSize: 512000, // 500KB for metadata only
|
|
459
|
+
maxDepth: 3,
|
|
460
|
+
},
|
|
461
|
+
fileUploads: {
|
|
462
|
+
maxFileSize: 2147483648, // 2GB per file
|
|
463
|
+
maxTotalSize: 10737418240, // 10GB total
|
|
464
|
+
maxFiles: 50,
|
|
465
|
+
allowedExtensions: [
|
|
466
|
+
".jpg", ".png", ".gif", ".mp4", ".webm",
|
|
467
|
+
".pdf", ".zip", ".tar", ".gz",
|
|
468
|
+
],
|
|
469
|
+
maxFilenameLength: 200,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
gracefulShutdownTimeout: "5m", // 5 minutes for large uploads to complete
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
await app.listen();
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Microservice (Internal)
|
|
479
|
+
|
|
480
|
+
**Use Case:** Internal microservice behind API gateway
|
|
481
|
+
|
|
482
|
+
**Description:** Configuration for internal services with no CORS, allowing private IPs, and moderate limits.
|
|
483
|
+
|
|
484
|
+
<span style="color: #3498db">**💡 Tip:**</span> Internal services can be more permissive since they're not internet-facing.
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import { YinzerFlow } from "yinzerflow";
|
|
488
|
+
|
|
489
|
+
const app = new YinzerFlow({
|
|
490
|
+
port: 3000,
|
|
491
|
+
cors: {
|
|
492
|
+
enabled: false, // No CORS for internal services
|
|
493
|
+
},
|
|
494
|
+
rateLimit: {
|
|
495
|
+
enabled: false, // Gateway handles rate limiting
|
|
496
|
+
},
|
|
497
|
+
bodyParser: {
|
|
498
|
+
json: {
|
|
499
|
+
maxSize: 524288, // 512KB
|
|
500
|
+
maxDepth: 10,
|
|
501
|
+
},
|
|
502
|
+
fileUploads: {
|
|
503
|
+
maxFileSize: 0, // No file uploads
|
|
504
|
+
maxFiles: 0,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
ipSecurity: {
|
|
508
|
+
trustedProxies: ["127.0.0.1", "10.0.0.0/8"],
|
|
509
|
+
allowPrivateIps: true,
|
|
510
|
+
detectSpoofing: true,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
await app.listen();
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Load Balancer Setup
|
|
518
|
+
|
|
519
|
+
**Use Case:** API behind load balancer (ALB, nginx, etc.)
|
|
520
|
+
|
|
521
|
+
**Description:** Configuration for services behind load balancers with proper proxy trust settings.
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
import { YinzerFlow } from "yinzerflow";
|
|
525
|
+
|
|
526
|
+
const app = new YinzerFlow({
|
|
527
|
+
port: 3000,
|
|
528
|
+
ipSecurity: {
|
|
529
|
+
trustedProxies: [
|
|
530
|
+
"192.168.1.10", // Load balancer IP
|
|
531
|
+
"192.168.1.11", // Backup load balancer
|
|
532
|
+
],
|
|
533
|
+
headerPreference: ["x-forwarded-for", "x-real-ip"],
|
|
534
|
+
maxChainLength: 5,
|
|
535
|
+
detectSpoofing: true,
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
await app.listen();
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### CDN Configuration (Cloudflare)
|
|
543
|
+
|
|
544
|
+
**Use Case:** API behind Cloudflare CDN
|
|
545
|
+
|
|
546
|
+
**Description:** Configuration for services behind Cloudflare with proper IP extraction from cf-connecting-ip header.
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
import { YinzerFlow } from "yinzerflow";
|
|
550
|
+
|
|
551
|
+
const app = new YinzerFlow({
|
|
552
|
+
port: 3000,
|
|
553
|
+
cors: {
|
|
554
|
+
enabled: true,
|
|
555
|
+
origin: ["https://yourdomain.com"],
|
|
556
|
+
credentials: true,
|
|
557
|
+
},
|
|
558
|
+
ipSecurity: {
|
|
559
|
+
trustedProxies: [
|
|
560
|
+
// Cloudflare IP ranges (example - use full list)
|
|
561
|
+
"173.245.48.0/20",
|
|
562
|
+
"103.21.244.0/22",
|
|
563
|
+
"103.22.200.0/22",
|
|
564
|
+
],
|
|
565
|
+
headerPreference: ["cf-connecting-ip", "x-forwarded-for"],
|
|
566
|
+
allowPrivateIps: false, // Only real client IPs
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
await app.listen();
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Environment-Based Configuration
|
|
574
|
+
|
|
575
|
+
**Use Case:** Single codebase for multiple environments
|
|
576
|
+
|
|
577
|
+
**Description:** Use environment variables to configure different environments from the same codebase.
|
|
578
|
+
|
|
579
|
+
<span style="color: #2ecc71">**✅ Recommended:**</span> This pattern makes deployment easier and reduces configuration errors.
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
import { YinzerFlow } from "yinzerflow";
|
|
583
|
+
|
|
584
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
585
|
+
const isDevelopment = process.env.NODE_ENV === "development";
|
|
586
|
+
|
|
587
|
+
const app = new YinzerFlow({
|
|
588
|
+
port: parseInt(process.env.PORT || "3000"),
|
|
589
|
+
host: process.env.HOST || "0.0.0.0",
|
|
590
|
+
|
|
591
|
+
networkLogs: isDevelopment, // Only in development
|
|
592
|
+
|
|
593
|
+
cors: {
|
|
594
|
+
enabled: true,
|
|
595
|
+
origin: process.env.ALLOWED_ORIGINS?.split(",") || ["http://localhost:3000"],
|
|
596
|
+
credentials: true,
|
|
597
|
+
},
|
|
598
|
+
|
|
599
|
+
rateLimit: {
|
|
600
|
+
enabled: isProduction, // Only in production
|
|
601
|
+
window: "15m",
|
|
602
|
+
max: parseInt(process.env.RATE_LIMIT_MAX || "100"),
|
|
603
|
+
},
|
|
604
|
+
|
|
605
|
+
bodyParser: {
|
|
606
|
+
json: {
|
|
607
|
+
maxSize: parseInt(process.env.MAX_JSON_SIZE || "262144"),
|
|
608
|
+
allowPrototypeProperties: false,
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
ipSecurity: {
|
|
613
|
+
trustedProxies: process.env.TRUSTED_PROXIES?.split(",") || ["127.0.0.1"],
|
|
614
|
+
allowPrivateIps: !isProduction,
|
|
615
|
+
detectSpoofing: isProduction,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
await app.listen();
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
## 🚀 Performance Notes
|
|
623
|
+
|
|
624
|
+
### Memory Considerations
|
|
625
|
+
|
|
626
|
+
- 💾 **JSON parsing**: `maxSize` directly impacts memory usage per request
|
|
627
|
+
- 📁 **File uploads**: Memory scales with `maxFileSize` × `maxFiles` × concurrent requests
|
|
628
|
+
- 🔄 **Rate limiting**: Uses ~24 bytes per tracked client (minimal overhead)
|
|
629
|
+
- ⏱️ **Graceful shutdown**: `gracefulShutdownTimeout` should account for longest request duration
|
|
630
|
+
|
|
631
|
+
<span style="color: #f39c12">**⚡ Performance:**</span> Limits comparison:
|
|
632
|
+
|
|
633
|
+
- **Conservative** (high-security): 32KB JSON, no files, 20 requests/5min
|
|
634
|
+
- **Moderate** (standard API): 256KB JSON, 10MB files, 100 requests/15min
|
|
635
|
+
- **Permissive** (file service): 500KB JSON, 2GB files, 1000 requests/hour
|
|
636
|
+
|
|
637
|
+
### Graceful Shutdown Tuning
|
|
638
|
+
|
|
639
|
+
- ⏱️ **Standard APIs**: `'30s'` to `'1m'` is usually sufficient
|
|
640
|
+
- ⏱️ **Long-running requests**: `'5m'` to `'15m'` for file processing or complex queries
|
|
641
|
+
- ⏱️ **Container orchestration**: Set container termination grace period to `gracefulShutdownTimeout + 1s`
|
|
642
|
+
|
|
643
|
+
<span style="color: #2ecc71">**✅ Rule of thumb:**</span> Set `gracefulShutdownTimeout` to 2× your longest expected request duration.
|
|
644
|
+
|
|
645
|
+
## 🔒 Security Notes
|
|
646
|
+
|
|
647
|
+
### 🛡️ Secure Defaults
|
|
648
|
+
|
|
649
|
+
- **Problem**: Many frameworks default to permissive settings that can be exploited.
|
|
650
|
+
- **YinzerFlow Solution**: All defaults are security-first - rate limiting enabled, CORS disabled, strict parsing limits, and prototype pollution protection.
|
|
651
|
+
|
|
652
|
+
### 🛡️ Configuration Validation
|
|
653
|
+
|
|
654
|
+
- **Problem**: Invalid configuration can crash servers or create security holes.
|
|
655
|
+
- **YinzerFlow Solution**: All configuration is validated at startup with descriptive error messages.
|
|
656
|
+
|
|
657
|
+
### 🛡️ Environment Separation
|
|
658
|
+
|
|
659
|
+
- **Problem**: Using production config in development or vice versa causes issues.
|
|
660
|
+
- **YinzerFlow Solution**: Use environment variables and conditional logic to separate configs.
|
|
661
|
+
|
|
662
|
+
<span style="color: #2ecc71">**✅ Result:**</span> YinzerFlow's configuration system provides security by default while maintaining flexibility for different use cases.
|
|
663
|
+
|
|
664
|
+
## 🔧 Troubleshooting
|
|
665
|
+
|
|
666
|
+
### Configuration not applying
|
|
667
|
+
|
|
668
|
+
**Symptom:** Changes to configuration don't seem to take effect.
|
|
669
|
+
|
|
670
|
+
**Cause:** Configuration is only read once at server creation.
|
|
671
|
+
|
|
672
|
+
<span style="color: #2ecc71">**✅ Fix:**</span> Restart the server after configuration changes.
|
|
673
|
+
|
|
674
|
+
```typescript
|
|
675
|
+
// ❌ This won't work
|
|
676
|
+
const app = new YinzerFlow({ port: 3000 });
|
|
677
|
+
app.config.port = 4000; // Configuration is immutable
|
|
678
|
+
|
|
679
|
+
// ✅ This works
|
|
680
|
+
const app = new YinzerFlow({ port: 4000 });
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
### CORS errors in browser
|
|
684
|
+
|
|
685
|
+
**Symptom:** Browser blocks requests with CORS policy errors like:
|
|
686
|
+
- `"Access-Control-Allow-Origin" header missing`
|
|
687
|
+
- `"CORS policy: No 'Access-Control-Allow-Origin' header is present"`
|
|
688
|
+
- `"Method [METHOD] is not allowed by Access-Control-Allow-Methods"`
|
|
689
|
+
|
|
690
|
+
**Common causes:**
|
|
691
|
+
|
|
692
|
+
1. 🌐 **Origin mismatch**: Origin doesn't match exactly (check protocol, domain, port)
|
|
693
|
+
2. 🔤 **Typos**: Spelling errors in origin URL
|
|
694
|
+
3. 📝 **Trailing slashes**: `https://yourdomain.com/` vs `https://yourdomain.com`
|
|
695
|
+
4. ⚙️ **HTTP method not allowed**: Using PUT/DELETE but only GET/POST configured
|
|
696
|
+
5. 🔑 **Credentials mismatch**: `credentials: true` required when using cookies/auth
|
|
697
|
+
6. 🔒 **Wildcard with credentials**: Can't use `origin: '*'` with `credentials: true`
|
|
698
|
+
|
|
699
|
+
<span style="color: #2ecc71">**✅ Fix checklist:**</span>
|
|
700
|
+
|
|
701
|
+
1. **Check origin matches exactly** (including `https://` and port):
|
|
702
|
+
```typescript
|
|
703
|
+
cors: {
|
|
704
|
+
enabled: true,
|
|
705
|
+
origin: ["https://yourdomain.com:3000"], // Exact match with protocol and port
|
|
706
|
+
credentials: true,
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
2. **Verify HTTP method is allowed**:
|
|
711
|
+
```typescript
|
|
712
|
+
cors: {
|
|
713
|
+
enabled: true,
|
|
714
|
+
origin: ["https://yourdomain.com"],
|
|
715
|
+
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"], // Include all methods you use
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
3. **Check for typos** in origin URL:
|
|
720
|
+
```typescript
|
|
721
|
+
// ❌ Common typos
|
|
722
|
+
origin: ["https://yourdomain.com "], // Trailing space
|
|
723
|
+
origin: ["http://yourdomain.com"], // HTTP instead of HTTPS
|
|
724
|
+
origin: ["https://yourdomian.com"], // Misspelled domain
|
|
725
|
+
|
|
726
|
+
// ✅ Correct
|
|
727
|
+
origin: ["https://yourdomain.com"]
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
4. **Ensure credentials setting matches**:
|
|
731
|
+
```typescript
|
|
732
|
+
// If frontend uses: fetch(url, { credentials: 'include' })
|
|
733
|
+
cors: {
|
|
734
|
+
enabled: true,
|
|
735
|
+
origin: ["https://yourdomain.com"], // Must be specific, not '*'
|
|
736
|
+
credentials: true, // Must be true
|
|
737
|
+
}
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
<span style="color: #3498db">**💡 Tip:**</span> Check browser console Network tab → Select failed request → Look at Response Headers to see what CORS headers were sent.
|
|
741
|
+
|
|
742
|
+
### File uploads rejected
|
|
743
|
+
|
|
744
|
+
**Symptom:** File uploads fail with 413 Payload Too Large.
|
|
745
|
+
|
|
746
|
+
**Cause:** File exceeds `maxFileSize` or `maxTotalSize` limits.
|
|
747
|
+
|
|
748
|
+
<span style="color: #2ecc71">**✅ Fix:**</span> Increase file upload limits.
|
|
749
|
+
|
|
750
|
+
```typescript
|
|
751
|
+
bodyParser: {
|
|
752
|
+
fileUploads: {
|
|
753
|
+
maxFileSize: 52428800, // 50MB per file
|
|
754
|
+
maxTotalSize: 104857600, // 100MB total
|
|
755
|
+
maxFiles: 20,
|
|
756
|
+
},
|
|
757
|
+
}
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### Wrong client IP address
|
|
761
|
+
|
|
762
|
+
**Symptom:** `request.ipAddress` shows proxy IP instead of client IP.
|
|
763
|
+
|
|
764
|
+
**Cause:** Proxy not configured in `trustedProxies`.
|
|
765
|
+
|
|
766
|
+
<span style="color: #2ecc71">**✅ Fix:**</span> Add your proxy/load balancer IP to trusted proxies.
|
|
767
|
+
|
|
768
|
+
<span style="color: #3498db">🔗 See [IP Security Documentation](../modules/ip-security.md) for details</span>
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
ipSecurity: {
|
|
772
|
+
trustedProxies: ["192.168.1.10"], // Your load balancer IP
|
|
773
|
+
headerPreference: ["x-forwarded-for", "x-real-ip"],
|
|
774
|
+
}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### Rate limit headers missing
|
|
778
|
+
|
|
779
|
+
**Symptom:** Responses don't include `RateLimit-*` headers.
|
|
780
|
+
|
|
781
|
+
**Cause:** `standardHeaders` is disabled.
|
|
782
|
+
|
|
783
|
+
<span style="color: #2ecc71">**✅ Fix:**</span> Enable standard rate limit headers.
|
|
784
|
+
|
|
785
|
+
```typescript
|
|
786
|
+
rateLimit: {
|
|
787
|
+
enabled: true,
|
|
788
|
+
standardHeaders: true, // Enable headers
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### Server shuts down immediately
|
|
793
|
+
|
|
794
|
+
**Symptom:** Server starts but shuts down right away on SIGTERM/SIGINT.
|
|
795
|
+
|
|
796
|
+
**Cause:** `gracefulShutdownTimeout` is enabled (default) and a signal is being sent, or you have duplicate signal handlers.
|
|
797
|
+
|
|
798
|
+
<span style="color: #2ecc71">**✅ Fix:**</span> Disable graceful shutdown if using custom signal handlers.
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
const app = new YinzerFlow({
|
|
802
|
+
port: 3000,
|
|
803
|
+
gracefulShutdownTimeout: 0, // Disable automatic signal handling
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// Your custom signal handling
|
|
807
|
+
process.on("SIGTERM", async () => {
|
|
808
|
+
await customCleanup();
|
|
809
|
+
await app.close();
|
|
810
|
+
process.exit(0);
|
|
811
|
+
});
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
<span style="color: #3498db">**💡 Tip:**</span> Check if your process manager (PM2, Docker, etc.) is sending signals. The default behavior will catch them and gracefully shut down.
|
|
815
|
+
|